【问题标题】:C# RijndaelManaged vs Python Crypto.Cipher AES + CBCC# RijndaelManaged vs Python Crypto.Cipher AES + CBC
【发布时间】:2021-10-15 15:18:28
【问题描述】:

我已经把头撞到墙上好几天了,希望有人能指出显而易见的事情。我正在尝试使用Crypto.Cipher 将 C# 的 RijndaelManaged 加密与 Python 的加密相匹配。

问题: 尽管一切都是平等的,但我收到了两个不同的加密输出。

这些是传递的值:

  • 字符串形式的加密密钥(32 个字符)
  • 要加密的值已填充为字符串(在本例中为 32 个字符)

Python 3:

import os
import base64
from Crypto.Cipher import AES

iv = 'wdp0hP2WRKWsuP8B'

def fix_binary_data_length(binary_value):
  block_length = 16
  binary_value_length = len(binary_value)
  length_with_padding = (
    binary_value_length + (block_length - binary_value_length) % block_length
  )
  return binary_value.ljust(length_with_padding, b'=')

def encrypt(value: str, key: str):
  binary_iv = iv.encode('UTF-8')
  binary_value = value.encode('UTF-8')
  binary_value = fix_binary_data_length(binary_value)
  binary_key = key.encode('UTF-8')
  cipher = AES.new(binary_key, AES.MODE_CBC, binary_iv)
  encrypted_value = cipher.encrypt(binary_value)
  return encrypted_value

C#

using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

public class Crypt {

  public static string encrypt(string _sValue, string _sKey){
    string _sIv = "wdp0hP2WRKWsuP8B";
    if (_sKey.Length != 32) { return string.Empty; }
    using (RijndaelManaged _Rijndael = new RijndaelManaged(){
      Mode = CipherMode.CBC,
      KeySize = 256,
      BlockSize = 128
    }){
      byte[] _chEncrypt = Encoding.UTF8.GetBytes(_sValue);
      using (ICryptoTransform _Encryptor = _Rijndael.CreateEncryptor(Encoding.UTF8.GetBytes(_sKey), Encoding.UTF8.GetBytes(_sIv)))
      using (MemoryStream _Stream = new MemoryStream())
      using (CryptoStream _CryptoStream = new CryptoStream(_Stream, _Encryptor, CryptoStreamMode.Write)){
        _CryptoStream.Write(_chEncrypt, 0, _chEncrypt.Length);
        _CryptoStream.FlushFinalBlock();
        return Convert.ToBase64String(_Stream.ToArray());
      }
    }
    return string.Empty;
  }
}

【问题讨论】:

  • 您的 C# 代码将无法编译——您无法从返回 string 的方法中返回 false。如果您甚至没有运行问题中的代码,那么我们花时间逐行​​检查它是没有意义的。请发布一个实际 minimal reproducible example,我们——以及——可以运行。
  • @canton7 抱歉,我刚刚更新了代码。
  • 生成的密文略有不同,因为您使用的是随机 IV。除此之外,您还应用不同的填充。顺便说一句,IV 推导是不合理的(截断 Base64 编码数据)。
  • @Topaco 感谢您的回复。关于 IV,出于上下文原因,我包含了 IV 生成部分,但在测试时,我实际上传递了相同的 16 个字符的 IV 字符串。我从他们每个人那里得到的输出都有些相似。 python 加密字符串:H5DGbNhnJUT/apqzgOvAr2qRG78TgffIrPKhLQMA6T8= 和 C# 加密字符串:H5DGbNhnJUT/apqzgOvAr/rW+2OxvCq7FVMRWuN/YVs= 大约偏离了一半......这与 IV 有关系吗?
  • 不,这是不同的填充(Python 代码中的自定义,C# 代码中的 PKCS7)。应用相同的填充,最好是 PKCS7。 PyCryptodome 支持在专用模块中进行填充,Crypto.Util.Padding

标签: python c# encryption rijndaelmanaged pycryptodome


【解决方案1】:

感谢@Topaco 指出了显而易见的事实;)

似乎我没有完全掌握填充的概念。这就是我让它工作的方式:

import os
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

iv = 'wdp0hP2WRKWsuP8B'

def encrypt(value: str, key: str):
  binary_iv = iv.encode('UTF-8')
  binary_value = value.encode('UTF-8')
  binary_key = key.encode('UTF-8')
  cipher = AES.new(binary_key, AES.MODE_CBC, binary_iv)
  encrypted_value = cipher.encrypt(pad(binary_value, AES.block_size))
  encrypted_value = base64.b64encode(encrypted_value)
  return encrypted_value

【讨论】:

    猜你喜欢
    • 2015-08-04
    • 1970-01-01
    • 2013-08-11
    • 2015-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-11
    相关资源
    最近更新 更多