【问题标题】:AES 256 encryption - Qt equivalent for JavaAES 256 加密 - Qt 等效于 Java
【发布时间】:2014-03-24 18:40:28
【问题描述】:

我的 AES 256 加密方法在 Java 中实现并正常工作,如下所示!

  private static final byte[] IV = {
    0, 2, 4, 8, 16, 32, 64, 127, 
    127, 64, 32, 16, 8, 4, 2, 0
};

  //actual encryption over here
  private static byte[] encrypt(byte[] raw, byte[] clear) throws 
Exception {  
    SecretKeySpec skeySpec = new SecretKeySpec(raw,  "AES");  
    Cipher cipher = null;

    if(isIVUsedForCrypto) {
        cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(IV));  
    }
    else 
    {
        cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);  
    }
    byte[] encrypted = cipher.doFinal(clear);  
    return encrypted;  
}  

上述方法返回的字节数组最终使用以下toHex方法转换为HEX字符串。

      public static String toHex(byte[] buf) {  
    if (buf == null)  
        return "";  
    StringBuffer result = new StringBuffer(2*buf.length);  
    for (int i = 0; i < buf.length; i++) {  
        appendHex(result, buf[i]);  
    }  
    return result.toString();  
}  
private final static String HEX = "0123456789ABCDEF";  
private static void appendHex(StringBuffer sb, byte b) {  
    sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));  
}  

所以使用 Java AES 256 加密代码的最终结果是一个 HEX 字符串。

现在是 Qt 部分,

  QByteArray IV("0, 2, 4, 8, 16, 32, 64, 127,127, 64, 32, 16, 8, 4, 2, 0");


 QString encrypt(QByteArray r, const QString &password)
 {
const char *sample = r.data();
string plain = password.toStdString();
string ciphertext;
// Generate Cipher, Key, and CBC
byte key[ AES::MAX_KEYLENGTH ], iv[ AES::BLOCKSIZE ];
StringSource( reinterpret_cast<const char *>(sample), true,
              new HashFilter(*(new SHA256), new ArraySink(key, AES::MAX_KEYLENGTH)) );
memset( iv, 0x00, AES::BLOCKSIZE );
CBC_Mode<AES>::Encryption Encryptor( key, sizeof(key), iv );
StringSource( plain, true, new StreamTransformationFilter( Encryptor,
              new HexEncoder(new StringSink( ciphertext ) ) ) );
return QString::fromStdString(ciphertext);
} 

我从主方法调用上述函数

        QString encrypted = encrypt(result, "test");

其中“结果”是QByteArray,我将其传递给加密,就像在 java 中所做的那样。

Java 和 Qt 两种情况下的字节数组都是一样的。我已经验证过了。

我的问题

尤其是 Qt 的加密逻辑在某处失败,导致通过 Java 和 Qt 获得的 HEX 结果不匹配。

谁能告诉我我在 Qt 部分做错了什么。我没有正确使用IVQByteArray result

【问题讨论】:

  • 当使用SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); 创建密钥时,Java 如何确切使用AESraw 构造密钥?
  • Cipher.getInstance("AES/CBC/PKCS5Padding"); - 我相信默认情况下使用的是 AES-128。也许你应该试试"AES256/CBC/PKCS5Padding"。请参阅 Java 的 Cipher Algorithm Names

标签: java c++ qt encryption crypto++


【解决方案1】:

我猜你的 Java 实现错过了键上的哈希步骤。我正在使用密钥的 SHA256 哈希。要测试 c++ 实现,请将代码更改为:

QString encrypt(QByteArray r, const QString &password)
 {
const char *sample = r.data();
string plain = password.toStdString();
string ciphertext;
// Generate Cipher, Key, and CBC
byte key[ AES::MAX_KEYLENGTH ], iv[ AES::BLOCKSIZE ];
//StringSource( reinterpret_cast<const char *>(sample), true,
//              new HashFilter(*(new SHA256), new ArraySink(key, AES::MAX_KEYLENGTH)) );
for(int i=0; i< AES::MAX_KEYLENGTH; ++i){
    key[i] = reinterpret_cast<const char *>(decodedKey)[i];
}
memset( iv, 0x00, AES::BLOCKSIZE );
CBC_Mode<AES>::Encryption Encryptor( key, sizeof(key), iv );
StringSource( plain, true, new StreamTransformationFilter( Encryptor,
              new HexEncoder(new StringSink( ciphertext ) ) ) );
return QString::fromStdString(ciphertext);
} 

【讨论】:

  • 是的,感谢它现在工作正常...如果我将来遇到任何问题,我会在这里添加评论
  • 你有完整的代码吗? AES::BLOCKSIZE 来自哪里?它来自 openssl 库吗?
  • @meadlai 我相信这段代码使用了 Crypto++ 库...
【解决方案2】:

Java 代码和 Qt 中的初始化向量不同:

private static final byte[] IV = {
    0, 2, 4, 8, 16, 32, 64, 127, 
    127, 64, 32, 16, 8, 4, 2, 0
};

在 C++ 中:

memset( iv, 0x00, AES::BLOCKSIZE ); // ==> This fills the iv array with 0s

因此,您需要对两种方案使用相同的 IV。

更新:

为了为 AES 的 CBC 模式提供 IV,您需要像在 Java 中一样指定 IV:

byte iv[ AES::BLOCKSIZE ] = {0, 2, 4, 8, 16, 32, 64, 127, 
                             127, 64, 32, 16, 8, 4, 2, 0};

请注意,AES::BLOCKSIZE 是在库头文件中定义的,它是16

【讨论】:

  • 再次感谢 sorush-r。那么它会正常工作吗? qbytearray 怎么样...我是否正确使用它。抱歉,我是 Java 开发人员,所以很难理解 C++
  • 这意味着我应该做 memset (iv, IV, AES::BLOCKSIZE);对吗?
  • 你好,请到聊天室
  • 是的,我试过了...我改为这样写 byte iv[AES::BLOCKSIZE] = { 0x00, 0x02 ....} 基本上我将数字表示为十六进制...然后我删除了那条 memset 行,因为它不是必需的,但十六进制结果仍然不匹配..是因为 HexEncoder 类。它可能在内部使用了一些 java 没有的不同算法
  • 是的,感谢它现在工作正常...如果我将来遇到任何问题,我会在这里添加评论
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-07
  • 2010-11-02
  • 2013-08-24
  • 2015-04-21
  • 2014-03-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多