Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java AES计数器模式递增_Java_Encryption_Cryptography_Aes_Ctr Mode - Fatal编程技术网

Java AES计数器模式递增

Java AES计数器模式递增,java,encryption,cryptography,aes,ctr-mode,Java,Encryption,Cryptography,Aes,Ctr Mode,我已经用Java编写了一个加密/解密原型,使用中的示例代码。但是,我尝试使用AES的计数器模式(CTR),加密值似乎与我尝试加密的整数序列一样可递增 考虑我的原型的以下输出: i = 0: enc='5941F8', dec='000', length=6 i = 1: enc='5941F9', dec='001', length=6 i = 2: enc='5941FA', dec='002', length=6 i = 3: enc='5941FB', dec='003', length=

我已经用Java编写了一个加密/解密原型,使用中的示例代码。但是,我尝试使用AES的计数器模式(CTR),加密值似乎与我尝试加密的整数序列一样可递增

考虑我的原型的以下输出:

i = 0: enc='5941F8', dec='000', length=6
i = 1: enc='5941F9', dec='001', length=6
i = 2: enc='5941FA', dec='002', length=6
i = 3: enc='5941FB', dec='003', length=6
i = 4: enc='5941FC', dec='004', length=6
i = 5: enc='5941FD', dec='005', length=6
i = 6: enc='5941FE', dec='006', length=6
i = 7: enc='5941FF', dec='007', length=6
i = 8: enc='5941F0', dec='008', length=6
i = 9: enc='5941F1', dec='009', length=6
i = 10: enc='5940F8', dec='010', length=6
i = 11: enc='5940F9', dec='011', length=6
i = 12: enc='5940FA', dec='012', length=6
请注意,
enc
值通常仅与
dec
值相差一位数。AES计数器模式生成的加密值通常是这样的吗?它们之间是否可以/相似?还是我做错了什么

到目前为止,我已经尝试过使用不同的加密密钥、init向量、填充方案、更长/更短的整数序列(从不同的值开始)等等,但到目前为止似乎没有任何效果。此外,Google和其他一些关于计数器模式下JavaAES密码的问题到目前为止几乎没有用处。请记住,我也是一个加密新手

我的原型代码如下:

public class Encryptor {
  public static String encrypt(String key, String initVector, String value) {
    try {
      IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
      SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");

      Cipher cipher = Cipher.getInstance("AES/CTR/PKCS5PADDING");
      cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);

      byte[] encrypted = cipher.doFinal(value.getBytes());
      return DatatypeConverter.printHexBinary(encrypted);
    }
    catch (Exception ex) {
      throw new RuntimeException(ex);
    }
  }

  public static String decrypt(String key, String initVector, String encrypted) {
    try {
      IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
      SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");

      Cipher cipher = Cipher.getInstance("AES/CTR/PKCS5PADDING");
      cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);

      byte[] decrypted = cipher.doFinal(DatatypeConverter.parseHexBinary(encrypted));
      return new String(decrypted);
    }
    catch (Exception ex) {
      ex.printStackTrace();
    }

    return null;
  }

  public static void main(String[] args) {
    String key = "Bar12345Bar12345"; // 128 bit key
    String initVector = "RandomInitVector"; // 16 bytes IV

    System.out.println(decrypt(key, initVector,
        encrypt(key, initVector, "Hello World")));
    for (int i = 0; i < 1000; ++i) {
      String encrypted = encrypt(key, initVector, StringUtils.leftPad("" + i, 3, '0'));
      String decrypted = decrypt(key, initVector, encrypted);
      int encLen = encrypted.length();
      System.out.println("i = " + i + ": enc='" + encrypted + "', dec='" + decrypted + "', length=" + encLen);
    }
  }
}
公共类加密机{
公共静态字符串加密(字符串密钥、字符串初始向量、字符串值){
试一试{
IvParameterSpec iv=新的IvParameterSpec(initVector.getBytes(“UTF-8”);
SecretKeySpec skeySpec=新的SecretKeySpec(key.getBytes(“UTF-8”),“AES”);
Cipher Cipher=Cipher.getInstance(“AES/CTR/PKCS5PADDING”);
cipher.init(cipher.ENCRYPT_模式,skeySpec,iv);
byte[]encrypted=cipher.doFinal(value.getBytes());
返回DatatypeConverter.printHexBinary(加密);
}
捕获(例外情况除外){
抛出新的运行时异常(ex);
}
}
公共静态字符串解密(字符串密钥、字符串初始化向量、字符串加密){
试一试{
IvParameterSpec iv=新的IvParameterSpec(initVector.getBytes(“UTF-8”);
SecretKeySpec skeySpec=新的SecretKeySpec(key.getBytes(“UTF-8”),“AES”);
Cipher Cipher=Cipher.getInstance(“AES/CTR/PKCS5PADDING”);
cipher.init(cipher.DECRYPT_模式,skeySpec,iv);
字节[]解密=cipher.doFinal(DatatypeConverter.parseHexBinary(加密));
返回新字符串(已解密);
}
捕获(例外情况除外){
例如printStackTrace();
}
返回null;
}
公共静态void main(字符串[]args){
String key=“Bar12345Bar12345”//128位密钥
String initVector=“RandomInitVector”//16字节IV
System.out.println(解密(密钥,initVector,
加密(密钥,initVector,“Hello World”);
对于(int i=0;i<1000;++i){
String encrypted=encrypt(key,initVector,StringUtils.leftPad(“+i,3,'0”);
String decrypted=解密(密钥,initVector,加密);
int encLen=encrypted.length();
System.out.println(“i=“+i+”:enc=”“+encrypted+”,dec=”“+decrypted+”,length=“+encLen”);
}
}
}
。这意味着一个nonce和密钥对创建一个唯一的密钥流,然后用明文进行异或运算。因为XOR是对称的,所以对密文进行解密的操作是完全相同的

现在,XOR的工作有点明智。如果对多次加密使用相同的密钥和nonce对,每次都将使用完全相同的密钥流对明文进行加密。这意味着在比较两个结果密文时,两个明文之间不同的位位置也将不同。这称为两次焊盘或多次焊盘

在您的示例中,如果对每个迭代执行XOR
enc
dec
,您将始终获得
0x6971C8
。这些是密钥流的前三个字节。ASCII字符0为
0x30
,与
0x59
异或时为
0x69
,依此类推


解决方案是每次使用相同密钥加密时使用不同的nonce(使用一次的数字)。nonce(有时称为IV)应该小于底层分组密码的块大小。AES的块大小为16字节。我们通常选择长度为8字节或12字节的随机nonce,这取决于我们希望在不发生反冲突的情况下加密多少数据。12字节的nonce似乎是最好的折衷方案,因为您可以生成许多随机nonce,而不会有太大的冲突机会,并且您可以使用密钥+nonce对加密高达68 GB的数据,而不会有反冲突的机会。

有趣的是,我否决了您链接到的答案。你也应该。在CBC模式下使用相同的IV是一个问题,但在CTR模式下这是一个更大的问题,因此你的问题。注意我在链接答案下的评论,这应该阻止你提出这个问题。我还不清楚该怎么做吗?不,答案很好。当我接受你的建议时,我得到了更好的数据。但你的回答提出了一个有趣的必然问题。请参阅下面对您的答案的评论。您的解决方案有效。非常感谢。我基本上使用了变量
I
的类似版本作为初始化向量。然而,这给我提出了一个比它解决的问题更大的问题。我猜测真的没有一种可行的方法来解密某些序列中应该是整数的值,对吗?为了使解密工作,我需要知道初始化向量。再次感谢!是和否,nonce不必随机选择,但必须不同。例如,如果存在与要加密的整数关联的唯一ID,则可以简单地将该ID用作nonce。如果您不想这样做,那么总是有可能使用保留格式的加密。请记住,FPE的实现并不多。警告:IV不是nonce,它是CTR模式的初始计数器值。nonce应该是例如IV的第一个(最左边)8字节,将其他字节留空,以便即使在使用唯一IV时也不会重叠计数器值。这在答案中不够清楚