[英]C# RSA encryption/decryption with transmission
我在 C# 的 .net 上看过很多使用 System.Security.Cryptography.RSACryptoServiceProvider 的加密/解密教程和示例,但我希望能够做的是:
谁能指出我对此有用的资源?
好吧,确实有足够的例子,但无论如何,你去吧
using System;
using System.Security.Cryptography;
namespace RsaCryptoExample
{
static class Program
{
static void Main()
{
//lets take a new CSP with a new 2048 bit rsa key pair
var csp = new RSACryptoServiceProvider(2048);
//how to get the private key
var privKey = csp.ExportParameters(true);
//and the public key ...
var pubKey = csp.ExportParameters(false);
//converting the public key into a string representation
string pubKeyString;
{
//we need some buffer
var sw = new System.IO.StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, pubKey);
//get the string from the stream
pubKeyString = sw.ToString();
}
//converting it back
{
//get a stream from the string
var sr = new System.IO.StringReader(pubKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
pubKey = (RSAParameters)xs.Deserialize(sr);
}
//conversion for the private key is no black magic either ... omitted
//we have a public key ... let's get a new csp and load that key
csp = new RSACryptoServiceProvider();
csp.ImportParameters(pubKey);
//we need some data to encrypt
var plainTextData = "foobar";
//for encryption, always handle bytes...
var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(plainTextData);
//apply pkcs#1.5 padding and encrypt our data
var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);
//we might want a string representation of our cypher text... base64 will do
var cypherText = Convert.ToBase64String(bytesCypherText);
/*
* some transmission / storage / retrieval
*
* and we want to decrypt our cypherText
*/
//first, get our bytes back from the base64 string ...
bytesCypherText = Convert.FromBase64String(cypherText);
//we want to decrypt, therefore we need a csp and load our private key
csp = new RSACryptoServiceProvider();
csp.ImportParameters(privKey);
//decrypt and strip pkcs#1.5 padding
bytesPlainTextData = csp.Decrypt(bytesCypherText, false);
//get our original plainText back...
plainTextData = System.Text.Encoding.Unicode.GetString(bytesPlainTextData);
}
}
}
作为旁注:对 Encrypt() 和 Decrypt() 的调用有一个 bool 参数,可以在 OAEP 和 PKCS#1.5 填充之间切换……如果在您的情况下可用,您可能想要选择 OAEP
public static string Encryption(string strText)
{
var publicKey = "<RSAKeyValue><Modulus>21wEnTU+mcD2w0Lfo1Gv4rtcSWsQJQTNa6gio05AOkV/Er9w3Y13Ddo5wGtjJ19402S71HUeN0vbKILLJdRSES5MHSdJPSVrOqdrll/vLXxDxWs/U0UT1c8u6k/Ogx9hTtZxYwoeYqdhDblof3E75d9n2F0Zvf6iTb4cI7j6fMs=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
var testData = Encoding.UTF8.GetBytes(strText);
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
// client encrypting data with public key issued by server
rsa.FromXmlString(publicKey.ToString());
var encryptedData = rsa.Encrypt(testData, true);
var base64Encrypted = Convert.ToBase64String(encryptedData);
return base64Encrypted;
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
}
public static string Decryption(string strText)
{
var privateKey = "<RSAKeyValue><Modulus>21wEnTU+mcD2w0Lfo1Gv4rtcSWsQJQTNa6gio05AOkV/Er9w3Y13Ddo5wGtjJ19402S71HUeN0vbKILLJdRSES5MHSdJPSVrOqdrll/vLXxDxWs/U0UT1c8u6k/Ogx9hTtZxYwoeYqdhDblof3E75d9n2F0Zvf6iTb4cI7j6fMs=</Modulus><Exponent>AQAB</Exponent><P>/aULPE6jd5IkwtWXmReyMUhmI/nfwfkQSyl7tsg2PKdpcxk4mpPZUdEQhHQLvE84w2DhTyYkPHCtq/mMKE3MHw==</P><Q>3WV46X9Arg2l9cxb67KVlNVXyCqc/w+LWt/tbhLJvV2xCF/0rWKPsBJ9MC6cquaqNPxWWEav8RAVbmmGrJt51Q==</Q><DP>8TuZFgBMpBoQcGUoS2goB4st6aVq1FcG0hVgHhUI0GMAfYFNPmbDV3cY2IBt8Oj/uYJYhyhlaj5YTqmGTYbATQ==</DP><DQ>FIoVbZQgrAUYIHWVEYi/187zFd7eMct/Yi7kGBImJStMATrluDAspGkStCWe4zwDDmdam1XzfKnBUzz3AYxrAQ==</DQ><InverseQ>QPU3Tmt8nznSgYZ+5jUo9E0SfjiTu435ihANiHqqjasaUNvOHKumqzuBZ8NRtkUhS6dsOEb8A2ODvy7KswUxyA==</InverseQ><D>cgoRoAUpSVfHMdYXW9nA3dfX75dIamZnwPtFHq80ttagbIe4ToYYCcyUz5NElhiNQSESgS5uCgNWqWXt5PnPu4XmCXx6utco1UVH8HGLahzbAnSy6Cj3iUIQ7Gj+9gQ7PkC434HTtHazmxVgIR5l56ZjoQ8yGNCPZnsdYEmhJWk=</D></RSAKeyValue>";
var testData = Encoding.UTF8.GetBytes(strText);
using (var rsa = new RSACryptoServiceProvider(1024))
{
try
{
var base64Encrypted = strText;
// server decrypting data with private key
rsa.FromXmlString(privateKey);
var resultBytes = Convert.FromBase64String(base64Encrypted);
var decryptedBytes = rsa.Decrypt(resultBytes, true);
var decryptedData = Encoding.UTF8.GetString(decryptedBytes);
return decryptedData.ToString();
}
finally
{
rsa.PersistKeyInCsp = false;
}
}
}
老实说,我很难实现它,因为我搜索过的几乎没有任何教程显示将密钥写入文件。 接受的答案是“很好”。 但对我来说,我必须改进它,以便将两个键都保存到两个单独的文件中。 我写了一个助手类,所以你们只需要复制并粘贴它。 希望这有助于大声笑。
using Microsoft.Win32;
using System;
using System.IO;
using System.Security.Cryptography;
namespace RsaCryptoExample
{
class RSAFileHelper
{
readonly string pubKeyPath = "public.key";//change as needed
readonly string priKeyPath = "private.key";//change as needed
public void MakeKey()
{
//lets take a new CSP with a new 2048 bit rsa key pair
RSACryptoServiceProvider csp = new RSACryptoServiceProvider(2048);
//how to get the private key
RSAParameters privKey = csp.ExportParameters(true);
//and the public key ...
RSAParameters pubKey = csp.ExportParameters(false);
//converting the public key into a string representation
string pubKeyString;
{
//we need some buffer
var sw = new StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, pubKey);
//get the string from the stream
pubKeyString = sw.ToString();
File.WriteAllText(pubKeyPath, pubKeyString);
}
string privKeyString;
{
//we need some buffer
var sw = new StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, privKey);
//get the string from the stream
privKeyString = sw.ToString();
File.WriteAllText(priKeyPath, privKeyString);
}
}
public void EncryptFile(string filePath)
{
//converting the public key into a string representation
string pubKeyString;
{
using (StreamReader reader = new StreamReader(pubKeyPath)){pubKeyString = reader.ReadToEnd();}
}
//get a stream from the string
var sr = new StringReader(pubKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
csp.ImportParameters((RSAParameters)xs.Deserialize(sr));
byte[] bytesPlainTextData = File.ReadAllBytes(filePath);
//apply pkcs#1.5 padding and encrypt our data
var bytesCipherText = csp.Encrypt(bytesPlainTextData, false);
//we might want a string representation of our cypher text... base64 will do
string encryptedText = Convert.ToBase64String(bytesCipherText);
File.WriteAllText(filePath,encryptedText);
}
public void DecryptFile(string filePath)
{
//we want to decrypt, therefore we need a csp and load our private key
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
string privKeyString;
{
privKeyString = File.ReadAllText(priKeyPath);
//get a stream from the string
var sr = new StringReader(privKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
RSAParameters privKey = (RSAParameters)xs.Deserialize(sr);
csp.ImportParameters(privKey);
}
string encryptedText;
using (StreamReader reader = new StreamReader(filePath)) { encryptedText = reader.ReadToEnd(); }
byte[] bytesCipherText = Convert.FromBase64String(encryptedText);
//decrypt and strip pkcs#1.5 padding
byte[] bytesPlainTextData = csp.Decrypt(bytesCipherText, false);
//get our original plainText back...
File.WriteAllBytes(filePath, bytesPlainTextData);
}
}
}
出于示例目的,我将分享我的非常简单的代码。 希望它能帮助像我这样搜索快速代码参考的人。 我的目标是从后端接收 rsa 签名,然后使用公钥验证输入字符串并在本地存储以备将来定期验证。 这是用于签名验证的主要部分:
...
var signature = Get(url); // base64_encoded signature received from server
var inputtext= "inputtext"; // this is main text signature was created for
bool result = VerifySignature(inputtext, signature);
...
private bool VerifySignature(string input, string signature)
{
var result = false;
using (var cps=new RSACryptoServiceProvider())
{
// converting input and signature to Bytes Arrays to pass to VerifyData rsa method to verify inputtext was signed using privatekey corresponding to public key we have below
byte[] inputtextBytes = Encoding.UTF8.GetBytes(input);
byte[] signatureBytes = Convert.FromBase64String(signature);
cps.FromXmlString("<RSAKeyValue><Modulus>....</Modulus><Exponent>....</Exponent></RSAKeyValue>"); // xml formatted publickey
result = cps.VerifyData(inputtextBytes , new SHA1CryptoServiceProvider(), signatureBytes );
}
return result;
}
对于大数据
public class RsaService : System.IDisposable
{
public delegate int TransformBlockCall(System.ReadOnlySpan<byte> data, System.Span<byte> destination);
private readonly RSA _encoder;
private readonly RSAEncryptionPadding _padding;
private readonly TransformBlockCall _encryptBlockCall;
private readonly TransformBlockCall _decryptBlockCall;
private int _encrypt_InputBlockSize;
private int _encrypt_OutputBlockSize;
private int _decrypt_InputBlockSize;
private int _decrypt_OutputBlockSize;
public RsaService(RSA encoder) {
if(encoder == null)
throw new System.ArgumentNullException(nameof(encoder));
_encoder = encoder;
_padding = RSAEncryptionPadding.Pkcs1;
_encryptBlockCall = new TransformBlockCall(EncryptBlock);
_decryptBlockCall = new TransformBlockCall(DecryptBlock);
OnEndSetParameters();
}
private void OnEndSetParameters() {
_encrypt_InputBlockSize = GetSizeOutputEncryptOfKeySize(_encoder.KeySize);
_encrypt_OutputBlockSize = _encoder.KeySize / 8;
_decrypt_InputBlockSize = _encrypt_OutputBlockSize;
_decrypt_OutputBlockSize = _encrypt_OutputBlockSize;
}
public void ImportParameters(RSAParameters parameters) {
_encoder.ImportParameters(parameters);
OnEndSetParameters();
}
public byte[] Encrypt(byte[] data) {
if(data == null) throw new System.ArgumentNullException(nameof(data));
if(data.Length == 0) return data;
int outputLength = GetEncryptOutputMaxByteCount(data.Length);
byte[] outputData = new byte[outputLength];
Encrypt(data, outputData);
return outputData;
}
public byte[] Decrypt(byte[] data) {
if(data == null) throw new System.ArgumentNullException(nameof(data));
if(data.Length == 0) return data;
int maxOutputLength = GetDecryptOutputMaxByteCount(data.Length);
byte[] outputData = new byte[maxOutputLength];
int actual_OutputLength = Decrypt(data, outputData);
if(maxOutputLength > actual_OutputLength)
System.Array.Resize(ref outputData, actual_OutputLength);
return outputData;
}
public int Encrypt(System.ReadOnlySpan<byte> data, System.Span<byte> destination) {
#if DEBUG
int inputBlockSize = _encrypt_InputBlockSize;
int outputBlockSize = _encoder.KeySize / 8;
int blockCount = (data.Length / inputBlockSize);
if(data.Length % inputBlockSize != 0)
blockCount++;
System.Diagnostics.Debug.Assert((blockCount * outputBlockSize) <= destination.Length);
#endif
if(data.Length > _encrypt_InputBlockSize)
return TransformFinal(_encryptBlockCall, data, destination, _encrypt_InputBlockSize);
else
return _encryptBlockCall(data, destination);
}
public int Decrypt(System.ReadOnlySpan<byte> data, System.Span<byte> destination) {
if(data.Length > _decrypt_InputBlockSize)
return TransformFinal(_decryptBlockCall, data, destination, _decrypt_InputBlockSize);
else
return _decryptBlockCall(data, destination);
}
private int EncryptBlock(System.ReadOnlySpan<byte> data, System.Span<byte> destination) => _encoder.Encrypt(data, destination, _padding);
private int DecryptBlock(System.ReadOnlySpan<byte> data, System.Span<byte> destination) => _encoder.Decrypt(data, destination, _padding);
public int GetEncryptOutputMaxByteCount(int inputCount) => GetBlockCount(inputCount, _encrypt_InputBlockSize) * _encrypt_OutputBlockSize;
public int GetDecryptOutputMaxByteCount(int inputCount) => GetBlockCount(inputCount, _decrypt_InputBlockSize) * _decrypt_OutputBlockSize;
public void Dispose() {
_encoder.Dispose();
System.GC.SuppressFinalize(this);
}
#region Methods_Helper
public static RsaService Create(RSAParameters parameters) => new RsaService(RSA.Create(parameters));
public static RsaService Create() => new RsaService(RSA.Create());
// [keySize] ÷ 8 - [11 bytes for padding] = Result
// Exsimple: [2048 key size] ÷ 8 - [11 bytes for padding] = 245
public static int GetSizeOutputEncryptOfKeySize(int keySize) => (keySize / 8) - 11;
private static int GetBlockCount(int dataLength,int inputBlockSize) {
int blockCount = (dataLength / inputBlockSize);
if(dataLength % inputBlockSize != 0)
blockCount++;
return blockCount;
}
public static int TransformFinal(TransformBlockCall transformBlockCall, System.ReadOnlySpan<byte> data, System.Span<byte> destination, int inputBlockSize) {
int blockCount = GetBlockCount(data.Length, inputBlockSize);
int data_writtenCount = 0;
int destination_writtenCount = 0;
while(blockCount-- > 0) {
if(blockCount == 0) {
inputBlockSize = data.Length - data_writtenCount;
if(inputBlockSize == 0) break;
}
destination_writtenCount += transformBlockCall(data: data.Slice(data_writtenCount, inputBlockSize)
, destination: destination.Slice(destination_writtenCount));
data_writtenCount += inputBlockSize;
}
return destination_writtenCount;
}
public static (RSAParameters keyPublic, RSAParameters keyPrivate) GenerateKeyPair(int keySize = 2048) {
RSAParameters keyPriv;
RSAParameters keyPub;
using(var rsa = RSA.Create(keySize)) {
keyPriv = rsa.ExportParameters(true);
keyPub = rsa.ExportParameters(false);
}
return (keyPub, keyPriv);
}
#endregion Methods_Helper
}
public static class Program
{
static void Main() {
var (keyPublic, keyPrivate) = RsaService.GenerateKeyPair();
var encryptor = RsaService.Create(keyPublic);
var decryptor = RsaService.Create(keyPrivate);
string originalText = "";
for(int i = 0; i < 1000; i++) {
originalText += "ABC123456789";
}
byte[] inputData = Encoding.UTF8.GetBytes(originalText); // data random for test
System.Console.WriteLine("inputData.Length: {0}", inputData.Length);
var encryptedData = encryptor.Encrypt(inputData);
System.Console.WriteLine("encryptedData.Length: {0}", encryptedData.Length);
byte[] decryptedData = decryptor.Decrypt(encryptedData);
string decryptedText = Encoding.UTF8.GetString(decryptedData);
System.Console.WriteLine("status: {0}", decryptedText == originalText);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.