2012-10-31 18 views
3

我試圖使用AES算法生成加密文本在Android和iPhone平臺上,但問題是我們甚至使用相同的加密解密庫(AES-128)並使用相同的固定變量(Key,IV,模式),但是我得到了兩個不同的結果。iPhone和Android的加密方法

我很感激任何幫助。 :(

在下面的代碼呈現使用的加密和解密方法,

代碼版本的Android:

  • 密鑰=「123456789ABCDEFG」;
    • IV =「1111111111111111」;
    • 純文本=「HelloThere」;
    • Mode =「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 = 「ABCDEF」; 
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

請記住,字符串的getBytes()方法不確定每次都返回相同的字符串 –

+0

您是否嘗試過通過此解密Java和Objective-C版本的輸出? http://www.everpassword.com/aes-encryptor –

+0

你有沒有試過基本的plaintext.equals(解密(加密(明文)))測試?這兩種方法都返回true嗎? – Shark

回答

4

首先要檢查的是你正在使用的字節數。您將IV,密鑰和明文列爲字符。這些字符將使用某種編碼轉換爲字節。檢查字節的樣子,而不是字符。您需要在兩臺機器上逐字節地列出所有內容並進行比較。或者,請準確指定您要在每臺機器上使用哪種轉換。機器的默認設置可能會有所不同。

一旦你知道輸入字節是相同的,那麼我們可以尋找其他問題。

作爲一個小問題,通常最好使用填充,比如PKCS#7;這樣你就不必將你的信息放到密碼的塊大小上。

+0

謝謝,但我測試了字節(逐字節)但結果是不一樣的任何建議? 爲填充,我試過PKCS填充和沒有填充模式,這個想法是我沒有填充模式的限制,因爲PHP服務器使用無填充。 –

3

哦,你忘了使用.getBytes(「UTF-8」); ...

非常重要。

編輯:

我知道我應該提高這個答案的質量,但我這裏說的+下面說什麼Rossum的是竅門能讓這種權利。

這只是關於加密/解密合規性 - 當您跨平臺工作時,您還必須擁有二進制合規性。

所以轉儲原始數據,並檢查它們的差異,直到你的眼睛流血,你發現併成功地修補這個小小的怪癖,使這種差異。 .getBytes(「UTF-8」)會在Java/Android環境中爲您提供一致的字符串(因爲除非您閱讀文檔,否則getBytes()不會像您期望的那樣工作)

+0

謝謝,我已經嘗試了兩種平臺的getBytes(「UTF-8」),但我得到了不同的結果。 –

0

該代碼存在各種問題,但是您在Android上獲取不同密文的原因是您沒有指定IV,並且正在生成隨機密碼。你也可以說'沒有填充',但是iOS代碼正在做填充,Android很可能也是默認的,因爲你沒有明確地指定它。最後,如果你正在加密任何不是塊大小倍數的東西(如你的示例純文本所示),你需要需要填充。 getBytes()默認爲Android上的UTF-8,所以這是您的問題中最少的,但確實要明確。

+0

對不起,提供的鏈接中的錯誤,但雖然我嘗試了相同的IV(我把它硬編碼),並沒有填充iOS代碼我得到了不同的結果,兩個平臺。 我也使用getBytes(「UTF-8」),但仍然有不同的結果。 對於填充類型很抱歉,但PHP服務器使用無填充模式,所以我對這種模式是嚴格的。 感謝您的幫助 –

+0

'沒有填充'只意味着你必須自己填充它,否則你會得到一個錯誤。更新您的代碼以顯示如何使用IV。 –