我曾尝试使用AES算法生成加密文本在(Android和IPhone)平台上,但问题是我们使用相同的加密解密库(AES-128)并使用相同的固定变量(Key,IV,模式)但我得到两个不同的结果。
我感谢任何帮助。 :(
以下代码介绍了使用的加密和解密方法,
Android版代码:
代码:
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];
}
我的一些参考文献:
答案 0 :(得分:4)
要检查的第一件事是您正在使用的字节。您将IV,密钥和明文列为字符。这些字符将使用某种编码转换为字节。检查字节的外观,而不是字符。您需要在两台机器上逐字列出所有内容并进行比较。或者,准确指定要在每台计算机上使用的转换。机器默认值可能不同。
一旦你知道输入字节是相同的,那么我们可以寻找其他问题。
作为一个小问题,通常最好使用填充,例如PKCS#7;这样你就不必使你的消息符合密码的块大小。
答案 1 :(得分:3)
非常重要。
编辑:
我知道我应该提高这个答案的质量,但我在这里所说的+下面所说的rossum是正确的做法。
这只是关于加密/解密合规性 - 当您跨平台工作时,您也必须具有二进制合规性。
所以转储原始数据并检查它们是否存在差异,直到你的眼睛流出,然后你发现并成功修补了那个带来差异的小怪癖。
对于初学者来说,.getBytes(“UTF-8”)会在Java / android环境中为你提供一致的字符串(因为除非你阅读文档,否则getBytes()不能按你预期的方式工作) / p>
答案 2 :(得分:0)
代码有各种各样的问题,但是你在Android上每次加密时获得不同密文的原因是你没有指定IV,而是生成一个随机的。你也说'没有填充',但iOS代码正在填充,而Android很可能也是默认情况下,因为你没有明确指定它。最后,如果要加密任何不是块大小倍数的任何内容(如示例纯文本),则执行 need 填充。 getBytes()
在Android上默认为UTF-8,因此这是您遇到的问题中最少的问题,但要明确说明问题。