Android和Crypto ++ AES 128位加密结果不匹配

时间:2016-10-18 06:00:50

标签: android c++ encryption crypto++ javax.crypto

我正在尝试使用相同的密钥和VI来加密和解密相同的消息,比如aabbcc@gmail.com。密钥长度是128位,因为我知道在Java / Android中,256不容易实现。

这是我使用Crypto ++进行AES加密的功能

string encryptString(string toBeEncrypted) {
//
// Create Cipher Text
//
CryptoPP::AES::Encryption aesEncryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Encryption cbcEncryption(aesEncryption, iv);

std::string ciphertext;

std::cout << "To be encrypted (" << toBeEncrypted.size() << " bytes)" << std::endl;
std::cout << toBeEncrypted;
std::cout << std::endl << std::endl;

CryptoPP::StreamTransformationFilter stfEncryptor(cbcEncryption, new CryptoPP::StringSink(ciphertext), CryptoPP::StreamTransformationFilter::PKCS_PADDING);
stfEncryptor.Put(reinterpret_cast<const unsigned char*> (toBeEncrypted.c_str()), toBeEncrypted.length() + 1);
stfEncryptor.MessageEnd();

}

键是&#34; 4ff539a893fed04840749287bb3e4152&#34;和IV是&#34; 79f564e83be16711759ac7c730072bd0&#34;。

它们以二进制形式存储在x86 Windows上的VMWare中运行的ubuntu中。

keyiv从字节转换为十六进制数组的函数是:

std::string hexToStr(unsigned char *data, int len)
{
    std::stringstream ss;
    ss<<std::hex;
    for(int i(0);i<len;++i){
        ss<<std::setfill('0')<<std::setw(2)<<(int)data[i];
    }

return ss.str();
}

我检查了十六进制字符串与字节数组keyiv的内存,它们是匹配的。

加密aabbcc@gmail.com的结果是来自C ++的c08a50b45ff16650542e290e05390a6c6fe533e11e9f802ad7d47681fd41f964

我通过将返回的字符串ciphertext传递给函数hexToStr,例如cout<<TFFHelper::hexStr((unsigned char *)ciphertext.c_str(), ciphertext.length())<<endl;

来获得此结果

我也可以使用以下函数对其进行修改,并将原始字符串而不是十六进制字符串传递给此函数。

string TFFEncryption::decryptString(string toBeDecrypted) {

string decryptedtext;
CryptoPP::AES::Decryption aesDecryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv);

CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::StringSink(decryptedtext), CryptoPP::StreamTransformationFilter::PKCS_PADDING);
stfDecryptor.Put(reinterpret_cast<const unsigned char*> (toBeDecrypted.c_str()), toBeDecrypted.size());
stfDecryptor.MessageEnd();

return decryptedtext;
}

我在我的Android代码中添加了相同的VI和KEY,并尝试加密。加密后,它会以半匹配结果结束。

Android代码如下:

public class myAES {
private static final String key = "4ff539a893fed04840749287bb3e4152";
private static final String initVector = "79f564e83be16711759ac7c730072bd0";
private final  static char[] hexArray = "0123456789ABCDEF".toCharArray();

public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

public static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    for ( int j = 0; j < bytes.length; j++ ) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
}

public static byte[] encrypt(String value) {
    try {
        IvParameterSpec iv = new IvParameterSpec(hexStringToByteArray(initVector));
        SecretKeySpec skeySpec = new SecretKeySpec(hexStringToByteArray(key), "AES");

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

        byte[] encrypted = cipher.doFinal(value.getBytes());
        Log.v("Encryption successful", bytesToHex(encrypted));
        return encrypted;
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

public static String decrypt(byte[] encrypted) {
    try {
        IvParameterSpec iv = new IvParameterSpec(hexStringToByteArray(initVector));
        SecretKeySpec skeySpec = new SecretKeySpec(hexStringToByteArray(key), "AES");

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

        byte[] original = cipher.doFinal(encrypted);
        Log.v("Decryption successful", new String(original, "UTF-8"));
        return new String(original);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}
}

我得到了C08A50B45FF16650542E290E05390A6CFE5466FC480F0667517B248410930B69的结果。

我在Java8上的Netbeans中使用了相同的代码,运行在相同的C ++代码的Ubuntu上,并得到与我在前一行(Android结果)中提到的完全相同的结果。我不认为这是依赖于操作系统的,但我可能在代码中对Java或C ++做错了。

所以十六进制字符串的前半部分是匹配的,后半部分则不匹配。我尝试将短语aabbcc@gmail.com缩减为abc@gmail.com,这导致C ++与Java(Ubuntu与Android)完全不同的结果。

但是,如果我在Java中使用二进制数组,我会得到原始短语aabbcc@gmail.comabc@gmail.com

我有以下问题。

  1. 我做错了什么?
  2. const char *加入unsigned char *的正确方法吗?我认为应该没问题,因为我得到了二进制文件的十六进制字符串
  3. 填充是否导致半匹配结果?

1 个答案:

答案 0 :(得分:2)

加密++ 消息中的电子邮件已'0'终止,但 Java 中的消息不是。

由于 AES 是块长度为128位(16字节)的块密码,并且您的电子邮件长度恰好为16字节,因此第一个块在两种实现中都以相同的方式加密。第二个块的第一个位置中的'0'给出了第二个加密块的差异。

使用this online tool注意以下屏幕截图中的额外'00''0f'之后的所有'00'都是此工具未在此处删除的 PKCS5填充 ..

enter image description here