2013-08-06 7 views
5

पढ़ रहा एल्गोरिथ्म आरएसए और निम्नलिखित कोड का उपयोग कर फिर से संगठित करने में सक्षम के साथ जावा उपयोग करते हुए उत्पन्न सार्वजनिक कुंजी है:आरएसए PublicKey

X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(arrBytes); 
KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
publicKey = keyFactory.generatePublic(pubKeySpec); 

प्रश्न कैसे कोई तिथि नहीं का उपयोग कर डॉटनैट तरफ PublicKey निर्माण करने के लिए?

नमूना सार्वजनिक कुंजी ऊपर कोड मैं तत्व में निहित डेटा पास में :, किया जाएगा

<sun.security.rsa.RSAPublicKeyImpl resolves-to="java.security.KeyRep"> 
    <type>PUBLIC</type> 
    <algorithm>RSA</algorithm> 
    <format>X.509</format> 
    <encoded>MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMf54mcK3EYJn9tT9BhRoTX+8AkqojIyeSfog9ncYEye 
0VXyBULGg2lAQsDRt8lZsvPioORZW7eB6IKawshoWUsCAwEAAQ==</encoded> 
    </sun.security.rsa.RSAPublicKeyImpl> 

उत्तर

17

इनकोडिंग दुर्भाग्य से, सी # यह करने के लिए किसी भी आसान तरीका प्रदान नहीं करता है।

public static RSACryptoServiceProvider DecodeX509PublicKey(byte[] x509key) 
{ 
    byte[] SeqOID = { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 }; 

    MemoryStream ms = new MemoryStream(x509key); 
    BinaryReader reader = new BinaryReader(ms); 

    if (reader.ReadByte() == 0x30) 
     ReadASNLength(reader); //skip the size 
    else 
     return null; 

    int identifierSize = 0; //total length of Object Identifier section 
    if (reader.ReadByte() == 0x30) 
     identifierSize = ReadASNLength(reader); 
    else 
     return null; 

    if (reader.ReadByte() == 0x06) //is the next element an object identifier? 
    { 
     int oidLength = ReadASNLength(reader); 
     byte[] oidBytes = new byte[oidLength]; 
     reader.Read(oidBytes, 0, oidBytes.Length); 
     if (oidBytes.SequenceEqual(SeqOID) == false) //is the object identifier rsaEncryption PKCS#1? 
      return null; 

     int remainingBytes = identifierSize - 2 - oidBytes.Length; 
     reader.ReadBytes(remainingBytes); 
    } 

    if (reader.ReadByte() == 0x03) //is the next element a bit string? 
    { 
     ReadASNLength(reader); //skip the size 
     reader.ReadByte(); //skip unused bits indicator 
     if (reader.ReadByte() == 0x30) 
     { 
      ReadASNLength(reader); //skip the size 
      if (reader.ReadByte() == 0x02) //is it an integer? 
      { 
       int modulusSize = ReadASNLength(reader); 
       byte[] modulus = new byte[modulusSize]; 
       reader.Read(modulus, 0, modulus.Length); 
       if (modulus[0] == 0x00) //strip off the first byte if it's 0 
       { 
        byte[] tempModulus = new byte[modulus.Length - 1]; 
        Array.Copy(modulus, 1, tempModulus, 0, modulus.Length - 1); 
        modulus = tempModulus; 
       } 

       if (reader.ReadByte() == 0x02) //is it an integer? 
       { 
        int exponentSize = ReadASNLength(reader); 
        byte[] exponent = new byte[exponentSize]; 
        reader.Read(exponent, 0, exponent.Length); 

        RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); 
        RSAParameters RSAKeyInfo = new RSAParameters(); 
        RSAKeyInfo.Modulus = modulus; 
        RSAKeyInfo.Exponent = exponent; 
        RSA.ImportParameters(RSAKeyInfo); 
        return RSA; 
       } 
      } 
     } 
    } 
    return null; 
} 

public static int ReadASNLength(BinaryReader reader) 
{ 
    //Note: this method only reads lengths up to 4 bytes long as 
    //this is satisfactory for the majority of situations. 
    int length = reader.ReadByte(); 
    if ((length & 0x00000080) == 0x00000080) //is the length greater than 1 byte 
    { 
     int count = length & 0x0000000f; 
     byte[] lengthBytes = new byte[4]; 
     reader.Read(lengthBytes, 4 - count, count); 
     Array.Reverse(lengthBytes); // 
     length = BitConverter.ToInt32(lengthBytes, 0); 
    } 
    return length; 
} 

ऊपर कोड this question पर ही आधारित होता है (जो केवल कुछ महत्वपूर्ण आकार के लिए काम किया): लेकिन यह सही ढंग से एक X509 सार्वजनिक कुंजी (Base64 करने के लिए सुनिश्चित पहले x509key पैरामीटर को डिकोड कर) को डिकोड होगा। उपरोक्त कोड हालांकि किसी भी आरएसए कुंजी आकार के लिए काम करेगा, और आपके द्वारा प्रदान की गई कुंजी के साथ-साथ 2048-बिट और 4096-बिट कुंजी के साथ परीक्षण किया गया है।

एक वैकल्पिक समाधान उपकरण का उपयोग करके प्रमाणपत्र उत्पन्न करना होगा (XCA एक अच्छा है), एक पी 12 (पीकेसीएस 12) फ़ाइल को प्रमाण निर्यात करें और फिर चाबियाँ प्राप्त करने के लिए जावा और सी # दोनों में प्रमाणपत्र लोड करें।

सी # में आप X509Certificate2 कक्षा का उपयोग कर एक पीकेसीएस 12 फ़ाइल लोड कर सकते हैं।

X509Certificate2 cert = new X509Certificate2(certificateFile, certificatePassword, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet); 
RSACryptoServiceProvider provider1 = (RSACryptoServiceProvider)cert.PublicKey.Key; 
RSACryptoServiceProvider provider2 = (RSACryptoServiceProvider)cert.PrivateKey; 

जावा में आप KeyStore कक्षा का उपयोग कर एक पीकेसीएस 12 फ़ाइल लोड कर सकते हैं।

KeyStore keystore = KeyStore.getInstance("PKCS12"); 
keystore.load(new FileInputStream(certificateFile), certificatePassword.toCharArray()); 
Key key = keystore.getKey(certName, certificatePassword.toCharArray()); 
Certificate cert = keystore.getCertificate(certName); 
PublicKey publicKey = cert.getPublicKey(); 
KeyPair keys = new KeyPair(publicKey, (PrivateKey) key); 
+1

@gpa: इस उत्तर को अस्वीकार कर दिया गया।क्या यह आपके लिए काम नहीं करता है? यदि कोई समस्या है, तो क्या आप कुछ स्पष्टीकरण दे सकते हैं? – Syon

+0

देर से जवाब देने के लिए खेद है, लेकिन समाधान मेरे लिए काम नहीं करेगा, क्योंकि सार्वजनिक कुंजी जावा द्वारा उत्पन्न होती है और फ़ाइल में क्रमबद्ध होती है। डॉटनेट एप्लिकेशन ने एक ही सार्वजनिक कुंजी पढ़ी होगी और इसकी पब्लिककी का निर्माण किया होगा ... – gpa

+1

उत्पन्न करने के लिए विशिष्ट जावा कोड क्या है और फिर सार्वजनिक कुंजी को फ़ाइल में क्रमबद्ध करें? (क्या आप इसे अपने प्रश्न में जोड़ सकते हैं) जावा क्रमबद्ध ऑब्जेक्ट को पढ़ने वाला डॉटनेट आसानी से करने योग्य नहीं है, लेकिन यदि आप एक मानक प्रारूप में सार्वजनिक कुंजी को सहेज रहे हैं, तो इसे सी # में पुनर्निर्माण करना संभव होना चाहिए। – Syon

0

जावा में, RSAPublicKey करने के लिए PublicKey से publicKey डाली।

getModulus और getExponent आप BigIntegers, जिसमें से आप toByteArray का उपयोग बाइट्स प्राप्त करने के लिए मिल जाएगा है।

मुझे नहीं पता कि जावा BigInteger कक्षा में अग्रणी 0s रखता है, इसलिए जांच करें कि क्या आपको सार्वजनिक एक्सपोनेंट से अग्रणी नल (0x00) बाइट्स को पट्टी करना है या नहीं।

एनकोड आधार 64 में बाइट सरणियों या तो Apache Commons Codec या Java 8's Base64 Encoder का उपयोग कर।

आपको बाइट ऑर्डर की जांच करने की आवश्यकता हो सकती है (शायद मॉड्यूलस को रिवर्स करें, सुनिश्चित नहीं है)।

को क्रमानुसार इन इस XML का निर्माण करके: "<RSAKeyValue><Modulus> {अपने आधार 64 इनकोडिंग सार्वजनिक मापांक यहाँ} {</Modulus><Exponent> अपने आधार 64 इनकोडिंग सार्वजनिक प्रतिपादक यहां} </Exponent></RSAKeyValue>"

CSharp में:

var rsaCsp = new RSACryptoServiceProvider(o.BitLength); 
rsaCsp.FromXmlString(xmlRsaKeyValue); 

अब आप एक आरएसए सीएसपी आपकी सार्वजनिक कुंजी के साथ भरी हुई है।

पी, क्यू, डीपी, डीक्यू और इनवर्क्सक एक्सएमएल तत्वों को जोड़कर एक निजी कुंजी लोड करने के लिए एक ही प्रक्रिया को बढ़ाया जा सकता है।

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