[英]Rewriting RijndaelManaged decryption from C# to Python
我正在考慮將這個“解密”功能從C#移植到Python(來源: https : //stackoverflow.com/a/10177020 )
public static string Decrypt(string cipherText, string passPhrase)
{
// Get the complete stream of bytes that represent:
// [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
// Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
// Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
// Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();
using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
{
var keyBytes = password.GetBytes(Keysize / 8);
using (var symmetricKey = new RijndaelManaged())
{
symmetricKey.BlockSize = 256;
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
{
using (var memoryStream = new MemoryStream(cipherTextBytes))
{
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
var plainTextBytes = new byte[cipherTextBytes.Length];
var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
}
}
}
}
}
}
我已經在C#中加密了“Hello World”,並設法達到了我在Python中一直使用正確值(包括)keyBytes的程度。 我試圖使用pprp( https://pypi.org/project/pprp/ )和其他庫獲取解密文本,但無論我嘗試什么,我只得到“錯誤的IV大小”或垃圾數據。 我假設我正在努力使用PKCS7填充,但此時我只是完全迷失了。 非常感謝最后一部分的任何幫助。 :)
import pprp
import base64
from pkcs7 import PKCS7Encoder
cipherText = "JKjzaiOSreH+l0GSzsatS8nmohRisvINOwrEjHOwIqIXo88CQT0/al7V7vXOmuamfTeJ235O1SZ0Yd2BZk2e2V4MznT7hyzqzu5J326JIReXPeH6EdtPFrxhdTPsfb8Q"
passphrase = "a78356254f093b00e45434828110c7b5"
# This constant is used to determine the keysize of the encryption algorithm in bits.
# We divide this by 8 within the code below to get the equivalent number of bytes.
keysize = 256
# This constant determines the number of iterations for the password bytes generation function.
derivationIterations = 1000
# Get the complete stream of bytes that represent:
# [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
cipherTextBytesWithSaltAndIv = base64.b64decode(cipherText)
cipherTextBytesWithSaltAndIv=list(bytearray(cipherTextBytesWithSaltAndIv))
# Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
saltStringBytes = cipherTextBytesWithSaltAndIv[:int(keysize / 8)]
# Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
ivStringBytes = cipherTextBytesWithSaltAndIv[int(keysize / 8):int((keysize / 8) * 2)]
# Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
cipherTextBytes = cipherTextBytesWithSaltAndIv[int((keysize / 8) * 2):]
keyBytes = pprp.pbkdf2(passphrase.encode('utf-8'), bytes(saltStringBytes), int(keysize / 8))
print(base64.b64encode(keyBytes))
如果您發布了完整的代碼,包括Rijndael加密(根據您的描述實現了),那將是有意義的。 無論如何,包括使用PBKDF2的密鑰生成的現有Python代碼生成與C#代碼相同的數據。
pprp僅實現Rijndael- block密碼本身。 這樣只允許加密一個完整的塊。 填充和操作模式在很大程度上都沒有實現,即它們仍然必須由用戶實現。 操作模式定義了如何基於塊密碼對多個塊進行加密。 “很大”意味着已經有一個適配器實現(不安全)ECB模式和PKCS7填充。 在這種情況下,這沒有用,因為C#代碼使用CBC模式和PKCS7填充。 為此,必須首先實現適當的適配器。 ECB模式(adapters.py)的現有實現可以用作藍圖。 可能的實現(用於解密)是:
import pprp
import base64
# CBC-Adapter
def rjindael_decrypt_gen_CBC(key, s, iv, block_size=pprp.config.DEFAULT_BLOCK_SIZE_B):
r = pprp.crypto_3.rijndael(key, block_size=block_size) # for Python 2 use crypto_2 instead of crypto_3
i = 0
for block in s:
decrypted = r.decrypt(block)
decrypted = xor(decrypted, iv)
iv = block
yield decrypted
i += 1
def xor(block, iv):
resultList = [ (a ^ b) for (a,b) in zip(block, iv) ]
return bytes(resultList)
#
# Posted code goes here...
#
# Decryption
blocksize = 32
sg = pprp.data_source_gen(cipherTextBytes, blocksize)
dg = rjindael_decrypt_gen_CBC(keyBytes, sg, ivStringBytes, blocksize);
decrypted = pprp.decrypt_sink(dg, blocksize)
print("Decrypted data: " + str(decrypted))
關於“錯誤的IV大小”錯誤消息,我懷疑您嘗試的其他實現實際上是AES實現。 AES是不相同的Rijndael算法,而是一種特殊變異的Rijndael算法 。 例如,AES具有16字節的固定塊大小,而Rijndael允許16,20,24,28或32字節。 在C#代碼中,使用塊大小為32字節的Rijndael,因此其長度必須對應於塊大小的IV也是32字節大。 如果您在AES實現中使用此IV,您將不可避免地收到錯誤消息,如“錯誤的IV大小”或類似的東西。 另外,pprp支持塊大小為16,24和32字節。 默認情況下,使用16字節的塊大小。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.