首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PBKDF2 Python键与.NET Rfc2898

PBKDF2 Python键与.NET Rfc2898
EN

Stack Overflow用户
提问于 2014-10-02 19:52:13
回答 1查看 4.6K关注 0票数 9

我正在尝试编写一个Python模块,该模块将加密现有.NET类可以解密的文本。据我所知,我的代码行向上,但它没有解密(我在C#端得到了一个“无效填充长度”错误)。我的pkcs7代码看起来不错,但是研究表明,无效的密钥可能会导致同样的问题。

这两个机构有什么不同?Python:

代码语言:javascript
复制
derived_key = PBKDF2(crm_key, salt, 256 / 8, iterations)
iv = PBKDF2(crm_key, salt, 128 / 8, iterations)

encoder = pkcs7.PKCS7Encoder()

cipher = AES.new(derived_key, AES.MODE_CBC, iv)
decoded = cipher.decrypt(encoded_secret)

#encode - just stepped so i could debug. 
padded_secret = encoder.encode(secret)              # 1
encodedtext = cipher.encrypt(padded_secret)         # 2
based_secret = base64.b64encode(encodedtext)        # 3

我认为based_secret可以被传递给C#并在那里解码。但失败了。相同的加密c#代码是:

代码语言:javascript
复制
var rfc = new Rfc2898DeriveBytes(key, saltBytes);


        // create provider & encryptor
        using (var cryptoProvider = new AesManaged())
        {
            // Set cryptoProvider parameters
            cryptoProvider.BlockSize = cryptoProvider.LegalBlockSizes[0].MaxSize;
            cryptoProvider.KeySize = cryptoProvider.LegalKeySizes[0].MaxSize;

            cryptoProvider.Key = rfc.GetBytes(cryptoProvider.KeySize / 8);
            cryptoProvider.IV = rfc.GetBytes(cryptoProvider.BlockSize / 8);

            using (var encryptor = cryptoProvider.CreateEncryptor())
            {
                // Create a MemoryStream.
                using (var memoryStream = new MemoryStream())
                {
                    // Create a CryptoStream using the MemoryStream and the encryptor.
                    using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                    {
                        // Convert the passed string to a byte array.
                        var valueBytes = Encoding.UTF8.GetBytes(plainValue);

                        // Write the byte array to the crypto stream and flush it.
                        cryptoStream.Write(valueBytes, 0, valueBytes.Length);
                        cryptoStream.FlushFinalBlock();

                        // Get an array of bytes from the
                        // MemoryStream that holds the
                        // encrypted data.
                        var encryptBytes = memoryStream.ToArray();

                        // Close the streams.
                        cryptoStream.Close();
                        memoryStream.Close();

                        // Return the encrypted buffer.
                        return Convert.ToBase64String(encryptBytes);
                    }
                }
            }

我使用的Python pkcs7实现是:https://gist.github.com/chrix2/4171336

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-10-07 12:21:43

首先,我验证了Rfc2898和PBKDF2是相同的。然后,如前所述,问题似乎是.net主义。我在msdn上发现的

GetBytes在Rfc2898DeriveBytes中的实现在每个调用上都会发生变化,即。它控制着国家。(见约半页的评论)

Python中的示例(伪输出):

代码语言:javascript
复制
derived_key = PBKDF2(key, salt, 32, 1000)
iv = PBKDF2(key, salt, 16, 1000)
print(base64.b64encode(derived_key))
print(base64.b64encode(iv))
$123456789101112134==
$12345678==

.NET中的相同(Ish)代码(同样,伪输出):

代码语言:javascript
复制
var rfc = new Rfc2898DeriveBytes(key, saltBytes);
    using (var cryptoProvider = new AesManaged())
    {
        // Set cryptoProvider parameters
        cryptoProvider.BlockSize = cryptoProvider.LegalBlockSizes[0].MaxSize;
        cryptoProvider.KeySize = cryptoProvider.LegalKeySizes[0].MaxSize;

        cryptoProvider.Key = rfc.GetBytes(cryptoProvider.KeySize / 8);
        cryptoProvider.IV = rfc.GetBytes(cryptoProvider.BlockSize / 8);
    }
Console.Writeline(Convert.ToBase64(cryptoProvider.Key));
Console.Writeline(Convert.ToBase64(cryptoProvider.IV));

$123456789101112134==
$600200300==

随后对rfc.GetBytes的调用总是产生不同的结果。MSDN表示,它会将呼叫的密钥大小进行复合。因此,如果您两次调用GetBytes(20),这与调用GetBytes(20+20)或GetBytes(40)相同。从理论上讲,这应该只是增加键的大小,而不是完全改变它。

有一些解决方案可以解决这个问题,这可能是在第一次调用时生成一个较长的密钥,然后将其分割成派生密钥和IV,或者随机生成一个IV,将其附加到编码的消息中,然后在解密之前将其剥离。

切片python输出产生与.NET相同的结果。

代码语言:javascript
复制
derived_key = PBKDF2(key, salt, 32, 1000)
iv = PBKDF2(key, salt, 32 + 16, 1000) # We need 16, but we're compensating for .NETs 'already called' awesomeness on the GetBytes method
split_key = iv[32:]

print(base64.b64encode(derived_key))
print(base64.b64encode(iv))
print(base64.b64encode(split_key))

$ 123456789101112134==   # matches our derived key
$ 12345678== # doesn't match
$ 600200300== # matches. this is the base 64 encoded version of the tailing 16 bytes.

好好享受,

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26168544

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档