内容简介:Python 与 C# 的 RSA 加解密数据交互
最近在做一个东西,服务端是用 Python 写的 API,客户端是其他语言写的,比如 C#。客户端与服务端之间有个数据通信的需求是通过 RSA 做加解密。例如客户端 C# 使用公钥加密数据,服务端 Python 使用私钥解密数据。因此需要让不同语言的 RSA 加密后的数据兼容,能够互相解密。
在 C# 中 RSA 的私钥和公钥文件是使用 XML 格式存储的,而 Python 的 pycrypto 是使用 PEM 格式,第一个要解决的问题是密钥文件的一致性问题。使用 openssl 生成的 RSA 密钥文件,C# 无法读取。研究了很久 C# 读取 PEM 的方法,但是没有找到简单高效的方法,最后的妥协方法是使用 C# 生成 RSA 的密钥,然后再转成 PEM 格式。
生成 xml 格式的 RSA 密钥
使用如下代码,用 C# 生成 RSA 的密钥
public void GenerateRSAKey()
{
using (var rsa = new RSACryptoServiceProvider(2048))
{
// 输出私钥
Console.WriteLine(rsa.ToXmlString(true));
// 输出公钥
Console.WriteLine(rsa.ToXmlString(false));
}
}
将 RSA 由 xml 转成 pem 格式
可以使用 这个在线工具 ,但是在线 工具 毕竟有数据泄露的风险,最后参考了 这篇文章 ,代码在这里 XMLSec2PEM.java 。
编译代码
javac XMLSec2PEM.java
转换 XML 到 PEM
java XMLSec2PEM your_key.xml
将上述输出的内容保存到 rsa_key.pem。在 Python 中调用会提示 不支持的 RSA Key 格式
,需要进一步做转换
openssl pkcs8 -topk8 -in rsa_key.pem -nocrypt -out rsa.key
最后得到可用的 rsa.key,使用 openssl 提取出公钥
openssl rsa -in rsa.key -pubout -out rsa_pub.key
不同语言兼容的 RSA 加解密
要做到 C# 和 Python 相互兼容的 RSA 加解密还是有很多细节问题的,例如 C# 默认会做随机的填充,因此每次加密得到的数据都不同,以及 Unicode 和 UTF8的编码问题等。
关于 C# 和 Python 之间相互加解密,可以参考 这篇文章 , 代码在这 。以下代码经过测试,C# 加密的数据,Python 可以正确解密,反之亦然。
Python 版的完整代码
需要先安装依赖
pip install pycrypto
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, absolute_import
import sys
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3
if PY3:
text_type = str
binary_type = bytes
else:
text_type = unicode
binary_type = str
def utf8(value):
if not isinstance(value, binary_type) and not isinstance(value, text_type):
value = binary_type(value)
if isinstance(value, text_type):
return value.encode('utf-8')
else:
return value
_TO_UNICODE_TYPES = (text_type, type(None))
def to_unicode(value):
if isinstance(value, _TO_UNICODE_TYPES):
return value
if not isinstance(value, bytes):
raise TypeError(
"Expected bytes, unicode, or None; got %r" % type(value)
)
return value.decode("utf-8")
def read_file(file_path):
with open(file_path, 'r') as f:
return f.read()
rsa_key_content = read_file('rsa.key')
rsa_pub_key_content = read_file('rsa_pub.key')
class RSAHelper(object):
@classmethod
def decrypt(cls, enc_data, key_content=rsa_key_content, passphrase=''):
rsa = RSA.importKey(key_content, passphrase=passphrase)
# Generate a cypher using the PKCS1.5 standard
cipher = PKCS1_v1_5.new(rsa)
return cipher.decrypt(enc_data, '')
@classmethod
def encrypt(cls, plain_data, key_content=rsa_pub_key_content, passphrase=''):
rsa = RSA.importKey(key_content, passphrase=passphrase)
# Generate a cypher using the PKCS1.5 standard
cipher = PKCS1_v1_5.new(rsa)
return cipher.encrypt(utf8(plain_data))
@classmethod
def encrypt_b64(cls, plain_data, key_content=rsa_pub_key_content, passphrase=''):
data = cls.encrypt(plain_data, key_content, passphrase)
data = to_unicode(base64.b64encode(utf8(data)))
return data
@classmethod
def decrypt_b64(cls, enc_data, key_content=rsa_key_content, passphrase=''):
enc_data = base64.b64decode(utf8(enc_data))
data = cls.decrypt(enc_data, key_content, passphrase)
data = to_unicode(data)
return data
if __name__ == '__main__':
enc = RSAHelper.encrypt_b64('123456中文')
print(enc)
plain = RSAHelper.decrypt_b64(enc)
print(plain)
C# 版的完整代码
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace TestConsoleApplication
{
public class RSAHelper
{
public static void Test()
{
try
{
var privateKey = ReadKeyFile("rsa.xml");
var publicKey = ReadKeyFile("rsa_pub.xml");
var dataToEncrypt = "123456中文";
var encryptedData = EncryptBase64(dataToEncrypt, publicKey);
Console.WriteLine("加密后:\n{0}", encryptedData);
var decryptedData = DecryptBase64(encryptedData, privateKey);
Console.WriteLine("解密后:\n{0}", decryptedData);
}
catch (ArgumentNullException)
{
Console.WriteLine("Encryption failed.");
}
Console.ReadLine();
}
public static string ReadKeyFile(stringfilePath)
{
using (var fs = new FileStream(filePath, FileMode.Open))
{
var certBytes = new byte[fs.Length];
fs.Read(certBytes, 0, (int)fs.Length);
return Encoding.UTF8.GetString(certBytes);
}
}
public static string EncryptBase64(stringdataToEncrypt,stringkeyContent,booldoOAEPPadding =false)
{
var byteConverter = new UTF8Encoding();
var bytesToEncrypt = byteConverter.GetBytes(dataToEncrypt);
var data = Encrypt(bytesToEncrypt, keyContent, doOAEPPadding);
if (data == null)
{
return null;
}
var b64Data = Convert.ToBase64String(data);
return b64Data;
}
public static string DecryptBase64(stringdataToDecrypt,stringkeyContent,booldoOAEPPadding =false)
{
var bytesToEncrypt = Convert.FromBase64String(dataToDecrypt);
var data = Decrypt(bytesToEncrypt, keyContent, doOAEPPadding);
var byteConverter = new UTF8Encoding();
return byteConverter.GetString(data);
}
public static byte[]Encrypt(byte[] dataToEncrypt,stringkeyContent,booldoOAEPPadding =false)
{
try
{
byte[] encryptedData;
using (var rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(keyContent);
encryptedData = rsa.Encrypt(dataToEncrypt, doOAEPPadding);
}
return encryptedData;
}
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}
public static byte[]Decrypt(byte[] dataToDecrypt,stringkeyContent,booldoOAEPPadding =false)
{
try
{
byte[] decryptedData;
using (var rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(keyContent);
decryptedData = rsa.Decrypt(dataToDecrypt, doOAEPPadding);
}
return decryptedData;
}
catch (CryptographicException e)
{
Console.WriteLine(e.ToString());
return null;
}
}
}
class Program
{
static void Main(string[] args)
{
RSAHelper.Test();
}
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- Python 与 C# 的 RSA 加解密数据交互
- APICloud解密本地资源到逆向APP算法到通用资源解密
- NodeJS加密解密,node-rsa加密解密用法
- CMSEasy企业建站源代码解密工具,适用于纯本地解密机制!
- 如何解密keystore文件
- 解密 Runloop
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Uberland
Alex Rosenblat / University of California Press / 2018-11-19 / GBP 21.00
Silicon Valley technology is transforming the way we work, and Uber is leading the charge. An American startup that promised to deliver entrepreneurship for the masses through its technology, Uber ins......一起来看看 《Uberland》 这本书的介绍吧!