2013-10-31 12 views
10

से SecKeyRef लाने में असमर्थ मैं उद्देश्य सी & आईओएस प्रोग्रामिंग के लिए नया हूं।उद्देश्य सी: पीईएम निजी कुंजी

मैं सर्वर और क्लाइंट के बीच आदान-प्रदान की जाने वाली डेटा को एन्क्रिप्ट करने और डिक्रिप्ट करने के लिए openssl का उपयोग करके उत्पन्न एक साधारण सार्वजनिक/निजी कुंजी (पीईएम प्रारूप) का उपयोग कर रहा हूं। मुझे यह सफलतापूर्वक जावा सर्वर & क्लाइंट में काम कर रहा है।

समस्या तब शुरू हुई जब मैं जावा में सार्वजनिक कुंजी का उपयोग करके डेटा एन्क्रिप्ट कर रहा था और उद्देश्य सी/आईओएस में निजी कुंजी का उपयोग करके डिक्रिप्ट कर रहा था। मैंने कुछ उदाहरणों को देखा है और कुछ कोड एक साथ रखे हैं लेकिन मुझे एक त्रुटि मिल रही है -25300 जब मैं निजी कुंजी से SecKeyRef बनाने के हिस्से के रूप में SecItemCopyMatching को हर समय कॉल करता हूं।

बीटीडब्ल्यू, यहां कोई प्रमाण पत्र शामिल नहीं है और यह केवल सादे कुंजी है। यह है कि मैं क्या कर रहा हूं:

  1. पीईएम निजी कुंजी और बेस 64 डीकोड पढ़ें।
  2. SecItemCopyMatching का उपयोग करके डीकोडेड स्ट्रिंग से SecKeyRef उत्पन्न करें।
  3. SecKeyDecrypt का उपयोग करके डिक्रिप्ट करें।

मेरे समस्या # 2 कदम जो -25,300 की स्थिति वापस है (errSecItemNotFound -25,300
आइटम पाया नहीं जा सकता है। आईओएस 2.0 में और बाद में उपलब्ध।)

यहाँ पैदा करने के लिए मेरे कोड है SecKeyRef:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 
NSString *challenge = @"2KFqc46DNSWrizzv69lJN25o62xEYQw/QLcMiT2V1XLER9uJbOu+xH2qgTuNWa1HZ9SW3Lq+HovtkhFmjmf08QkVQohHmxCJXVyCgVhPBleScAgQ8AoP3tmV0RqGb2mJrb19ybeYP7uZ2piVtF4cRwU1gO3VTooCUK3cX4wS7Tc="; 
NSLog(@"challenge, %@", challenge); 

NSData *incomingData = [self base64DataFromString:challenge]; 
uint8_t *challengeBuffer = (uint8_t*)[incomingData bytes]; 
NSLog(@"challengeBuffer: %s", challengeBuffer); 

[self decryptWithPrivateKey:challengeBuffer]; 

free(challengeBuffer); 

return YES; 
} 

// Generate a SecKeyRef from the private key in the private.pem file. 
- (SecKeyRef)getPrivateKeyRef { 
NSString *startPrivateKey = @"-----BEGIN RSA PRIVATE KEY-----"; 
NSString *endPrivateKey = @"-----END RSA PRIVATE KEY-----"; 
NSString* path = [[NSBundle mainBundle] pathForResource:@"private" 
               ofType:@"pem"]; 
NSString* content = [NSString stringWithContentsOfFile:path 
               encoding:NSUTF8StringEncoding 
               error:NULL]; 
NSLog(@"Private Key: %@", content); 

NSString *privateKey; 
NSScanner *scanner = [NSScanner scannerWithString:content]; 
[scanner scanUpToString:startPrivateKey intoString:nil]; 
[scanner scanString:startPrivateKey intoString:nil]; 
[scanner scanUpToString:endPrivateKey intoString:&privateKey]; 

NSData *privateTag = [self dataWithBase64EncodedString:privateKey]; 
NSLog(@"Decoded String: %@", privateTag); 

OSStatus status = noErr; 
SecKeyRef privateKeyReference = NULL; 

NSMutableDictionary * queryPrivateKey = [[NSMutableDictionary alloc] init]; 

// Set the private key query dictionary. 
[queryPrivateKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass]; 
[queryPrivateKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; 
[queryPrivateKey setObject:privateTag forKey:(__bridge id)kSecAttrApplicationTag]; 
[queryPrivateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef]; 
//[queryPrivateKey setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnRef]; 


// Get the key. 
status = SecItemCopyMatching((__bridge CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKeyReference); 
NSLog(@"status: %ld", status); 

if(status != noErr) 
{ 
    privateKeyReference = NULL; 
} 

return privateKeyReference; 
} 

// Decrypt data 
- (void)decryptWithPrivateKey:(uint8_t *)cipherBuffer { 
OSStatus status = noErr; 

SecKeyRef privateKeyRef = [self getPrivateKeyRef]; 

size_t plainBufferSize = SecKeyGetBlockSize(privateKeyRef); 
uint8_t *plainBuffer = malloc(plainBufferSize); 

size_t cipherBufferSize = strlen((char *)cipherBuffer); 
NSLog(@"decryptWithPrivateKey: length of input: %lu", cipherBufferSize); 

// Error handling 
status = SecKeyDecrypt(privateKeyRef, 
         PADDING, 
         cipherBuffer, 
         cipherBufferSize, 
         &plainBuffer[0], 
         &plainBufferSize 
         ); 
NSLog(@"decryption result code: %ld (size: %lu)", status, plainBufferSize); 
NSLog(@"FINAL decrypted text: %s", plainBuffer); 
} 

मैं अब कुछ दिनों के लिए मेरे सिर तोड़ने किया गया है और मुझे लगा जैसे मैं यहाँ कुछ मदद मिल की जरूरत है। कोई भी कोई संकेतक? मैं क्रिप्टो डोमेन ज्ञान और समर्थन प्राप्त करने में अधिक समय व्यतीत कर सकता हूं जो आईओएस प्रदान करता है लेकिन मैं कोई भी आईओएस प्रोग्रामिंग नहीं करता हूं और यह एक बार बात है।

मुझे बस कुछ दिशा चाहिए और मैं इसे काम करने के लिए संघर्ष कर सकता हूं।

टीआईए।

+0

क्या आपने कभी यह काम किया है? वही मुद्दा। –

+0

मुझे अभी भी इसका सामना करना पड़ रहा है। क्या आपको यह काम मिल गया? –

+0

आप केवल उन चीज़ों को पुनर्प्राप्त करने के लिए 'SecItemCopyMatching' का उपयोग कर सकते हैं जिन्हें आपने पहले चाबी में जोड़ा था। जैसा कि आपने कुछ भी नहीं जोड़ा है, पुनः प्राप्त करने के लिए कुछ भी नहीं है। – orkoden

उत्तर

0

आपने अपनी निजी कुंजी और कुंजीपटल में प्रमाण पत्र स्टोर किया है। अन्यथा SecItemCopyMatching कुछ भी नहीं करेगा। आपको केवल इसे एक बार आयात करना होगा।

/* importing client identity (private key) */ 
NSData* certificateData = ... ; // decoded pkcs21 certificate from base64 pem 
NSString* passcode = @"passphrased used to encrypt the private key"; 
CFDictionaryRef optionsDictionary = (__bridge CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys: passcode, kSecImportExportPassphrase, nil]; 
CFArrayRef certificates; 
OSStatus error = SecPKCS12Import((__bridge CFDataRef) certificateData, optionsDictionary, &certificates); 
CFDictionaryRef myIDs = CFArrayGetValueAtIndex(certificates, 0); 

SecIdentityRef identity = (SecIdentityRef) CFDictionaryGetValue(myIDs, kSecImportItemIdentity); 

NSDictionary* clientCertificateQuery = @{(__bridge id)kSecValueRef  : identity, 
             (__bridge id)kSecAttrLabel  : @"some label you can use to find the item again with SecItemCopyMatching"}; 
OSStatus err = SecItemAdd((__bridge CFDictionaryRef) clientCertificateQuery, NULL); 

तो फिर तुम बाद में SecItemCopyMatching का उपयोग निजी कुंजी पाने के लिए पहचान और SecIdentityCopyPrivateKey प्राप्त करने के लिए कर सकते हैं। के रूप में आप निश्चित रूप से errSecDuplicateItem में चलेंगे

NSDictionary* clientCertificateQuery = @{(__bridge id)kSecMatchLimit : (__bridge id)kSecMatchLimitAll, 
             (__bridge id)kSecClass  : (__bridge id)kSecClassIdentity, 
             (__bridge id)kSecReturnRef : (__bridge id)kCFBooleanTrue}; 
SecIdentityRef identity = NULL; 
OSStatus errorCode = SecItemCopyMatching((__bridge CFDictionaryRef) clientCertificateQuery, &identity); 
SecKeyRef privateKeyRef; 
OSStatus err = SecIdentityCopyPrivateKey (identity, &privateKeyRef); 

हमेशा OSStatus त्रुटियों की जाँच करें।

ऐप्पल के Certificate, Key, and Trust Services Reference को पढ़ना सुनिश्चित करें।

+0

हाय @orkoden। उत्तर के लिए धन्यवाद, लेकिन मुझे स्ट्रिंग प्रारूप में चाबियाँ मिलीं।स्ट्रिंग को बेस 64 के साथ एन्कोड किया गया है और उसके बाद यह प्रारूप है: @ "- BEGIN आरएसए निजी कुंजी ----- MIICXAIBAAKBgQC0HPYiPItBtjJNky ...----- अंत आरएसए निजी कुंजी -"; मैं इस डेटा से pkcs21 डेटा कैसे उत्पन्न करूं? –

2

जब मैं जावा सर्वर और आईफोन एप्लिकेशन के साथ काम कर रहा था तब मुझे एक ही समस्या का सामना करना पड़ा और मेरा काम नीचे जैसा था।

  1. जावा सर्वर पर पी 12 उत्पन्न करें। [पासवर्ड को नोट करना याद रखें।]
  2. आधार 64 स्ट्रिंग में पी 12 फ़ाइल के कच्चे बाइट्स को कनवर्ट करें।
  3. आईओएस एप्लिकेशन में उन डेटा को भेजें चाहे आप चाहे कितना भी हों।

    3.1 आप टेक्स्ट 64 में बेस 64 डाल सकते हैं और उसे आईओएस भेज सकते हैं। [मेरे मामले में सबसे सुरक्षित तरीका और काम ठीक है।]

    3.2 आप उस स्ट्रिंग को भेजने के लिए JSON स्ट्रिंग का उपयोग कर सकते हैं। [यह आपके डेटा को दूषित कर सकता है।]

  4. एक बार जब आप आईफोन एप्लिकेशन पर डेटा प्राप्त करते हैं तो आधार 64 स्ट्रिंग को NSData में परिवर्तित करें। NSData+Base64
  5. अपनी निजी कुंजी के SecKeyRef प्राप्त करने के लिए निम्न विधि का उपयोग करें।

    - (SecKeyRef)getPrivateKeyFromData:(NSData *)p12Data withPassword:(NSString *)password { 
        NSMutableDictionary *options = [[NSMutableDictionary alloc] init]; 
        SecKeyRef privateKey = NULL; 
        [options setObject:password forKey:(__bridge id)kSecImportExportPassphrase]; 
        CFArrayRef items = NULL;// = CFArrayCreate(NULL, 0, 0, NULL); 
        OSStatus securityError = SecPKCS12Import((__bridge CFDataRef)p12Data, 
                  (__bridge CFDictionaryRef)options, &items); 
        if (securityError == noErr && CFArrayGetCount(items) > 0) { 
         CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0); 
         SecIdentityRef identityApp = 
         (SecIdentityRef)CFDictionaryGetValue(identityDict, 
                 kSecImportItemIdentity); 
         securityError = SecIdentityCopyPrivateKey(identityApp, &privateKey); 
        if (securityError != noErr) { 
          privateKey = NULL; 
         } 
        } 
        //NSLog(@"-------------------- Private Key Error %d",(int)securityError); 
        CFRelease(items); 
        options = nil; 
        p12Data = nil; 
        password = nil; 
        return privateKey; 
    } 
    

आशा इस मदद करता है !!!!!

+0

उत्तर @Pratik के लिए धन्यवाद, लेकिन मुझे स्ट्रिंग प्रारूप में चाबियाँ मिलीं। स्ट्रिंग को बेस 64 के साथ एन्कोड किया गया है और उसके बाद यह प्रारूप है: @ "- BEGIN आरएसए निजी कुंजी ----- MIICXAIBAAKBgQC0HPYiPItBtjJNky ...----- अंत आरएसए निजी कुंजी -"; मेरे पास पी 12 और उसका पासवर्ड नहीं है। –

+0

+1 @ प्रातिक। मैंने नमूना .p12 फ़ाइल और इसके कामकाजी ठीक के साथ अपने कोड की कोशिश की। –

+0

@ सौरभ शुक्ला मुझे किसी की मदद करने में खुशी है। क्षमा करें मैं पहले के प्रश्न का उत्तर देने में सक्षम नहीं था। –

6

दुर्भाग्यवश आईओएस पर सुरक्षा ढांचे की आवश्यकता है कि निजी कुंजी पीकेसीएस 12 प्रारूप में पासफ्रेज़ के साथ हो। सार्वजनिक कुंजी X509 बख्तरबंद डीईआर या पीकेसीएस 12 में हो सकती है, लेकिन निजी कुंजी को पीकेसीएस 12 होना आवश्यक है। आप जिस निजी कुंजी का उपयोग करने का प्रयास कर रहे हैं वह एक पीईएम-स्वरूपित आरएसए कुंजी है।

आप कुंजी की पहुंच है यदि यह openssl command line tools का उपयोग कर परिवर्तित किया जा सकता है:

openssl pkcs12 -export -nocerts -inkey privatekey.pem -out privatekey.p12

यह निजी कुंजी से एक PKCS12 फ़ाइल बनाने के लिए, और एक पदबंध की आवश्यकता है। यदि आपके पास निजी कुंजी का नियंत्रण नहीं है (उदाहरण के लिए, यदि यह किसी बाहरी स्रोत से सर्वर से आ रहा है), तो आप भाग्य से बाहर हैं।

लेकिन मान लीजिए कि आप पीकेसीएस 12 के लिए उस परेशानी पीईएम आरएसए निजी कुंजी को परिवर्तित करने के लिए ऊपर दिए गए कदमों को करने में सक्षम थे। PKCS12 डेटा से निजी कुंजी निकाला जा रहा है बहुत मुश्किल नहीं है:

  1. लोड PKCS12 NSData के रूप में। यदि आप फाइल सिस्टम पर संसाधन हैं तो आप dataWithContentsOfURL: का उपयोग कर ऐसा कर सकते हैं।
  2. पासफ्रेज़ के साथ पीकेसीएस 12 डेटा आयात करने के लिए SecPKCS12Import का उपयोग करें।
  3. आयातित वस्तुओं से SecIdentityRef निकालें।
  4. कॉपी SecIdentityRef

से निजी कुंजी ऐसा करने के लिए एक समारोह होगा:

OSStatus SecKeyPrivatePKCS12Import(CFDataRef keyData, CFStringRef passphrase, SecKeyRef *privateKey){ 
    OSStatus  status    = errSecSuccess; 
    CFDictionaryRef secImportOptions = NULL; 
    CFArrayRef  secImportItems  = NULL; 

    if ((keyData != NULL) && (CFStringGetLength(passphrase) > 0)){ 
     const void *keys[] = { kSecImportExportPassphrase }; 
     const void *values[] = { passphrase }; 

     secImportOptions = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL); 

     status = SecPKCS12Import((CFDataRef) keyData, (CFDictionaryRef)secImportOptions, &secImportItems); 
     if (CFArrayGetCount(secImportItems) > 0){ 
      CFDictionaryRef identityDict = CFArrayGetValueAtIndex(secImportItems, 0); 
      SecIdentityRef identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity); 
      SecIdentityCopyPrivateKey(identityApp, privateKey); 
     } 
    } 

    return status; 
} 

ऑब्जेक्टिव-सी से यह कॉलिंग लगेगा जैसे:

OSStatus status = errSecSuccess; 

status = SecKeyPrivatePKCS12Import((_bridge CFDataRef)data, (_bridge CFStringRef)passphrase, &privateKey); 
if (privateKey == NULL){ 
    // Check the status value for why it failed 
} 

कि मान लिया जाये "डेटा" NSData का एक उदाहरण है जिसमें PKCS12 डेटा है, और "पासफ्रेज़" एक NSString उदाहरण represe है पासफ्रेज nting। सफलता पर "PrivateKey" PKCS12 डेटा से आयात की गई निजी कुंजी के साथ आबादी है।

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