تشفير على BouncyCastle RSA زوج المفاتيح وتخزينها في SQL2008 قاعدة البيانات

StackOverflow https://stackoverflow.com/questions/844997

سؤال

لدي وظيفة أن يولد BouncyCastle زوج مفاتيح RSA.أنا بحاجة إلى تشفير المفتاح الخاص ومن ثم تخزين مشفرة الخاصة والعامة مفاتيح منفصلة في SQL2008 حقول قاعدة البيانات.

أنا باستخدام التالية للحصول على keypair:

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

من الواضح أن keyBytes وضع أين أنا تحويل keyParam.ToString() غير صحيح كما يحول KeyParameter اسم وليس القيمة الفعلية.أنا تقديم هذه الوظيفة السابقة زوج المفاتيح عودة المفاتيح.خاص.

السؤال الآخر هو أنا لا تشفير المفتاح العام ما هو الشكل الذي يجب أن يكون تخزين هذا في SQL2008 قاعدة البيانات nvarchar(256) أو غيرها ؟

أي مساعدة سيكون موضع تقدير كبير.

هل كانت مفيدة؟

المحلول

عن الأسباب التي ينبغي أن تكون واضحة الافتراضي (وربما غير مقصود) التسلسل لا تلعب بشكل جيد مع المفاتيح الخاصة التي يجب أن إلا أن تكون مكتوبة في حالات محدودة جدا.

BouncyCastle لديه دعم PKCS#8, وهو ذات الصلة معيار "التسلسلية" مفاتيح خاصة.هناك ASN.1 الهياكل يسمى PrivateKeyInfo و EncryptedPrivateKeyInfo.لأنها في ASN.1 هناك معيار طرق تسلسل/إلغاء تسلسل لهم.وكما يوحي اسمها ، أحد المتاجر الرئيسية في نص عادي ، وغيرها بتشفير المفتاح بناء على المرور.

بالنسبة المفاتيح العامة - وهذه لا تكون في العادة المشفرة.قبل الميلاد يدعم معيار X. 509 شكل SubjectPublicKeyInfo عن التسلسلية لهم.

في C# بناء الرفيع المستوى الطبقات أن ننظر ليكون:

  • Org.BouncyCastle.الأمن.PrivateKeyFactory
  • Org.BouncyCastle.الأمن.PublicKeyFactory
  • Org.BouncyCastle.Pkcs.EncryptedPrivateKeyInfoFactory
  • Org.BouncyCastle.Pkcs.PrivateKeyInfoFactory
  • Org.BouncyCastle.X509.SubjectPublicKeyInfoFactory

نصائح أخرى

وطالما يتم وضع علامة على الكائن كما تسلسل، طريقة واحدة لتحويل كائن إلى صفيف بايت هو استخدام فئة BinaryFormatter في صافي.

وسوف تحتاج لإضافة هذه العبارة باستخدام إلى ملف التعليمات البرمجية:

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 المختلفة. (مفاتيح يمكن أيضا أن يتم بناؤها من هذه 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;
}

وهذا يعطينا زوج من السهل استخدام كائنات تسلسل.

ووAsymmetricCipherKeyPair يكشف مفاتيح العامة والخاصة ككائنات AsymmetricKeyParameter. للحصول على خصائص أكثر تفصيلا سوف تحتاج للادلاء هذه إلى ما يلي:

وkeyPair.Public إلى BouncyCastle.Crypto.Parameters.RsaKeyParameters keyPair.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();

وDesierializing هو بعد ذلك فقط معكوس كما هو موضح سابقا. مرة واحدة لديك إما البنيات عامة أو خاصة إلغاء تسلسل يمكنك استخدام contructors 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);

ونأمل أن كل معنى! يجب على نماذج التعليمات البرمجية تساعدك في طريقك.

النهج الصحيح هو استخدام بيترز الاقتراح.

ولقد تضمنت صغيرة 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);

يستخدم النموذج نطاط القلعة API. ملاحظة أن العينة لا تشفير المفتاح.على CreatePrivateKeyInfo طريقة طاقتها للسماح باستخدام كلمة مرور الحماية الرئيسية.

وفيما يتعلق بالجزء الثاني من سؤالك، ونوع البيانات التي يجب أن تستخدم لتخزين المفتاح سيكون VARBINARY (256).

عودة إلى الجزء الأول من سؤالك، لديك فعلا خيار وجود SQL خادم التعامل مع التشفير بالنسبة لك. منح، ما إذا كنت تريد أن تفعل هذا من شأنه أن يكون مسألة ما هي متطلبات التطبيق الخاص بك، ولكنني سوف يذهب أكثر من ذلك في حال خيار.

وسنكون الأساسية جدا هنا ومجرد استخدام مفاتيح متماثل والثلاثي DES.

أولا، قاعدة البيانات لديها المفتاح الرئيسي الذي يستخدم لحماية الشهادات والمفاتيح غير المتماثلة. يتم تشفير المفتاح الرئيسي مع الثلاثي DES.

CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'supersecretpassword'  

وSQL خادم 2005/2008 يمكن أن تولد شهادات X.509 الخاصة بها تستخدم لحماية المفاتيح المستخدمة لتشفير البيانات الفعلية.

CREATE CERTIFICATE ExampleCertificate 
     WITH SUBJECT = 'thisisjustsomemetadata'

وهناك الكثير من الخيارات لتشفير مفاتيح متماثل (شهادات وكلمات السر ومفاتيح أخرى)، فضلا عن العديد من خوارزميات المعتمدة. ولكن بالنسبة لهذا المثال، سنستخدم شهادة لدينا.

CREATE SYMMETRIC KEY ExampleKey
     WITH ALGORITHM = TRIPLE_DES  
     ENCRYPTION BY CERTIFICATE EncryptTestCert 

والاحتياجات الأساسية التي يجب فك باستخدام نفس الطريقة التي تم تشفيرها. في حالتنا، وهذا سيكون على شهادة أنشأنا.

 DECLARE @Value VARCHAR(50)
 SET @Value = 'supersecretdata!'

 OPEN SYMMETRIC KEY ExampleKey DECRYPTION BY CERTIFICATE ExampleCertificate  
     UPDATE SomeTable  
     SET SomeColumn = ENCRYPTBYKEY(KEY_GUID('ExampleKey'), @Value)

فك التشفير تماما كما هو واضحة.

OPEN SYMMETRIC KEY ExampleKey DECRYPTION BY CERTIFICATE ExampleCertificate  
     SELECT CONVERT(VARCHAR(50),DECRYPTBYKEY(SomeColumn)) AS DecryptedData 
     FROM SomeTable 

ونأمل أن هذا حل مشكلتك، أو على الأقل فتح ما يصل الى حلول بديلة (على الرغم من شخص ما الذي لديه خبرة عمل التشفير في C # التطبيقات ربما يمكن العثور على خطأ في رمز أعلاه الخاص بك). إذا كان لديك المتطلبات التي تحتم أن البيانات لا يمكن ان يستمر حتى عبر السلك إلى SQL Server في نص عادي، فمن الواضح أن هذا لا يمكن أن تذهب (وأيضا، <م> يمكن فعلا إنشاء اتصالات SSL ل SQL خادم ...).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top