2012-08-14 85 views
13

首先是第一件事。前段時間,我需要在Android中使用簡單的AES加密來加密密碼,並將其作爲密碼被解密的.net Web服務的參數發送。iOS和Android中的AES加密以及C#.NET中的解密。

以下是我的Android加密:

private static String Encrypt(String text, String key) 
     throws Exception { 
     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     byte[] keyBytes= new byte[16]; 
     byte[] b= key.getBytes("UTF-8"); 
     int len= b.length; 
     if (len > keyBytes.length) len = keyBytes.length; 
     System.arraycopy(b, 0, keyBytes, 0, len); 
     SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); 
     IvParameterSpec ivSpec = new IvParameterSpec(keyBytes); 
     cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivSpec); 

     byte[] results = cipher.doFinal(text.getBytes("UTF-8")); 
     String result = Base64.encodeBytes(results); 
     return result; 
     } 

然後我用解密在C#中:

 public static string Decrypt(string textToDecrypt, string key) 
    { 
     System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); 

     RijndaelManaged rijndaelCipher = new RijndaelManaged(); 
     rijndaelCipher.Mode = CipherMode.CBC; 
     rijndaelCipher.Padding = PaddingMode.PKCS7; 

     rijndaelCipher.KeySize = 0x80; 
     rijndaelCipher.BlockSize = 0x80; 

     string decodedUrl = HttpUtility.UrlDecode(textToDecrypt); 
     byte[] encryptedData = Convert.FromBase64String(decodedUrl); 
     byte[] pwdBytes = Encoding.UTF8.GetBytes(key); 
     byte[] keyBytes = new byte[0x10]; 
     int len = pwdBytes.Length; 
     if (len > keyBytes.Length) 
     { 
      len = keyBytes.Length; 
     } 
     Array.Copy(pwdBytes, keyBytes, len); 
     rijndaelCipher.Key = keyBytes; 
     rijndaelCipher.IV = keyBytes; 
     byte[] plainText = rijndaelCipher.CreateDecryptor().TransformFinalBlock(encryptedData, 0, encryptedData.Length); 
     return encoding.GetString(plainText); 
    } 

這工作就像一個魅力,但是當我試圖做的問題來了在iOS中也是如此。我的iPhone/iPad的漂亮的新開發的應用程序,所以ofcause我GOOGLE了它,幾乎提供了所有的代碼示例是如下:

- (NSData *)AESEncryptionWithKey:(NSString *)key { 
char keyPtr[kCCKeySizeAES128]; // room for terminator (unused) 
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding) 

// fetch key data 
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding]; 

NSUInteger dataLength = [self length]; 

size_t bufferSize = dataLength + kCCBlockSizeAES128; 
void *buffer = malloc(bufferSize); 

size_t numBytesEncrypted = 0; 

CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 
             keyPtr, kCCKeySizeAES128, 
             NULL /* initialization vector (optional) */, 
             [self bytes], [self length], /* input */ 
             buffer, bufferSize, /* output */ 
             &numBytesEncrypted); 
if (cryptStatus == kCCSuccess) { 
    //the returned NSData takes ownership of the buffer and will free it on deallocation 
    return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted]; 
} 

free(buffer); //free the buffer; 
return nil; 

}

也許我是有點過於樂觀,當我希望的是平穩過渡這裏,因爲當Android是扔我的東西,如:

"EgQVKvCLS4VKLoR0xEGexA=="

那麼iOS版給我:

"yP42c9gajUra7n0zSEuVJQ==" 

希望它只是我忘了的東西,或者一些設置是錯誤的?

[更新]結果現在顯示在base64編碼之後。

+1

android版本是一個URL編碼的base64字符串,它等於'「YHH + gTxyIxvAx1cPFLcP0IEW2HcVHQVi9X11656CFsk =」''(60 71 fe 81 3c 72 23 1b c0 c7 57 0f ​​14 b7 0f ​​d0 81 16 d8 77 15 1d 05 62 f5 7d 75 eb 9e 82 16 c9)'。 – Joe 2012-08-14 13:17:51

+0

Woops,對不起,我忘了提及這一點。我使用另一種方法對iOS版本的結果進行編碼,但在編碼之前結果不同。 – Morten 2012-08-14 13:21:02

+0

更新了問題以顯示base64編碼後的結果。使用相同的密碼和相同的密鑰。 – Morten 2012-08-14 13:45:41

回答

5

首先需要注意的是,您在此代碼中存在重大的安全問題。你正在接收一個字符串密碼,然後把它放到一個密鑰中。如果這個字符串是人爲的,那麼你已經大幅縮小了你的密鑰空間(把AES-128變成更像AES-40或AES-50,甚至更糟)。您需要使用PBKDF2鹽和拉伸鍵。請參閱Properly encrypting with AES with CommonCrypto進行更全面的討論。

您還有一個重大的安全問題,因爲您將您的密鑰用作IV(請參閱下面的更多內容;這實際上是導致您的症狀的原因)。這不是選擇IV並使您的密文可預測的正確方法。用相同的密鑰加密的相同明文會得到相同的結果。這類似於根本沒有IV。 IV需要是隨機的。有關更多討論,請參閱上述鏈接。

現在到你的實際症狀。問題在於你在Java和C#中使用鍵作爲IV,但是你在iOS上使用0(NULL)作爲IV(IV不是可選的;你只是傳遞0)。你需要在所有情況下使用相同的IV。

+0

我知道存在一些安全問題,但這只是一個臨時解決方案。這只是一個快速解決方案,所以我們沒有傳遞可讀的文本,直到我們的最終解決方案完成。我現在無法真正測試任何東西,因爲它在工作中是一個問題,但是,如果我理解正確,應該修復如果我更改以下內容: 在C#中--decryption:rijndaelCipher.IV = X; 在Java加密中:IvParameterSpec ivSpec = new IvParameterSpec(X); ...並將NULL參數更改爲X,其中X ofcause是相同的值? 順便說一下,非常感謝您的回答... – Morten 2012-08-14 16:18:34

+0

目前上面的代碼中的「X」是除了iOS以外的密鑰副本。你可以使它成爲iOS上的關鍵,或者使它成爲C#和Java的關鍵。我不會讓它有一些靜態值(0除外)。 – 2012-08-14 16:33:48

+0

好的,非常感謝你的幫助。我會明天嘗試,並將您的答案標記爲「已接受」以及... – Morten 2012-08-14 17:04:36