簡體   English   中英

iOS和Android中的AES加密,以及C#.NET中的解密

[英]AES encryption in iOS and Android, and decryption in C#.NET

首先是第一件事。 前段時間我在Android中需要一個簡單的AES加密來加密密碼並將其作為密碼被解密的.net Web服務的參數發送。

以下是我的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的應用程序,所以因為我用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編碼之后。

首先要注意的是,此代碼中存在重大安全問題。 您正在使用字符串密碼並將其放入密鑰中。 如果那個字符串是人類可用的,那么你就會極大地限制你的密鑰空間(將AES-128變成更像AES-40或AES-50,甚至可能更糟)。 您需要使用PBKDF2對密鑰進行加鹽和拉伸。 有關更全面的討論,請參閱使用CommonCrypto使用AES正確加密

您還有一個重大的安全問題,因為您正在使用您的密鑰作為您的IV(請參閱下面的內容;​​這實際上是您的症狀的原因)。 這不是選擇IV的正確方法,並使您的密文可預測。 使用相同密鑰加密的相同明文將給出相同的結果。 這類似於完全沒有IV。 IV必須是隨機的。 有關更多討論,請參閱上面的鏈接。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM