首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >加密RSA密钥对并存储在SQL2008数据库中

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

Stack Overflow用户
提问于 2009-05-10 09:21:28
回答 4查看 15.6K关注 0票数 5

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

我使用以下命令来获取密钥对:

代码语言:javascript
复制
private static AsymmetricCipherKeyPair createASymRandomCipher()
{
    RsaKeyPairGenerator r = new RsaKeyPairGenerator();
    r.Init(new KeyGenerationParameters(new SecureRandom(), 1024));
    AsymmetricCipherKeyPair keys = r.GenerateKeyPair();
    return keys; 
}

这可以很好地返回密钥,但我不确定如何加密私钥并随后将其存储在数据库中。

这就是我目前使用的加密数据(不正确?):

代码语言:javascript
复制
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;
}

显然,我要转换keyParam.ToString()的keyBytes设置是不正确的,因为它只转换KeyParameter名称,而不是实际值。我将keys.Private的前一个密钥对返回提交给此函数。

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

任何帮助都将不胜感激。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-02-02 23:42:41

出于一些应该明确的原因,默认(可能是无意的)序列化不能很好地处理私钥,私钥应该只在非常有限的情况下写出。

BouncyCastle支持PKCS#8,这是“序列化”私钥的相关标准。有称为PrivateKeyInfo和EncryptedPrivateKeyInfo的ASN.1结构。因为它们在ASN.1中,所以有标准的方法来序列化/反序列化它们。顾名思义,一个以明文存储密钥,另一个基于密码加密密钥。

对于公钥-这些通常不会被加密。BC支持用于序列化它们的X.509标准格式的SubjectPublicKeyInfo。

在C#构建中,要查看的高级类如下:

  • Org.BouncyCastle.Security.PrivateKeyFactory
  • Org.BouncyCastle.Security.PublicKeyFactory
  • Org.BouncyCastle.Pkcs.EncryptedPrivateKeyInfoFactory
  • Org.BouncyCastle.Pkcs.PrivateKeyInfoFactory
  • Org.BouncyCastle.X509.SubjectPublicKeyInfoFactory
票数 17
EN

Stack Overflow用户

发布于 2009-05-15 15:03:47

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

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

代码语言:javascript
复制
using System.Runtime.Serialization.Formatters.Binary;

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

代码语言:javascript
复制
MemoryStream memStream = new MemoryStream();

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

代码语言:javascript
复制
BinaryFormatter formatter = new BinarryFomatter();

并用它来序列化你的对象。

代码语言:javascript
复制
formatter.Serialize(memStream, someObject);

要获取可以使用的字节数,请执行以下操作:

代码语言:javascript
复制
return memStream.ToArray();

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

代码语言:javascript
复制
memStream.Write(arrBytes, 0, arrBytes.Length);

返回到流的开头。

代码语言:javascript
复制
memStream.Seek(0, SeekOrigin.Begin);

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

代码语言:javascript
复制
Object obj = (Object)formatter.Deserialize(memStream);

如果您已经在使用加密函数,那么在将创建的字节数组存储到数据库中之前,您应该能够非常容易地对其进行加密。

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

..。我以前从未使用过BouncyCastle。经过一些测试后,似乎公钥和私钥对象是不可序列化的,因此您需要将这些对象转换为可序列化的对象!

看起来,公钥和私钥将属性公开为各种BouncyCastle.Math.BigInteger值。(密钥也可以从这些BigIntegers构造)。此外,BigIntegers有一个ToByteArray()函数,也可以从字节数组构造。非常有用..

知道您可以将每个键分解为BigIntegers,然后将它们转换为字节数组,并且反向操作也是可能的,因此您可以将所有这些内容存储在一个可序列化的对象中。一个简单的结构或类可以做如下工作:

代码语言:javascript
复制
[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;
}

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

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

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

下面的函数将把它们转换成之前声明的结构:

代码语言:javascript
复制
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;
}

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

代码语言:javascript
复制
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();

反其道而行之,如前所述。一旦反序列化了公共或私有结构,就可以使用BouncyCastle构造器重新创建密钥。这些函数说明了这一点。

代码语言:javascript
复制
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;
}

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

代码语言:javascript
复制
AsymmetricKeyParameter publ = (AsymmetricKeyParameter)recreateASymCipherPublicKey(cKeyPair.publicKey);
AsymmetricKeyParameter priv = (AsymmetricKeyParameter)recreateASymCipherPrivateKey(cKeyPair.privateKey);
AsymmetricCipherKeyPair keyPair = new AsymmetricCipherKeyPair(publ, priv);

希望这一切都是有意义的!代码示例应该会对您有所帮助。

票数 11
EN

Stack Overflow用户

发布于 2010-09-28 18:57:42

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

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

代码语言:javascript
复制
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);

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

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/844997

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档