AES 256 encryption - Qt equivalent for Java

2019-02-10 19:55发布

I have my AES 256 encryption method implemented and working fine in Java as follows!

  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;  
}  

The byte array that is returned from the above method is finally converted to a HEX string using the following toHex method.

      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));  
}  

So the end result using Java AES 256 encryption code is a HEX String.

Now for the Qt part,

  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);
} 

And from the main method i call the above function

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

where "result" is a QByteArray that I pass to encrypt as done similarly in java.

The byte arrays in both cases Java and Qt are obtained the same. I have verified that.

My problem

The encryption logic for Qt especially is failing somewhere due to which the HEX result obtained via Java and Qt don't match.

Can anyone tell me what I am doing wrong in the Qt part. Am I not using the IV or the QByteArray result correctly?

2条回答
虎瘦雄心在
2楼-- · 2019-02-10 20:33

I guess your Java implementation misses a hash step on the key. I'm using a SHA256 hash of the key. To test c++ implementation, change code to this:

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);
} 
查看更多
smile是对你的礼貌
3楼-- · 2019-02-10 20:36

Initialization vector is different in your Java code and Qt:

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

And in C++:

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

So you need to use same IV for both schemes.

Update:

In order to provide an IV for CBC mode of AES, you need to specify IV as you do in Java:

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

Note that AES::BLOCKSIZE is defined in library headers and it is 16.

查看更多
登录 后发表回答