2013-10-31 16 views
10

私はObjective C & iOSプログラミングを初めて学びました。目的C:PEM秘密鍵からSecKeyRefを取得できません

私は、サーバーとクライアントの間で交換する必要があるデータを暗号化して解読するためにopensslを使用して生成された単純な公開鍵/秘密鍵(PEM形式)を使用しています。私はこれをJavaサーバー&クライアントで正常に動作させています。

Javaで公開鍵を使用してデータを暗号化し、Objective C/iOSで秘密鍵を使用して暗号化を解除したときに問題が発生しました。私はいくつかの例を見ていくつかのコードをまとめましたが、秘密鍵からSecKeyRefを作成する際にSecItemCopyMatchingを常に呼び出すと-25300というエラーが発生します。

ここには証明書が含まれておらず、単なる一般的なキーです。 ここに私がやっていることがあります:

  1. PEM秘密鍵とBase64デコードを読んでください。
  2. SecItemCopyMatchingを使用して、復号化された文字列からSecKeyRefを生成します。
  3. SecKeyDecryptを使用して復号化します。

私の問題は、-25300のステータスを返し、ステップ#2である(errSecItemNotFound -25300
項目は、iOS 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); 
} 

私は今、数日間、私の頭を壊してきたと私はここにいくつかの助けを得る必要があるように私は感じました。いずれかの任意のポインタ? iOSが提供するCryptoドメインの知識とサポートを得るのに多くの時間を費やすことができましたが、iOSプログラミングを一切やっていない、これは一度だけのことです。

私はちょうどある方向性が必要で、私はそれを機能させるために苦労することができます。

TIA。

+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); 

次に、あなたは後で秘密鍵を取得するために、アイデンティティとSecIdentityCopyPrivateKeyを取得するためにSecItemCopyMatchingを使用することができます。

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

確実にerrSecDuplicateItemを実行するため、OSStatusエラーをチェックしてください。

アップルのCertificate, Key, and Trust Services Referenceを必ずお読みください。

+0

こんにちは@orkoden。答えをありがとう、しかし私は文字列形式のキーを持っています。文字列はbase64でエンコードされ、この形式になります。@ " - BEGIN RSA PRIVATE KEY ----- MIICXAIBAAKBgQC0HPYiPItBtjJNky ...-- RSAプライベートキー終了 - ";このデータからpkcs21データをどのように生成しますか? –

2

私はjavaサーバーとiPhoneアプリケーションで作業していたときに同じ問題に直面しました。私の回避策は次のとおりです。

  1. Javaサーバーでp12を生成します。 [パスワードを書き留めておいてください]
  2. p12ファイルの生のバイトを64バイトの文字列に変換します。
  3. どのようにしても、iOSアプリケーションにそれらのデータを送信します。

    3.1ベース64をテキストファイルに入れてiOSに送ることができます。 [私の場合、安全な方法と正常に動作します。]

    3.2 JSON文字列を使用してその文字列を送信できます。 [これによりデータが破損する可能性があります。]

  4. iPhoneアプリケーションでデータを取得すると、ベース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ありがとうが、私は文字列形式のキーを持っています。文字列はbase64でエンコードされ、この形式になります。@ " - BEGIN RSA PRIVATE KEY ----- MIICXAIBAAKBgQC0HPYiPItBtjJNky ...-- RSAプライベートキー終了 - ";私はp12とそのパスワードを持っていません。 –

+0

+1 @Pratik。私はあなたのコードをサンプル.p12ファイルとそのうまく動作しています。 –

+0

@SaurabhShukla誰かを助けてうれしいです。申し訳ありませんが、以前の質問に返信することができませんでした。 –

6

残念ながら、iOSのセキュリティフレームワークでは、秘密鍵がパスフレーズ付きのPKCS12形式である必要があります。公開鍵はX509装甲DERまたはPKCS12に入れることができますが、秘密鍵はPKCS12である必要があります。使用しようとしているプラ​​イベートキーは、PEM形式のRSAキーです。

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

これは、秘密鍵でPKCS12ファイルを作成し、パスフレーズが必要です:あなたは、キーへのアクセス権を持っている場合は

openssl command line tools使用して変換することができます。秘密鍵を制御できない場合(たとえば、サーバーなどの外部ソースからのものなど)、運が悪いです。

しかし、上記の手順を実行して、問題のあるPEM RSA秘密鍵をPKCS12に変換できたとします。 PKCS12データから秘密鍵を抽出 はあまりにも難しいことではありません。

  1. ロードPKCS12 NSDataとして。もしこれがファイルシステム上のリソースであればdataWithContentsOfURL:を使ってこれを行うことができます。
  2. SecPKCS12Importを使用して、パスフレーズでPKCS12データをインポートします。
  3. インポートしたアイテムからSecIdentityRefを抽出します。
  4. コピーSecIdentityRef

から秘密鍵は、そのようにするための機能は、次のようになりますと仮定すると

OSStatus status = errSecSuccess; 

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

:Objective-Cのからそれを呼び出す

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

は次のようになります"data"はPKCS12データを含むNSDataのインスタンスであり、 "passphrase"はNSStringインスタンスrepreseですパスフレーズを入力してください。成功すると、「privateKey」にPKCS12データからインポートされた秘密鍵が設定されます。

関連する問題