簡體   English   中英

C# RFC2898DeriveBytes 正在工作,但 Python PBKDF2 生成的密鑰和 IV 不適用於 Python AES 解密

[英]C# RFC2898DeriveBytes is working but Python PBKDF2 generated key and IV are not working with Python AES Decryption

我手頭有一個問題要解密遵循規范的 AES 加密密文 密文包括: · 256 字節的 RFC2898 派生鹽,后跟使用密碼“密碼”和 AES 加密的消息衍生IV。 示例消息是“這是我的秘密字符串,lorem ipsum”,密碼是“password”,使用 C# 代碼加密此消息使用以下 c# 代碼解密得很好

private static readonly int SALT_SIZE = 256;
public static void Decrytor(){
// Encrypted Message
           var cipherText = "i+EKwmlAF0VYh4GwDd+bGf3+yreYsPJW2Oq/w9FXjsp7RI3VqRiqtnqiAD4n6U0JJSTe2ct4B7lgrG+dHxeGcXYEYIERXvU0xnUdH+z3mRwmgYOqCU9HRUKy/z3GKISTm8qH030KTYm3YMBjnKpU8gaRcoDPP/nCiB3o5fPdyspgJgT/qt5BuvwYq7n0qg6ez/Wi4447gq/qHwG3wuuYLSBUCfmIkgGaO1KXqv3SsR8EAhrmMBmPDJfjc3sydNqs5B8J9/JvZFEZULTb8rLQZKQvgHhH9/53Bzs3zmoq0RFbgSueUbyeWb9rLAzYieTz8Yj0srG4GtwPrTPoItc6/hvx5stZ6pX8tgyk9Y3baT0JFMtGgxve7yduy8idTCQdAwRc5NOo4+CBk7P/sIw6+Q==";
            var key = "password";
            // Extract the salt from our cipherText
            var allTheBytes = Convert.FromBase64String(cipherText);
            var saltBytes = allTheBytes.Take(SALT_SIZE).ToArray();
            var cipherTextBytes = allTheBytes.Skip(SALT_SIZE).Take(allTheBytes.Length - SALT_SIZE).ToArray();

            var keyDerivationFunction = new Rfc2898DeriveBytes(key, saltBytes);
            // Derive the previous IV from the Key and Salt
            var keyBytes = keyDerivationFunction.GetBytes(32);
            var ivBytes = keyDerivationFunction.GetBytes(16);

            // Create a decrytor to perform the stream transform.
            // Create the streams used for decryption.
            // The default Cipher Mode is CBC and the Padding is PKCS7 which are both good
            var aesManaged = new AesManaged();
            var decryptor = aesManaged.CreateDecryptor(keyBytes, ivBytes);
            var memoryStream = new MemoryStream(cipherTextBytes);
            var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
            var streamReader = new StreamReader(cryptoStream);

            // Return the decrypted bytes from the decrypting stream.
            Console.WriteLine("\n{0}\n", streamReader.ReadToEnd());
        }

輸出是: “這是我的秘密字符串,lorem ipsum”

但是當我嘗試按照 Python2.7 等效實現解密消息時,它沒有正確解密前幾個字符

import base64
from Crypto.Cipher import AES
from Crypto.Protocol import KDF

def p_decrypt( self, text ):
    text_dec = base64.b64decode(text)
    salt = text_dec[:256]
    enc_txt = text_dec[256:]
    key_bytes = KDF.PBKDF2(self.key, salt, dkLen=32)
    iv = KDF.PBKDF2(self.key, salt)
    cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
    return cipher.decrypt(enc_txt)

輸出為:" 增 "j "t 字符串,lorem ipsum?????????????"

預期輸出:“這是我的秘密字符串,lorem ipsum”

我試圖找到問題所在,當我使用 C# RFC2898DeriveBytes 方法生成的 keyBytes 和 IV 時,該方法也可以正常工作 python 代碼,但 python 代碼沒有使用 PBKDF2 生成的 keyBytes 和 IV 正確解密整個消息。

C# RFC2898DeriveBytes 和 python PBKDF2 都使用 HMACSHA1 散列算法生成 keyBytes,但 C# RFC2898DeriveBytes 方法生成不同的 keyBytes 和 IV,而 Python PBKDF2 返回生成的 keyBytes 的前 16 個字節用於 IV call

請給我一些有用的指導。

謝謝,M Umer

Rfc2898DeriveBytes是一個流響應對象,因此連接兩個連續的調用與執行一個將兩個長度相加的調用相同。

var pbkdf2WithTwoCalls = new Rfc2898DeriveBytes(...)
var pbkdf2WithOneCall = new Rfc2898DeriveBytes(sameParametersAsAbove);

byte[] twoCallA = pbkdf2WithTwoCalls.GetBytes(32);
byte[] twoCallB = pbkdf2WithTwoCalls.GetBytes(16);

byte[] oneCall = pbkdf2WithOneCall.GetBytes(32 + 16);

if (!oneCall.SequenceEquals(twoCallA.Concat(twoCallB))
    throw new TheUniverseMakesNoSenseException();

因此,您在 Python 中的解決方案是對 PBKDF2 進行一次 48 字節的調用,然后將其拆分為 32 字節的 AES 密鑰和 16 字節的 IV。

您的解密響應表明密鑰正確,但 IV 不正確。

# coding:utf8
# python3
# pip3 install pycryptodome

import base64
from Crypto.Cipher import AES
from Crypto.Protocol import KDF

cipherText = 'i+EKwmlAF0VYh4GwDd+bGf3+yreYsPJW2Oq/w9FXjsp7RI3VqRiqtnqiAD4n6U0JJSTe2ct4B7lgrG+dHxeGcXYEYIERXvU0xnUdH+z3mRwmgYOqCU9HRUKy/z3GKISTm8qH030KTYm3YMBjnKpU8gaRcoDPP/nCiB3o5fPdyspgJgT/qt5BuvwYq7n0qg6ez/Wi4447gq/qHwG3wuuYLSBUCfmIkgGaO1KXqv3SsR8EAhrmMBmPDJfjc3sydNqs5B8J9/JvZFEZULTb8rLQZKQvgHhH9/53Bzs3zmoq0RFbgSueUbyeWb9rLAzYieTz8Yj0srG4GtwPrTPoItc6/hvx5stZ6pX8tgyk9Y3baT0JFMtGgxve7yduy8idTCQdAwRc5NOo4+CBk7P/sIw6+Q=='
the_pass = 'password'

text_dec = base64.b64decode(cipherText)
salt = text_dec[:256]
enc_txt = text_dec[256:]
key_iv_bytes = KDF.PBKDF2(the_pass, salt, dkLen=48)

key = key_iv_bytes[:32]
iv = key_iv_bytes[32:]
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(enc_txt)

print(plaintext)
# b'This is my secret string, lorem ipsum\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b'

暫無
暫無

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

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