4

我曾尝试在两个(Android 和 iPhone)平台中使用 AES 算法生成加密文本,但问题是即使我们使用相同的加密解密库(AES-128)和相同的固定变量(Key、IV、mode),但我为他们得到了两个不同的结果。

我感谢任何帮助。:(

下面的代码介绍了使用的加密和解密方法,

安卓代码版本:

  • 键=“123456789abcdefg”;
    • IV =“1111111111111111”;
    • 纯文本 = “HelloThere”;
    • 模式=“AES/CBC/NoPadding”;

代码 :

  public class Crypto {
public static String encrypt(String seed, String cleartext) throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] result = encrypt(rawKey, cleartext.getBytes());
        return toHex(result);
}



public static String decrypt(String seed, String encrypted) throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] enc = toByte(encrypted);
        byte[] result = decrypt(rawKey, enc);
        return new String(result);
}


private static byte[] getRawKey(byte[] seed) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance(“CBC”);
        SecureRandom sr = SecureRandom.getInstance(“SHA1PRNG”);
        sr.setSeed(seed);
    kgen.init(128, sr); // 192 and 256 bits may not be available
    SecretKey skey = kgen.generateKey();
    byte[] raw = skey.getEncoded();
    return raw;
}
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, “AES”);
        Cipher cipher = Cipher.getInstance(“AES”);
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(clear);
        return encrypted;
}
private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, “AES”);
        Cipher cipher = Cipher.getInstance(“AES”);
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);
    byte[] decrypted = cipher.doFinal(encrypted);
        return decrypted;
}
public static String toHex(String txt) {
        return toHex(txt.getBytes());
}
public static String fromHex(String hex) {
        return new String(toByte(hex));
}
public static byte[] toByte(String hexString) {
        int len = hexString.length()/2;
        byte[] result = new byte[len];
        for (int i = 0; i < len; i++)
                result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
        return result;
}
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));
}

}

iPhone的代码版本:

- (NSData *) transform:(CCOperation) encryptOrDecrypt data:(NSData *) inputData {

NSData* secretKey = [Cipher md5:cipherKey];

CCCryptorRef cryptor = NULL;
CCCryptorStatus status = kCCSuccess;

uint8_t iv[kCCBlockSizeAES128];
memset((void *) iv, 0x0, (size_t) sizeof(iv));

status = CCCryptorCreate(encryptOrDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                         [secretKey bytes], kCCKeySizeAES128, iv, &cryptor);

if (status != kCCSuccess) {
    return nil;
}

size_t bufsize = CCCryptorGetOutputLength(cryptor, (size_t)[inputData length], true);

void * buf = malloc(bufsize * sizeof(uint8_t));
memset(buf, 0x0, bufsize);

size_t bufused = 0;
size_t bytesTotal = 0;

status = CCCryptorUpdate(cryptor, [inputData bytes], (size_t)[inputData length],
                         buf, bufsize, &bufused);

if (status != kCCSuccess) {
    free(buf);
    CCCryptorRelease(cryptor);
    return nil;
}

bytesTotal += bufused;

status = CCCryptorFinal(cryptor, buf + bufused, bufsize - bufused, &bufused);

if (status != kCCSuccess) {
    free(buf);
    CCCryptorRelease(cryptor);
    return nil;
}

bytesTotal += bufused;

CCCryptorRelease(cryptor);

return [NSData dataWithBytesNoCopy:buf length:bytesTotal];

}

 + (NSData *) md5:(NSString *) stringToHash {

const char *src = [stringToHash UTF8String];

unsigned char result[CC_MD5_DIGEST_LENGTH];

CC_MD5(src, strlen(src), result);

return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH];

}

我的一些参考资料:

4

3 回答 3

4

首先要检查的是您正在使用的字节。您将 IV、密钥和明文列为字符。这些字符将使用某种编码转换为字节。检查字节的样子,而不是字符。您需要逐字节列出两台机器上的所有内容并进行比较。或者,准确指定您将在每台机器上使用的转换。机器默认值可能会有所不同。

一旦您知道输入字节相同,那么我们就可以寻找其他问题。

作为一个小点,通常最好使用填充,例如 PKCS#7;这样您就不必使您的消息适合密码的块大小。

于 2012-10-31T14:20:38.900 回答
3

哦,伙计,你忘了使用 .getBytes("UTF-8"); ...

极其重要。

编辑:

我知道我应该提高这个答案的质量,但是我在这里所说的 + rossum 下面所说的才是正确解决这个问题的诀窍。

这只是关于加密/解密合规性 - 当您跨平台工作时,您还必须具有二进制合规性。

因此,转储原始数据并检查它们是否存在差异,直到您的眼睛流血并且您发现并成功修补了产生差异的那个小怪癖。

对于初学者, .getBytes("UTF-8") 将在 Java/android 环境中为您提供一致的字符串(因为 getBytes() 不能按照您期望的方式工作,除非您阅读文档)

于 2012-10-31T14:45:39.763 回答
0

该代码有各种问题,但是您在Android上的每次加密中获得不同密文的原因是您没有指定IV,并且正在生成一个随机的IV。您还说“无填充”,但 iOS 代码正在填充,而 Android 很可能也是默认设置,因为您没有明确指定它。最后,如果您加密的任何内容不是块大小的倍数(如您的示例纯文本),则确实需要填充。getBytes()在 Android 上默认为 UTF-8,所以这是你的问题中最少的,但一定要明确说明。

于 2012-11-01T03:36:48.257 回答