2013-03-27 47 views
0

問題描述

我最近遇到一種情況,這種情況下,我需要做一個256-AES跨平臺的加密/ iOS和之間解密Android使用預定義的String這樣的密鑰,如PreDefinedKey用零爲AES/ECB 256位大小鍵自定義字符串填充/ PKCS7Padding

AES的實現是在iOS上完成的,使用this code,我需要做的就是更改Android上的代碼,以便我可以執行「跨平臺」加密/解密。

注:我知道的iOS上的AES代碼有嚴重的安全/存儲問題,但它目前不是我關心的:-)

我能夠在做加密/解密無論是Android和iOS個人。但是,這裏的兩個AES實現似乎有一個微不足道的差別,這使得我無法進行「跨平臺」的加密/解密。例如,我把Android加密的字符串放到iOS中,它不能返回預期的結果(在這種情況下,它返回null)。

問:

在iOS和Android平臺,我敢肯定,該算法是AES/ECB/PKCS7Padding,與128-Rijndael算法AES實現。

兩個平臺都應該使用256位大小的密鑰。在深入瞭解iOS AES代碼的過程中,我發現它實際上使用zeroes將密鑰填充到256位。

下面是iOS上的相關代碼段零個補白:

// 'key' should be 32 bytes for AES256, will be null-padded otherwise 
    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused) 
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding) 

下面是在代碼中的AES參數(它使用的Rijndael-128算法,256位密鑰大小,NULL爲初始向量):

CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 
            keyPtr, kCCKeySizeAES256, 
            NULL /* initialization vector (optional) */, 
            [self bytes], dataLength, /* input */ 
            buffer, bufferSize, /* output */ 
            &numBytesEncrypted); 

但是在Android上我不知道該怎麼做類似的東西,所以有人能爲我指出正確的方法嗎?


代碼我使用

的Android平臺,我用下面的代碼來執行AES實現:

private static final String AES_SECRET = "PreDefinedKey"; 

/** 
* Method for AES encryption 
* @param raw 
* @param plain 
* @return 
* @throws Exception 
*/ 
private static byte[] encrypt(byte[] raw, byte[] plain) throws Exception { 
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES/ECB/PKCS7Padding"); 
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding"); 
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec); 
    byte[] encrypted = cipher.doFinal(plain); 
    return encrypted; 
} 



/** 
* AES decryption 
* @param encryptMsg 
* @return 
* @throws Exception 
*/ 
public static String AESDecrypt(String encryptMsg) 
     throws Exception {   
    byte[] rawKey = getRawKey(AES_SECRET.getBytes()); 
    //byte[] enc = toByte(encryptMsg); 
    byte[] enc = Base64.decode(encryptMsg, 0); 
    byte[] result = decrypt(rawKey, enc); 
    return new String(result); 

} 

/** 
* Method for AES decryption 
* @param raw 
* @param encrypted 
* @return 
* @throws Exception 
*/ 
private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception { 
    SecretKeySpec keySpec = new SecretKeySpec(raw, "AES/ECB/PKCS7Padding"); 
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding"); 
    cipher.init(Cipher.DECRYPT_MODE, keySpec); 
    byte[] decrypted = cipher.doFinal(encrypted); 
    return decrypted; 

} 

public static byte[] getRawKey(byte[] seed) throws Exception { 

    KeyGenerator kgen = KeyGenerator.getInstance("AES"); 
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 
    sr.setSeed(seed); 
    //Init for 256bit AES key 
    kgen.init(256); 
    SecretKey secret = kgen.generateKey(); 
    //Get secret raw key 
    byte[] raw = secret.getEncoded(); 

    return seed; 

} 

getRawKey()的方法,它使用SHA1PRNG產生隨機填充以使AES密鑰達到與iOS實現不同的256位大小(它使用零填充密鑰到256位)。

那麼,我該如何改變這個方法,以便我可以使用我的預定義的字符串鍵填充零到256位?

如果您需要更多信息,請讓我知道。謝謝!

回答

1

找到誰想出了這個零填充方案,並讓他們被解僱。然後檢查應用程序。

至於你的問題,只需創建一個長度爲32的字節數組並複製密鑰字節開始,使用它初始化SecretKeySpecKeyGenerator將生成一個隨機密鑰,整個「固定種子」的想法是有缺陷的,並不適用於最新的Android版本。這裏有一些代碼:

// zeros by default 
byte[] rawKey = new byte[32]; 
// if you don't specify the encoding you might get weird results 
byte[] keyBytes = AES_SECRET.getBytes("ASCII"); 
System.arraycopy(keyBytes, 0, rawKey, 0, keyBytes.length); 
SecretKey key = new SecretKeySpec(rawKey, "AES"); 
Cipher cipher = ... 
// rest of your decryption code 
+0

很酷,我只是彈出並嘗試你的方法,它工作!還有一個問題:我可能知道爲什麼(或如何)「固定大小」的東西不適用於最新的Android? – dumbfingers 2013-03-28 09:53:57

+1

我的意思是'固定種子'。這裏:http://android-developers.blogspot.jp/2013/02/using-cryptography-to-store-credentials.html – 2013-03-28 11:09:48

+0

thx爲鏈接:-) – dumbfingers 2013-03-28 11:23:10