从Python到C#的AES / RSA实现

时间:2016-09-21 17:11:01

标签: c# python encryption aes rsa

我想将以下python代码迁移到c#中。 入口点是encrypted_request方法

我对python或c#中的aes / rsa没有真正的线索。 也许有人可以解释不同的代码部分,如果可能的话,给我一个提示如何在c#中实现它。 特别是这里和那里使用的神奇数字我不明白。

modulus = ('00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7'
           'b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280'
           '104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932'
           '575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b'
           '3ece0462db0a22b8e7')
nonce = '0CoJUm6Qyw8W8jud'
pubKey = '010001'

def encrypted_request(text):
    text = json.dumps(text)
    secKey = createSecretKey(16)
    encText = aesEncrypt(aesEncrypt(text, nonce), secKey)
    encSecKey = rsaEncrypt(secKey, pubKey, modulus)
    data = {'params': encText, 'encSecKey': encSecKey}
    return data


def aesEncrypt(text, secKey):
    pad = 16 - len(text) % 16
    text = text + chr(pad) * pad
    encryptor = AES.new(secKey, 2, '0102030405060708')
    ciphertext = encryptor.encrypt(text)
    ciphertext = base64.b64encode(ciphertext).decode('u8')
    return ciphertext


def rsaEncrypt(text, pubKey, modulus):
    text = text[::-1]
    rs = pow(int(binascii.hexlify(text), 16), int(pubKey, 16)) % int(modulus, 16)
    return format(rs, 'x').zfill(256)


def createSecretKey(size):
    return binascii.hexlify(os.urandom(size))[:16]

来源:https://github.com/darknessomi/musicbox/blob/master/NEMbox/api.py

我在c#中的当前状态:

private byte[] hex2Binary(string hex) {
    byte[] binaryVal = new byte[hex.Length];
    for (int i = 0; i < hex.Length; i++) {
        string byteString = hex.Substring(i, 1);
        byte b = Convert.ToByte(byteString, 16);
        binaryVal[i] = b;
    }
    return binaryVal;
}
private string aesEncryptBase64(String plainText, string key) {
    return aesEncryptBase64(plainText, hex2Binary(key));
}
private string aesEncryptBase64(String plainText, byte[] key) {
    //pad = 16 - len(text) % 16
    //text = text + chr(pad) * pad
    int pad = 16 - plainText.Length % 16;
    for (int i=0; i<pad; i++) {
        plainText = plainText + ((char)pad);
    }

    byte[] plainBytes = null;
    RijndaelManaged aes = new RijndaelManaged();
    //aes.KeySize = 16;
    aes.Mode = CipherMode.CBC;

    aes.Key = key;
    aes.IV = hex2Binary(client.neteaseFix.encryptInfo.iv);

    MemoryStream ms = new MemoryStream();
    CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write);
    cs.Write(plainBytes, 0, plainBytes.Length);
    cs.Close();
    byte[] encryptedBytes = ms.ToArray();
    return Convert.ToBase64String(encryptedBytes); //decode("u8")
}

1 个答案:

答案 0 :(得分:0)

以下是我发现的一些事情,但这个问题有点过于开放:

  • aesEncryptBase64中,您手动应用填充。 .NET中的AES实现为您做到了这一点。如果您愿意自己动手​​,则需要设置aes.Padding = PaddingMode.None
  • aesEncryptBase64中,您创建了一个RijndaelManaged对象。不要这样做。你想要AES,只需使用AES.Create(),它返回一个AES对象(不是Rijndael对象)。
    • .NET在AES之前支持更大的Rijndael算法;块大小为128位的Rijndael被选为AES,但Rijndael支持AES不支持的模式,你不应该交替使用它们(尽管很多样本都可以)。
  • aesEncryptBase64 aes mscsIDisposable个对象都是rsaEncrypt,因此您应该使用它们。
  • Python中的private static rsaEncrypt(string text, string pubKey, string modulus) { RSAParameters rsaParams = new RSAParameters { Exponent = hex2Binary(pubKey), Modulus = hex2Binary(modulus), }; using (RSA rsa = RSA.Create()) { rsa.ImportParameters(rsaParams); return rsa.Encrypt(Encoding.ASCII.GetBytes(text), YOUNEEDTOPICKTHEPADDINGMODE); } } 方法正在执行原始RSA,这在.NET中是不受支持的(通常也不是一个好主意)。除非它仅由执行填充的例程调用(然后它只是一个旁道漏洞的坑)。

如果你的rsaEncrypt(在Python中)只是从执行签名或加密(或PSS或OAEP)填充的例程调用那么你的.NET等价物就是(使用你的方法命名框,而不是正常的。 NET)

#define KB 1024
#define MB (1024*1024)

size_t poolSize = 16*MB;

尽管如此,改进所有代码将会更好,因此它不必进行如此多的字符串重新解析。