加密BouncyCastle RSA密钥对并存储在SQL2008数据库中

Tra*_*PUK 5 .net c# sql-server bouncycastle private-key

我有一个生成BouncyCastle RSA密钥对的函数.我需要加密私钥,然后将加密的私钥和公钥存储到单独的SQL2008数据库字段中.

我使用以下内容获取密钥对:

private static AsymmetricCipherKeyPair createASymRandomCipher()
{
    RsaKeyPairGenerator r = new RsaKeyPairGenerator();
    r.Init(new KeyGenerationParameters(new SecureRandom(), 1024));
    AsymmetricCipherKeyPair keys = r.GenerateKeyPair();
    return keys; 
}
Run Code Online (Sandbox Code Playgroud)

这是正确的返回键,但我不知道如何加密私钥然后将其存储在数据库中.

这是我目前使用的加密数据(错误?):

public static byte[] encBytes2(AsymmetricKeyParameter keyParam, byte[] Key, byte[] IV)
{
    MemoryStream ms = new MemoryStream();
    Rijndael rjdAlg = Rijndael.Create();
    rjdAlg.Key = Key;
    rjdAlg.IV = IV;
    CryptoStream cs = new CryptoStream(ms, rjdAlg.CreateEncryptor(), CryptoStreamMode.Write);
    byte[] keyBytes = System.Text.Encoding.Unicode.GetBytes(keyParam.ToString());
    cs.Write(keyBytes, 0, keyBytes.Length);
    cs.Close();
    byte[] encryptedData = ms.ToArray();
    return encryptedData;
}
Run Code Online (Sandbox Code Playgroud)

显然,我转换keyParam.ToString()的keyBytes设置不正确,因为它只转换KeyParameter名称,而不是实际值.我正在向此函数提交以前的密钥对返回密钥.私有.

另一个问题是因为我没有加密公钥我应该在SQL2008数据库,nvarchar(256)或其他中存储什么格式?

任何帮助将不胜感激.

Pet*_*man 17

由于应该清楚的原因,默认(也许是无意的)序列化不能很好地与私钥一起使用,私钥只能在非常有限的情况下写出.

BouncyCastle支持PKCS#8,这是"序列化"私钥的相关标准.有一些名为PrivateKeyInfo和EncryptedPrivateKeyInfo的ASN.1结构.由于它们在ASN.1中,因此有标准方法可以序列化/反序列化它们.顾名思义,一个用密钥存储密钥,另一个用密码加密密钥.

对于公钥 - 这些通常不会被加密.BC支持SubjectPublicKeyInfo的X.509标准格式以对其进行序列化.

在C#构建中,要查看的高级类将是:

  • Org.BouncyCastle.Security.PrivateKeyFactory
  • Org.BouncyCastle.Security.PublicKeyFactory
  • Org.BouncyCastle.Pkcs.EncryptedPrivateKeyInfoFactory
  • Org.BouncyCastle.Pkcs.PrivateKeyInfoFactory
  • Org.BouncyCastle.X509.SubjectPublicKeyInfoFactory


Jam*_*kle 11

只要对象被标记为可序列化,将对象转换为字节数组的一种方法是使用.Net中的BinaryFormatter类.

您需要将此using语句添加到您的代码文件中:

using System.Runtime.Serialization.Formatters.Binary;
Run Code Online (Sandbox Code Playgroud)

二进制格式化程序可以将您的类输出到流.当您打算将对象转换为字节数组时,可以使用System.IO.MemoryStream作为临时存储.

MemoryStream memStream = new MemoryStream();
Run Code Online (Sandbox Code Playgroud)

然后,您可以创建新的二进制格式化程序.

BinaryFormatter formatter = new BinarryFomatter();
Run Code Online (Sandbox Code Playgroud)

并使用它来序列化您的对象.

formatter.Serialize(memStream, someObject);
Run Code Online (Sandbox Code Playgroud)

要获取可以使用的字节:

return memStream.ToArray();
Run Code Online (Sandbox Code Playgroud)

要反序列化字节数组,需要将字节写入内存流.

memStream.Write(arrBytes, 0, arrBytes.Length);
Run Code Online (Sandbox Code Playgroud)

返回到流的开头.

memStream.Seek(0, SeekOrigin.Begin);
Run Code Online (Sandbox Code Playgroud)

然后使用格式化程序重新创建对象.

Object obj = (Object)formatter.Deserialize(memStream);
Run Code Online (Sandbox Code Playgroud)

如果您已经在使用加密函数,则应该能够在将创建的字节数组存储到数据库之前非常轻松地对其进行加密.

希望这能帮助您朝着正确的方向前进.如果幸运的话,BouncyCastle对象将被标记为可序列化,否则您将需要一些额外的代码.稍后,我将有机会查看BouncyCastle库以便能够对此进行测试,并在必要时发布更多代码.


......我之前从未使用过BouncyCastle.经过一些测试后,看起来公钥和私钥对象都不是可序列化的,所以你需要将这些对象转换成这样的东西!

似乎公钥和私钥将属性公开为各种BouncyCastle.Math.BigInteger值.(键也可以从这些BigIntegers构建).此外,BigIntegers具有ToByteArray()函数,也可以从字节数组构造.很有用..

知道你可以将每个键分解为BigIntegers,然后将这些键分解为一个字节数组,反之亦然,你可以将所有这些存储在一个可序列化的对象中.一个简单的结构或类可以做例如

[Serializable]
private struct CipherPrivateKey
{
    public byte[] modulus;
    public byte[] publicExponent;
    public byte[] privateExponent;
    public byte[] p;
    public byte[] q;
    public byte[] dP;
    public byte[] dQ;
    public byte[] qInv;
}

[Serializable]
private struct CipherPublicKey
{
    public bool isPrivate;
    public byte[] modulus;
    public byte[] exponent;
}
Run Code Online (Sandbox Code Playgroud)

这为我们提供了一对易于使用的可序列化对象.

AsymmetricCipherKeyPair将公钥和私钥公开为AsymmetricKeyParameter对象.要获得更详细的属性,您需要将这些属性转换为以下内容:

keyPair.Public to BouncyCastle.Crypto.Parameters.RsaKeyParameters keyPair.Private to BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters

以下函数将这些函数转换为先前声明的结构:

private static CipherPublicKey getCipherPublicKey(Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters cPublic)
{
    CipherPublicKey cpub = new CipherPublicKey();
    cpub.modulus = cPublic.Modulus.ToByteArray();
    cpub.exponent = cPublic.Exponent.ToByteArray();
    return cpub;
}
private static CipherPrivateKey getCipherPrivateKey(Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters cPrivate)
{
    CipherPrivateKey cpri = new CipherPrivateKey();
    cpri.dP = cPrivate.DP.ToByteArray();
    cpri.dQ = cPrivate.DQ.ToByteArray();
    cpri.modulus = cPrivate.Modulus.ToByteArray();
    cpri.p = cPrivate.P.ToByteArray();
    cpri.privateExponent = cPrivate.Exponent.ToByteArray();
    cpri.publicExponent = cPrivate.PublicExponent.ToByteArray();
    cpri.q = cPrivate.Q.ToByteArray();
    cpri.qInv = cPrivate.QInv.ToByteArray();
    return cpri;
}
Run Code Online (Sandbox Code Playgroud)

使用前面提到的二进制格式化器,我们可以将刚创建的可序列化对象转换为字节数组.

CipherPublicKey cpub = getCipherPublicKey((Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)keypair.Public);
MemoryStream memStream = new MemoryStream();
BinaryFormatter formatter = new BinarryFomatter();
formatter.Serialize(memStream, cpub);
return memStream.ToArray();
Run Code Online (Sandbox Code Playgroud)

然后,Desierializing就像前面描述的那样.一旦你有反序列化的公共或私有结构,你可以使用BouncyCastle结构重新创建密钥.这些功能证明了这一点

private static Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters recreateASymCipherPublicKey(CipherPublicKey cPublicKey)
{
    Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters key;
    key = new Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters(
            cPublicKey.isPrivate,
            createBigInteger(cPublicKey.modulus),
            createBigInteger(cPublicKey.exponent));
    return key;
}

private static Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters recreateASymCipherPrivateKey(CipherPrivateKey cPrivateKey)
{
    Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters key;
    key = new Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters(
            createBigInteger(cPrivateKey.modulus),
            createBigInteger(cPrivateKey.publicExponent),
            createBigInteger(cPrivateKey.privateExponent),
            createBigInteger(cPrivateKey.p),
            createBigInteger(cPrivateKey.q),
            createBigInteger(cPrivateKey.dP),
            createBigInteger(cPrivateKey.dQ),
            createBigInteger(cPrivateKey.qInv));
    return key;
}
Run Code Online (Sandbox Code Playgroud)

如果您因任何原因需要重新创建原始密钥对:

AsymmetricKeyParameter publ = (AsymmetricKeyParameter)recreateASymCipherPublicKey(cKeyPair.publicKey);
AsymmetricKeyParameter priv = (AsymmetricKeyParameter)recreateASymCipherPrivateKey(cKeyPair.privateKey);
AsymmetricCipherKeyPair keyPair = new AsymmetricCipherKeyPair(publ, priv);
Run Code Online (Sandbox Code Playgroud)

希望一切都有意义!代码示例应该可以帮助您.


Hen*_*sen 6

正确的方法是使用Peters的建议.

我在下面添加了一个小的C#代码示例:

var keyPair = GetKeypair();

PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);                        
byte[] serializedKey = privateKeyInfo.ToAsn1Object().GetDerEncoded();

AsymmetricKeyParameter deserializedKey1 = PrivateKeyFactory.CreateKey(serializedKey);
Assert.AreEqual(keyPair.Private, deserializedKey1);

AsymmetricKeyParameter deserializedKey2 = PrivateKeyFactory.CreateKey(privateKeyInfo);            
Assert.AreEqual(keyPair.Private, deserializedKey2);
Run Code Online (Sandbox Code Playgroud)

该示例使用Bouncy Castle API.请注意,该示例不会加密密钥.该CreatePrivateKeyInfo方法被重载以允许使用密码作为密钥的保护.