13

まず最初に。少し前に、パスワードを暗号化し、パスワードが復号化された .net Web サービスのパラメーターとして送信するために、Android で単純な AES 暗号化が必要でした。

以下は私の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;

}

ここでスムーズな移行を望んでいたとき、私は少し楽観的すぎたのかもしれません。

"EgQVKvCLS4VKLoR0xEGexA=="

次に、iOSが私に与えます:

"yP42c9gajUra7n0zSEuVJQ=="

うまくいけば、それは私が忘れたものなのか、それとも設定の一部が間違っているのでしょうか?

[更新] base64 エンコーディング後に結果が表示されるようになりました。

4

1 に答える 1

5

最初の注意点は、このコードには重大なセキュリティ上の問題があるということです。文字列のパスワードを取得して、それをキーにドロップするだけです。その文字列を人間が入力できる場合は、キースペースを大幅に制限しています (AES-128 を AES-40 または AES-50 のように、さらに悪化させる可能性があります)。PBKDF2 を使用してキーをソルトおよびストレッチする必要があります。詳細については、CommonCryptoを使用した AES による適切な暗号化を参照してください。

また、キーを IV として使用しているため、重大なセキュリティ上の問題もあります (詳細は以下を参照してください。これが実際に症状の原因です)。これは IV を選択する正しい方法ではなく、暗号文を予測可能にします。同じ鍵で暗号化された同一の平文は、同じ結果になります。これは、IV がまったくないのと同じです。IV はランダムである必要があります。詳細については、上記のリンクを参照してください。

今あなたの実際の症状に。問題は、Java と C# ではキーを IV として使用しているが、iOS では IV として 0 (NULL) を使用していることです (IV はオプションではなく、0 を渡すだけです)。すべての場合で同じ IV を使用する必要があります。

于 2012-08-14T15:32:05.533 に答える