簡體   English   中英

將RijndaelManaged解密從C#重寫為Python

[英]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.

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