面向GCM的JAVA中IV的确定性构造
我对密码学是个新手。 我在GCM模式下尝试AES加密,以保护我的应用程序的静态数据 我通过了考试。它提到IV的独特性非常重要。它说,如果(key,IV)对被重复,对手就可以伪造密文。 PFB代码示例面向GCM的JAVA中IV的确定性构造,java,encryption,cryptography,bouncycastle,Java,Encryption,Cryptography,Bouncycastle,我对密码学是个新手。 我在GCM模式下尝试AES加密,以保护我的应用程序的静态数据 我通过了考试。它提到IV的独特性非常重要。它说,如果(key,IV)对被重复,对手就可以伪造密文。 PFB代码示例 public static void main(String[] args) throws Exception { byte[] keyBytes = MessageDigest.getInstance("MD5").digest(
public static void main(String[] args) throws Exception {
byte[] keyBytes = MessageDigest.getInstance("MD5").digest(
"som3C0o7p@s5".getBytes());
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
IvParameterSpec ivSpec = new IvParameterSpec(new byte[96]);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
byte[] block = new byte[96];
int i;
long st, et;
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
BufferedInputStream bIn = new BufferedInputStream(
new ProgressMonitorInputStream(null, "Encrypting ...",
new FileInputStream("input.txt")));
CipherInputStream cIn = new CipherInputStream(bIn, cipher);
BufferedOutputStream bOut = new BufferedOutputStream(
new FileOutputStream("output.txt"));
int ch;
while ((i = cIn.read(block)) != -1) {
bOut.write(block, 0, i);
}
cIn.close();
bOut.close();
Thread.sleep(5000);
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
InputStream is = new FileInputStream("output.txt");
OutputStream os = new FileOutputStream("output2.txt");
os = new CipherOutputStream(os, cipher);
while ((i = is.read(block)) != -1)
{
os.write(block, 0, i);
}
is.close();
os.close();
}
我能够加密和解密input.txt文件中的文本。ECM的IV必须是唯一的,并使用NIST 800-38D中规定的IV确定性结构生成
目前使用的是在[
IvParameterSpec(字节[]iv)使用
iv中的字节作为iv
在BouncyCastle或任何其他库中是否有任何可用的实现来获取确定性构造中的IV。或者我们是否需要构建自定义实现。以及如何实现IvParameterSpec。是否遵循规范
另外,请指导使用确定性方法创建IV的定制实现。没有NIST算法创建确定性IV(在8.2.1确定性构造中规定)所以也没有实现。它只是定义了一些需要遵循的一般程序,以创建NIST可以接受的程序 如果消息已经具有唯一性,那么最好在唯一ID上创建一个散列,并使用最左边的8个字节作为“计数器”,而不是使用以下基于计数器的方法
以下是一个根据NIST规范(据我所知)的简单结构。别忘了以一种永远不会重复使用的方式存储计数器
导入java.nio.charset.StandardCharset;
导入java.security.security;
导入java.util.array;
导入javax.crypto.Cipher;
导入javax.crypto.spec.IvParameterSpec;
导入javax.crypto.spec.SecretKeySpec;
导入org.bouncycastle.jce.provider.BouncyCastleProvider;
导入org.bouncycastle.util.encoders.Hex;
公共类计数器{
私有最终整数块大小字节;
专用最终字节[]ivCounter;
公共计数器IVCreator(最终整数块大小字节){
if(块大小字节%2!=0 | |块大小字节<16){
//AKA不要使用DES或3DES
抛出新的IllegalArgumentException(“块大小应为偶数且至少为16字节”);
}
this.blockSizeBytes=blockSizeBytes;
this.ivCounter=新字节[blockSizeBytes/2];
}
公共计数器IVCreator(最终字节[]oldCounter){
如果(oldCounter.length<8){
//AKA不要使用DES或3DES
抛出新的IllegalArgumentException(“计数器应大于8字节”);
}
this.blockSizeBytes=oldCounter.length*2;
this.ivCounter=oldCounter.clone();
}
公共IvParameterSpec createIV(){
递增计数器(ivCounter);
最后一个字节[]iv=Arrays.copyOf(ivCounter,blockSizeBytes);
返回新的IvParameterSpec(iv);
}
公共字节[]getCounter(){
返回ivCounter.clone();
}
专用静态无效增量计数器(最终字节[]计数器){
对于(int i=counter.length-1;i>=0;i--){
计数器[i]++;
如果(计数器[i]!=0){
打破
}
}
}
公共静态void main(最终字符串…args)引发异常{
addProvider(新的BouncyCastleProvider());
字节[]计数器;
Cipher gcm=Cipher.getInstance(“AES/gcm/NoPadding”);
SecretKeySpec aesKey=new SecretKeySpec(新字节[Cipher.getMaxAllowedKeyLength(“AES/GCM/NoPadding”)/byte.SIZE],“AES”);
{
CounterIVCreator=新的CounterIVCreator(gcm.getBlockSize());
IvParameterSpec ivSpec=ivCreator.createIV();
gcm.init(Cipher.ENCRYPT_模式,aesKey,ivSpec);
gcm.updateAAD(ivSpec.getIV());
byte[]ciphertext=gcm.doFinal(“owlstead.getBytes(StandardCharsets.UTF_8));
System.out.println(十六进制到十六进制字符串(密文));
gcm.init(Cipher.DECRYPT_模式,aesKey,ivSpec);
gcm.updateAAD(ivSpec.getIV());
字节[]明文=gcm.doFinal(密文);
System.out.println(新字符串(纯文本,StandardCharsets.UTF_8));
oldCounter=ivCreator.getCounter();
}
//第二部分,创建一个完全不同的密文
{
CounterIVCreator=新的CounterIVCreator(旧计数器);
IvParameterSpec ivSpec=ivCreator.createIV();
gcm.init(Cipher.ENCRYPT_模式,aesKey,ivSpec);
gcm.updateAAD(ivSpec.getIV());
byte[]ciphertext=gcm.doFinal(“owlstead.getBytes(StandardCharsets.UTF_8));
System.out.println(十六进制到十六进制字符串(密文));
gcm.init(Cipher.DECRYPT_模式,aesKey,ivSpec);
gcm.updateAAD(ivSpec.getIV());
字节[]明文=gcm.doFinal(密文);
System.out.println(新字符串(纯文本,StandardCharsets.UTF_8));
}
}
}
您必须自己实现它。特别是,您必须决定如何可靠地存储和更新每设备计数器。请注意,对于不包含GCM操作模式的Java版本,您应该只需要Bouncy Castle提供程序。Oracle Java 8确实包含这样的实现,它应该是comp以上代码不适用。您好,这适合您的需要吗?
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
public class CounterIVCreator {
private final int blockSizeBytes;
private final byte[] ivCounter;
public CounterIVCreator(final int blockSizeBytes) {
if (blockSizeBytes % 2 != 0 || blockSizeBytes < 16) {
// AKA don't use DES or 3DES
throw new IllegalArgumentException("Block size should be even and at least 16 bytes");
}
this.blockSizeBytes = blockSizeBytes;
this.ivCounter = new byte[blockSizeBytes / 2];
}
public CounterIVCreator(final byte[] oldCounter) {
if (oldCounter.length < 8) {
// AKA don't use DES or 3DES
throw new IllegalArgumentException("Counter should be larger than 8 bytes");
}
this.blockSizeBytes = oldCounter.length * 2;
this.ivCounter = oldCounter.clone();
}
public IvParameterSpec createIV() {
increaseCounter(ivCounter);
final byte[] iv = Arrays.copyOf(ivCounter, blockSizeBytes);
return new IvParameterSpec(iv);
}
public byte[] getCounter() {
return ivCounter.clone();
}
private static void increaseCounter(final byte[] counter) {
for (int i = counter.length - 1; i >= 0; i--) {
counter[i]++;
if (counter[i] != 0) {
break;
}
}
}
public static void main(final String ... args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
byte[] oldCounter;
Cipher gcm = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec aesKey = new SecretKeySpec(new byte[Cipher.getMaxAllowedKeyLength("AES/GCM/NoPadding") / Byte.SIZE], "AES");
{
CounterIVCreator ivCreator = new CounterIVCreator(gcm.getBlockSize());
IvParameterSpec ivSpec = ivCreator.createIV();
gcm.init(Cipher.ENCRYPT_MODE, aesKey, ivSpec);
gcm.updateAAD(ivSpec.getIV());
byte[] ciphertext = gcm.doFinal("owlstead".getBytes(StandardCharsets.UTF_8));
System.out.println(Hex.toHexString(ciphertext));
gcm.init(Cipher.DECRYPT_MODE, aesKey, ivSpec);
gcm.updateAAD(ivSpec.getIV());
byte[] plaintext = gcm.doFinal(ciphertext);
System.out.println(new String(plaintext, StandardCharsets.UTF_8));
oldCounter = ivCreator.getCounter();
}
// part deux, creates an entirely different ciphertext
{
CounterIVCreator ivCreator = new CounterIVCreator(oldCounter);
IvParameterSpec ivSpec = ivCreator.createIV();
gcm.init(Cipher.ENCRYPT_MODE, aesKey, ivSpec);
gcm.updateAAD(ivSpec.getIV());
byte[] ciphertext = gcm.doFinal("owlstead".getBytes(StandardCharsets.UTF_8));
System.out.println(Hex.toHexString(ciphertext));
gcm.init(Cipher.DECRYPT_MODE, aesKey, ivSpec);
gcm.updateAAD(ivSpec.getIV());
byte[] plaintext = gcm.doFinal(ciphertext);
System.out.println(new String(plaintext, StandardCharsets.UTF_8));
}
}
}