不对称加密包装器



我编写了一个非对称加密包装器,如下所示:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text.Json;
namespace MyEncryptionLibrary
{
public static class AsymmetricCipher
{
//Options for serialising the data. This will make it as small as possible:
private static JsonSerializerOptions jsonSerialiserOptions = new JsonSerializerOptions
{
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
};
public static string Encrypt<T>(T value, RSACryptoServiceProvider destinationPublicKeyRsa)
{
if (value == null)
{
return null;
}
try
{
var json = JsonSerializer.Serialize(value, jsonSerialiserOptions);
using (var aesAlg = Aes.Create())
{
using (var encryptor = aesAlg.CreateEncryptor())
{
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (var swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(json);
}
//Encrypt the key asymmetrically:
var encryptedKey = destinationPublicKeyRsa.Encrypt(aesAlg.Key, true);
var decryptedContent = msEncrypt.ToArray();
using (var ms = new MemoryStream())
using (var bW = new BinaryWriter(ms))
{
bW.Write(encryptedKey.Length);
bW.Write(encryptedKey);
bW.Write(aesAlg.IV.Length);
bW.Write(aesAlg.IV);
bW.Write(decryptedContent.Length);
bW.Write(decryptedContent);
return Convert.ToBase64String(ms.ToArray());
}
}
}
}
}
catch
{
return null;
}
}
public static T Decrypt<T>(string value, RSACryptoServiceProvider receiverPrivateKeyRsa)
{
T result = default(T);
if (string.IsNullOrEmpty(value))
{
return result;
}
try
{
var fullCipher = Convert.FromBase64String(value);
using (var ms = new MemoryStream(fullCipher))
using (var bR = new BinaryReader(ms))
{
var encryptedKeyLength = bR.ReadInt32();
var encryptedKey = bR.ReadBytes(encryptedKeyLength);
var ivLength = bR.ReadInt32();
var iv = bR.ReadBytes(ivLength);
var cipherLength = bR.ReadInt32();
var cipher = bR.ReadBytes(cipherLength);
//Decrypt the asymmetrically encrypted key:
var key = receiverPrivateKeyRsa.Decrypt(encryptedKey, true);
using (var aesAlg = Aes.Create())
{
using (var decryptor = aesAlg.CreateDecryptor(key, iv))
{
using (var msDecrypt = new MemoryStream(cipher))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var srDecrypt = new StreamReader(csDecrypt))
{
var json = srDecrypt.ReadToEnd();
result = JsonSerializer.Deserialize<T>(json);
}
}
}
}
}
}
}
catch { }
return result;
}
}
}

为了进行测试,我生成了一些密钥,如下所示:

public class KeyGenerator
{
private RSA rsa;
public KeyGenerator()
{
rsa = RSA.Create();
}
public string GetPrivateKeyContainer()
{
return rsa.ToXmlString(true);
}
public string GetPublicKeyContainer()
{
return rsa.ToXmlString(false);
}
}

然后通过在测试中使用它们

[TestInitialize]
public void Initialise()
{
keyGenerator = new KeyGenerator();
var publicKey = keyGenerator.GetPublicKeyContainer();
var privateKey = keyGenerator.GetPrivateKeyContainer();
publicKeyRsa = new RSACryptoServiceProvider();
publicKeyRsa.FromXmlString(publicKey);
privateKeyRsa = new RSACryptoServiceProvider();
privateKeyRsa.FromXmlString(privateKey);
}

我已经为它写了一些单元测试,它似乎对大多数人都很有效。然而,以下测试让我感到困惑:

[TestMethod]
public void ItShouldWork_006()
{
//Here the private key is used in both directions:
var text = "I wrote this. It should not matter how long it is as I may be sending a large string, or a smaller string, it's hard to say.";
var encrpyted = AsymmetricCipher.Encrypt(text, privateKeyRsa);
var decrypted = AsymmetricCipher.Decrypt<string>(encrpyted, privateKeyRsa);
Assert.AreNotEqual(text, decrypted);
}

此测试失败,因为解密的文本与输入文本匹配。我本以为用私钥加密的东西也不能用私钥解密,但似乎可以。这是因为私钥容器同时包含私钥和公钥吗?还是我做错了什么?

非常感谢您的任何建议!

RSA.GetXmlString(bool)方法的文档对此非常清楚:

ToXmlString方法创建一个XML字符串,该字符串包含当前RSA对象的公钥和私钥,或者只包含当前RSA物体的公钥。

事实上,RSA对象上提取私钥的所有方法(ExportRSAPrivateKeyTryExportEncryptedPkcs8PrivateKey等(都是作为公钥/私钥对进行提取的。加密总是使用对的公钥来完成的,这就是为什么一个适当安全的连接的两端都有自己的密钥对。(关于为什么,有堆积如山的文章,我只真正理解其中的一小部分——加密很奇怪。(

原则上,可以分离公钥和私钥,但不能使用标准RSA类。

最新更新