2009-05-10 12 views
5

में संग्रहीत करना मेरे पास एक ऐसा फ़ंक्शन है जो बाउंसीकास्टल आरएसए कुंजी जोड़ी उत्पन्न करता है। मुझे निजी कुंजी एन्क्रिप्ट करने की आवश्यकता है और फिर एन्क्रिप्टेड निजी और सार्वजनिक कुंजी को अलग SQL2008 डेटाबेस फ़ील्ड में स्टोर करना होगा।एक बाउंसीकास्टल आरएसए कुंजी जोड़ी को एन्क्रिप्ट करना और 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; 
} 

जाहिर keyBytes की स्थापना, जहां मैं keyParam.ToString() परिवर्तित कर रहा हूँ सही नहीं है, क्योंकि यह केवल KeyParameter नाम धर्मान्तरित वास्तविक मूल्य नहीं। मैं इस समारोह में पिछली कुंजी जोड़ी की चाबियों की वापसी कर रहा हूं। निजी।

दूसरा प्रश्न यह है कि मैं सार्वजनिक कुंजी को एन्क्रिप्ट नहीं कर रहा हूं, मुझे SQL2008 डेटाबेस, nvarchar (256) या अन्य में इसे किस प्रारूप में संग्रहीत किया जाना चाहिए?

किसी भी मदद की सराहना की जाएगी।

+0

किसी को भी इस पर कुछ विचार मिल गए हैं? – TravisPUK

उत्तर

16

कारणों के लिए स्पष्ट होना चाहिए, डिफ़ॉल्ट (और शायद अनजान) क्रमिकरण निजी कुंजी के साथ अच्छी तरह से नहीं खेलता है जिसे केवल सीमित स्थितियों में ही लिखा जाना चाहिए।

बाउंसीकास्टल को पीकेसीएस # 8 के लिए समर्थन है, जो निजी कुंजी "क्रमबद्ध" के लिए प्रासंगिक मानक है। PrivateKeyInfo और EncryptedPrivateKeyInfo नामक ASN.1 संरचनाएं हैं। चूंकि वे एएसएन 1 में हैं, इसलिए उन्हें क्रमबद्ध/deserialize करने के मानक तरीके हैं। जैसा कि नाम से पता चलता है, एक सादे टेक्स्ट में कुंजी स्टोर करता है, दूसरा पासवर्ड के आधार पर कुंजी को एन्क्रिप्ट करता है।

सार्वजनिक कुंजी के लिए - ये आमतौर पर एन्क्रिप्टेड नहीं होंगे। बीसी उन्हें serializing के लिए SubjectPublicKeyInfo के X.50 9 मानक प्रारूप का समर्थन करता है।

सी # निर्माण में, उच्च स्तर की कक्षाओं में देखने के लिए होगा पर:

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

पीटर, आपकी टिप्पणी के लिए धन्यवाद। मैं इस पर ध्यान दूँगा। – TravisPUK

+1

मुझे लगता है कि यह टिप्पणी वास्तव में इस प्रश्न का सही उत्तर है। AsymmetricKeyParameter वर्ग serializable नहीं है एक कारण है। चयनित उत्तर में उल्लिखित समाधान एक सुरक्षा समस्या होने का इंतजार कर रहा है। – Henrik

+0

मुझे एक त्रुटि मिल रही है: पीबीई एन्क्रिप्टेड प्राइवेटकेइन्फो पीढ़ी के साथ गैर-पीबीई एल्गोरिदम का उपयोग करने का प्रयास - किसी को पता है कि मुझे किस एल्गोरिदम का उपयोग करना चाहिए? मैं वर्तमान में PBEWithSHAAnd3KeyTripleDES – daveBM

1

आपके प्रश्न के दूसरे भाग के संबंध में, कुंजी प्रकार को संग्रहीत करने के लिए उपयोग किए जाने वाले डेटा प्रकार VARBINARY (256) होंगे।

अपने प्रश्न के पहले भाग पर वापस, आपके पास वास्तव में SQL सर्वर को आपके लिए एन्क्रिप्शन संभाल करने का विकल्प है। अनुमोदित, चाहे आप ऐसा करना चाहते हैं, यह आपके मामले की आवश्यकताओं के मामले में होगा, लेकिन अगर यह विकल्प है तो मैं इसे खत्म कर दूंगा।

हम यहां बहुत बुनियादी होंगे और केवल सममित कुंजी और ट्रिपल-डीईएस का उपयोग करें।

सबसे पहले, डेटाबेस में एक मास्टर कुंजी है जिसका उपयोग प्रमाणपत्र और असममित कुंजी की सुरक्षा के लिए किया जाता है। मास्टर कुंजी ट्रिपल-डीईएस के साथ एन्क्रिप्ट किया गया है।

CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'supersecretpassword' 

SQL सर्वर 2005/2008 वास्तविक डेटा एन्क्रिप्ट करने के लिए उपयोग की जाने वाली कुंजियों की सुरक्षा के लिए अपने स्वयं के X.50 9 प्रमाणपत्र उत्पन्न कर सकता है।

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 

उम्मीद है कि यह आपकी समस्या हल हो, या कम से कम आप वैकल्पिक समाधान के लिए खोल दिया है (हालांकि कोई है जो सी # क्षुधा में अनुभव कर एन्क्रिप्शन शायद अपनी उपरोक्त कोड में गलती मिल सकता था है)।यदि आपके पास ऐसी आवश्यकताएं हैं जो डेटा को सादे-पाठ में SQL सर्वर पर तार पर भी नहीं जा सकते हैं, तो जाहिर है यह एक नो-गो है (ठीक है, आप वास्तव में SQL सर्वर से SSL कनेक्शन बना सकते हैं ...)।

+0

आलसी: आपकी प्रतिक्रिया के लिए धन्यवाद। मुझे याद आया कि SQL2008 अपनी स्वयं की एन्क्रिप्शन कर सकता है, लेकिन इसके बारे में कुछ नहीं पता था, उस जानकारी के लिए धन्यवाद। जिस फ़ंक्शन को मैं बिल्ड कर रहा हूं उसे ऑपरेटर की चाबियों के आधार पर क्लाइंट पर एन्क्रिप्शन और डिक्रिप्शन करने की आवश्यकता है ताकि मैं तार में स्पष्ट टेक्स्ट नहीं भेज सकूं। तो अगर यह मेरी समस्या का समाधान नहीं करता है, तो यह निश्चित रूप से कुछ विकल्पों के लिए मेरी आंखें खोलता है। ;) – TravisPUK

+0

ओह, varbinary (256) टिप के लिए भी धन्यवाद। – TravisPUK

11

जब तक ऑब्जेक्ट को धारावाहिक के रूप में चिह्नित किया जाता है, तब तक ऑब्जेक्ट को बाइट सरणी में परिवर्तित करने का एक तरीका है। नेट में बाइनरीफॉर्मेटर क्लास का उपयोग करना।

आप अपने कोड फाइल करने के लिए इस कथन का उपयोग जोड़ने की आवश्यकता होगी:

using System.Runtime.Serialization.Formatters.Binary; 

एक द्विआधारी फ़ॉर्मेटर एक धारा के लिए अपने वर्ग उत्पादन कर सकते हैं। जैसा कि आप अपनी ऑब्जेक्ट को बाइट सरणी में कनवर्ट करना चाहते हैं, आप सिस्टम.आईओ.मेमरीस्ट्रीम को अस्थायी स्टोरेज के रूप में उपयोग कर सकते हैं।

MemoryStream memStream = new MemoryStream(); 

फिर आप एक नया बाइनरी फॉर्मेटर बना सकते हैं।

BinaryFormatter formatter = new BinarryFomatter(); 

और अपने ऑब्जेक्ट को क्रमबद्ध करने के लिए इसका उपयोग करें।

formatter.Serialize(memStream, someObject); 

बाइट्स आप उपयोग कर सकते हैं पाने के लिए:

return memStream.ToArray(); 

बाइट सरणी आप एक स्मृति धारा बाइट्स लिखने की ज़रूरत deserialize करने के लिए।

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

स्ट्रीम की शुरुआत पर लौटें।

memStream.Seek(0, SeekOrigin.Begin); 

फिर ऑब्जेक्ट को फिर से बनाने के लिए फ़ॉर्मेटर का उपयोग करें।

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

आप पहले से ही सुरक्षित तरीका कार्यक्षमताओं का उपयोग कर रहे हैं, तो आप डेटाबेस में भंडारण से पहले काफी आसानी से बनाया बाइट सरणी एन्क्रिप्ट करने के लिए सक्षम होना चाहिए।

उम्मीद है कि यह आपको सही दिशा में मदद करेगा। यदि आप भाग्यशाली हैं, तो BouncyCastle ऑब्जेक्ट्स को धारावाहिक के रूप में चिह्नित किया जाएगा, अगर आपको कुछ अतिरिक्त कोड की आवश्यकता नहीं है। बाद में, मुझे इसका परीक्षण करने में सक्षम होने के लिए बाउंसीकास्ट लाइब्रेरी को देखने का मौका मिलेगा और यदि आवश्यक हो तो अधिक कोड पोस्ट करेंगे।


... मैंने पहले कभी बाउंसीकास्टल का उपयोग नहीं किया है। कुछ परीक्षणों के बाद, ऐसा प्रतीत होता है कि सार्वजनिक और निजी कुंजी वस्तुएं क्रमबद्ध नहीं हैं, इसलिए आपको इन वस्तुओं को किसी चीज़ में परिवर्तित करने की आवश्यकता होगी!

ऐसा प्रतीत होता है कि सार्वजनिक और निजी कुंजी विभिन्न BouncyCastle.Math.BigInteger मानों के रूप में गुणों का पर्दाफाश करती हैं। (इन बिगइंटर से चाबियाँ भी बनाई जा सकती हैं)। इसके अलावा, BigIntegers के पास ToByteArray() फ़ंक्शन है और इसे बाइट सरणी से भी बनाया जा सकता है। बहुत उपयोगी ..

यह जानकर कि आप प्रत्येक कुंजी को बिगइंटर में तोड़ सकते हैं और इन्हें बाइट सरणी में बदल दिया जा सकता है और यह भी संभव है कि आप इन सभी को एक धारावाहिक वस्तु में स्टोर करने का एक तरीका भी संभव हो। एक साधारण संरचना या कक्षा उदा।

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

यह हमें धारावाहिक वस्तुओं का उपयोग करने में आसान बनाता है।

असीमेट्रिक कैफेरपेयर सार्वजनिक और निजी कुंजी को असममित केपे पैरामीटर वस्तुओं के रूप में उजागर करता है।

निम्नलिखित

keyPair.Public BouncyCastle.Crypto.Parameters.RsaKeyParameters को BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters को keyPair.Private: अधिक विस्तृत संपत्तियों पर प्राप्त करने के लिए आप इन निम्नलिखित को कास्ट करने के लिए की आवश्यकता होगी कार्यों की घोषणा पहले के structs करने के लिए इन में परिवर्तित कर देंगे:

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

द्विआधारी फ़ॉर्मेटर पहले उल्लेख किया है का उपयोग करना, हम serializable वस्तुओं हम सिर्फ एक बाइट सरणी के लिए बनाया है बदल सकते हैं।

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 पहले वर्णित जैसा ही विपरीत है। एक बार जब आपके पास सार्वजनिक या निजी structs deserialized हो, तो आप कुंजी को फिर से बनाने के लिए 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); 

उम्मीद है कि है कि सभी समझ में आता है! कोड नमूने आपको अपने रास्ते पर मदद कर सकते हैं।

+0

@ जेम्स, इसके लिए धन्यवाद। यह निश्चित रूप से मुझे सही दिशा में डाल देगा। बाउंसीकास्टल ऑब्जेक्ट्स को क्रमबद्ध करने के लिए, मुझे यकीन नहीं है। मैं इसकी जांच भी करूंगा। मैं पहले से ही एन्क्रिप्शन फ़ंक्शंस का उपयोग कर रहा हूं इसलिए इसे लागू करने पर विचार किया जाएगा। – TravisPUK

+0

हे कूल, ऐसा लगता है कि यह अच्छी तरह से चाल है। धन्यवाद जेम्स, वास्तव में मदद की सराहना करते हैं! – TravisPUK

+0

जबकि मेरा जवाब दिखाता है कि यह किया जा सकता है, इसका मतलब यह नहीं है कि यह किया जाना चाहिए, पीटर का सुझाव बहुत बेहतर है और हेनरिक सुझाव देता है कि इस तरह से क्रमबद्ध करने से सुरक्षा समस्याएं पैदा हो सकती हैं। – JamPickle

6

सही दृष्टिकोण पीटर्स के सुझाव का उपयोग करना है।

मैं एक छोटे से सी # कोड नमूना नीचे में शामिल हैं:

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 कैसल API का उपयोग करता। नोट कि नमूना कुंजी को एन्क्रिप्ट नहीं करता है। कुंजी की सुरक्षा के रूप में पासवर्ड के उपयोग की अनुमति देने के लिए CreatePrivateKeyInfo विधि ओवरलोड हो गई है।

+0

का उपयोग कर रहा हूं धन्यवाद हेनरिक, मैं इसे देख लूंगा। – TravisPUK

+0

स्पष्ट उदाहरण के लिए धन्यवाद - मैं 'PrivateKeyFactory.CreateKey (बाइट []) हमेशा के लिए देख रहा था! –

संबंधित मुद्दे