5

BouncyCastleRSAキーペアを生成する関数があります。秘密鍵を暗号化してから、暗号化された秘密鍵と公開鍵を別々のSQL2008データベースフィールドに保存する必要があります。

キーペアを取得するために以下を使用しています。

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

これで鍵が正常に返されますが、秘密鍵を暗号化してデータベースに保存する方法がわかりません。

これは私が現在データの暗号化を使用しているものです(間違って?):

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名のみを変換するため、正しくありません。この関数に、以前のキーペアのキーの戻りを送信しています。プライベート。

もう1つの質問は、公開鍵を暗号化していないため、SQL2008データベース、nvarchar(256)などにどの形式で保存する必要があるかということです。

どんな助けでも大歓迎です。

4

4 に答える 4

17

明らかな理由から、デフォルトの (そしておそらく不注意による) シリアライゼーションは、非常に限られた状況でのみ書き出す必要がある秘密鍵ではうまく機能しません。

BouncyCastle は、秘密鍵の「シリアル化」に関連する標準である PKCS#8 をサポートしています。PrivateKeyInfo および EncryptedPrivateKeyInfo と呼ばれる ASN.1 構造があります。それらは ASN.1 にあるため、シリアライズ/デシリアライズする標準的な方法があります。名前が示すように、1 つはキーを平文で保存し、もう 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
于 2010-02-02T15:42:40.937 に答える
11

オブジェクトがシリアル化可能としてマークされている限り、オブジェクトをバイト配列に変換する1つの方法は、.NetのBinaryFormatterクラスを使用することです。

次のusingステートメントをコードファイルに追加する必要があります。

using System.Runtime.Serialization.Formatters.Binary;

バイナリフォーマッタは、クラスをストリームに出力できます。オブジェクトをバイト配列に変換する場合は、System.IO.MemoryStreamを一時ストレージとして使用できます。

MemoryStream memStream = new MemoryStream();

その後、新しいバイナリフォーマッタを作成できます。

BinaryFormatter formatter = new BinarryFomatter();

これを使用してオブジェクトをシリアル化します。

formatter.Serialize(memStream, someObject);

使用できるバイトを取得するには、次のようにします。

return memStream.ToArray();

バイト配列を逆シリアル化するには、バイトをメモリストリームに書き込む必要があります。

memStream.Write(arrBytes, 0, arrBytes.Length);

ストリームの最初に戻ります。

memStream.Seek(0, SeekOrigin.Begin);

次に、フォーマッタを使用してオブジェクトを再作成します。

Object obj = (Object)formatter.Deserialize(memStream);

すでに暗号化機能を使用している場合は、作成したバイト配列をデータベースに保存する前に非常に簡単に暗号化できるはずです。

うまくいけば、それは正しい方向にあなたを助けるでしょう。運が良ければ、BouncyCastleオブジェクトはシリアル化可能としてマークされますが、そうでない場合は、追加のコードが必要になります。後で、これをテストできるようにBouncyCastleライブラリを確認する機会があり、必要に応じてさらにコードを投稿します。


...私はこれまでBouncyCastleを使用したことがありません。いくつかのテストの結果、公開鍵オブジェクトと秘密鍵オブジェクトはシリアル化できないようです。そのため、これらのオブジェクトをシリアル化できるものに変換する必要があります。

公開鍵と秘密鍵は、プロパティをさまざまなBouncyCastle.Math.BigInteger値として公開しているようです。(キーはこれらのBigIntegerから作成することもできます)。さらに、BigIntegersにはToByteArray()関数があり、バイト配列から構築することもできます。非常に便利..

各キーをBigIntegerに分割し、これらをバイト配列に分割することができ、その逆も可能であることを知っているので、これらすべてをシリアル化可能なオブジェクトに格納する方法があります。単純な構造体またはクラスは、たとえば

[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からBouncyCastle.Crypto.Parameters.RsaKeyParameterskeyPair.Privateから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;
}

前述のバイナリフォーマッタを使用して、作成したばかりのシリアル化可能なオブジェクトをバイト配列に変換できます。

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構造体を使用してキーを再作成できます。これらの関数はこれを示しています。

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;
}

何らかの理由で元のキーペアを再作成する必要がある場合:

AsymmetricKeyParameter publ = (AsymmetricKeyParameter)recreateASymCipherPublicKey(cKeyPair.publicKey);
AsymmetricKeyParameter priv = (AsymmetricKeyParameter)recreateASymCipherPrivateKey(cKeyPair.privateKey);
AsymmetricCipherKeyPair keyPair = new AsymmetricCipherKeyPair(publ, priv);

うまくいけば、それはすべて理にかなっています!コードサンプルは、途中で役立つはずです。

于 2009-05-15T15:03:46.723 に答える
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);

このサンプルでは、​​Bouncy Castle API を使用しています。サンプルはキーを暗号化しないことに注意してください。このCreatePrivateKeyInfoメソッドは、キーの保護としてパスワードを使用できるようにオーバーロードされています。

于 2010-09-28T10:57:42.180 に答える