将C#加密算法转换为Python 3

将C#加密算法转换为Python 3,c#,python,.net,encryption,aes,C#,Python,.net,Encryption,Aes,我已经得到了一个现有的加密算法,在将密码发送到API之前需要对密码进行加密 除了Python,我以前没有任何其他语言的经验,因此我无法理解在功能上我需要做什么来复制它 我相信C#中AES的默认模式是CBC。我想我已经复制了所需的大部分工作,但我需要填充数据,我不知道这到底发生在什么阶段,或者长度是在哪里添加的。我不明白在C代码中事情发生的顺序。我还相信默认的填充方法是PKCS#7,尽管我很高兴在这方面得到纠正 Original code public static string Encrypt

我已经得到了一个现有的加密算法,在将密码发送到API之前需要对密码进行加密

除了Python,我以前没有任何其他语言的经验,因此我无法理解在功能上我需要做什么来复制它

我相信C#中AES的默认模式是CBC。我想我已经复制了所需的大部分工作,但我需要填充数据,我不知道这到底发生在什么阶段,或者长度是在哪里添加的。我不明白在C代码中事情发生的顺序。我还相信默认的填充方法是PKCS#7,尽管我很高兴在这方面得到纠正

Original code

public static string EncryptStringToBytes_Aes(string username, string password)
{
    string encrypted = string.Empty;
    byte[] clearBytes = Encoding. UTF8.GetBytes(password);
    using (Aes aesAlg = Aes.Create())
    {
        byte[] k;
        byte[] iv;
          byte[] bytes = Encoding.UTF8.GetBytes(username);
        k = SHA256.Create().ComputeHash(bytes);
        iv = MD5.Create().ComputeHash(bytes);
        aesAlg.Key = k;
        aesAlg.IV = iv;

        ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, 
        aesAlg.IV);

        using (MemoryStream msEncrypt = new MemoryStream())
        {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, 
                encryptor, CryptoStreamMode.Write))
                {
                    csEncrypt.Write(clearBytes, 0, clearBytes.Length);
                }
                encrypted = Convert.ToBase64String(msEncrypt.ToArray());
        }
    }
    return encrypted;
}
我得到一个“ValueError:输入字符串的长度必须是16的倍数”

当我尝试一些填充时,encode状态为“AttributeError:‘bytes’对象没有属性‘encode’”

我希望能够阅读此代码的人能够帮助我完成用Python重新创建功能的最后步骤。

看看,您没有正确使用密码模块

调用
AES.new()
时,传入的键需要是16个字节的字符串,因此需要将
key
属性填充为16个字节的长度

encrypt()
方法将字节字符串作为输入,当您试图传入一个长度时(在您的示例中甚至没有定义)

您的评论表明您已经通过了,否则您将不会看到
AttributeError
异常

您看到的
AttributeError
是因为
Cipher.encrypt()
返回一个字节数组,而字节数组没有
encode()
方法。您需要首先将字节数组转换为字符串。来自的以下代码段应有帮助:

import array
decoded = array.array('b', your_input).tostring().decode('utf-8') 
显然,您应该将
'utf-8'
替换为
'base64'

查看,您没有正确使用密码模块

调用
AES.new()
时,传入的键需要是16个字节的字符串,因此需要将
key
属性填充为16个字节的长度

encrypt()
方法将字节字符串作为输入,当您试图传入一个长度时(在您的示例中甚至没有定义)

您的评论表明您已经通过了,否则您将不会看到
AttributeError
异常

您看到的
AttributeError
是因为
Cipher.encrypt()
返回一个字节数组,而字节数组没有
encode()
方法。您需要首先将字节数组转换为字符串。来自的以下代码段应有帮助:

import array
decoded = array.array('b', your_input).tostring().decode('utf-8') 

显然,您应该将
'utf-8'
替换为
'base64'

我相信我已经成功了,使用了这里的答案和注释。不需要填充密钥,因为哈希值已经是16的倍数。下面是(希望)成功的代码供参考。(不幸的是,在我测试连接之前,我还要翻译另外两段C代码!)


我相信我已经成功了,在这里我综合运用了答案和评论。不需要填充密钥,因为哈希值已经是16的倍数。下面是(希望)成功的代码供参考。(不幸的是,在我测试连接之前,我还要翻译另外两段C代码!)


对不起,我漏掉了这一行
length=password+'0'+str(len(clearbytes))
看起来不错,应该可以修复输出,我希望一切都只需要PKCS#7填充,但是原始代码行
csEncrypt.Write(clearbytes,0,clearbytes.length)
让我担心,因为我不确定它到底在做什么!建议
按键
不是好建议。应该说为AES-128生成一个随机的16字节密钥。可能可以通过使用PBKDF函数Argon2、Bcrypt和PBKDF2从密码生成
length=password+'0'+str(len(clearbytes))
看起来不错,应该可以修复输出,我希望一切都只需要PKCS#7填充,但是原始代码行
csEncrypt.Write(clearbytes,0,clearbytes.length)
让我担心,因为我不确定它到底在做什么!建议
按键
不是好建议。应该说为AES-128生成一个随机的16字节密钥。可能可以通过使用PBKDF函数Argon2、Bcrypt和PBKDF2从密码生成。您可以在
Crypto.Util.padding
中找到填充函数,或者如果您使用PyCrypto,则可以复制PyCryptodome的填充函数。然而,您的C#代码看起来并不好:它使用散列作为kdf、确定性IV,并且没有身份验证。这些因素可能会降低甚至破坏加密方案的安全性。感谢您的帮助!是的,我知道加密不是很好,它是一个外部公司的API,所以我们必须按要求跳转。幸运的是,这不是我们特别需要保持安全的东西:我们只需要它工作!您可以在
Crypto.Util.padding
中找到填充函数,或者如果您使用的是PyCrypto,则可以复制PyCryptodome的填充函数。然而,您的C#代码看起来并不好:它使用散列作为kdf、确定性IV,并且没有身份验证。这些因素可能会降低甚至破坏加密方案的安全性。感谢您的帮助!是的,我知道加密不是很好,它是一个外部公司的API,所以我们必须按要求跳转。幸运的是,这不是我们特别需要保持安全的东西:我们只需要它工作!
Python Conversion

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import hashlib
import base64


username = "example"
password = "example"
mode = AES.MODE_CBC
bytes = username.encode('utf-8')
data_for_padding = password + '0' + str(len(password))
padded = pad(data_for_padding)

key = hashlib.sha256(bytes).digest()
iv = hashlib.md5(bytes).digest()
encryptor = AES.new(key, mode, IV = iv)
clearbytes = padded.encode('utf-8')
ciphertext = encryptor.encrypt(clearbytes)

result = base64.b64encode(ciphertext)