2012-10-28 14 views
26

リクエストをバックエンドサーバーに送信する前に署名する必要があります。しかし秘密鍵は私に与えられます。だから私はそれをインポートし、署名にそれを使用する必要があります。私はインポートとサインインができますが、そのデータはopensslを使って署名したものとは異なります。私はそれが間違っていることを知っています。なぜなら私は公開鍵をインポートするときにそれを検証することができないからです。キーチェーンにインポートすることを避ける方法がある場合は、それも素晴らしいでしょう。 これを数日間頑張ってきましたが、これは私たちのための大事な作業です。いくらか助けてもらえますか? iphoneで秘密鍵をKeychainにインポートすると、正しく動作しない

- (SecKeyRef) getPrivateKey { 
//RSA KEY BELOW IS DUMMY. 

key = @"-----BEGIN RSA PRIVATE KEY-----\nORtMei3ImKI2ZKI636I4+uNCwFfZv9pyJzXyfr1ZNo7iaiW7A0NjLxikNxrWpr/M\n6HD8B2j/CSjRPW3bhsgDXAx/AI1aSfJFxazjiTxx2Lk2Ke3jbhE=\n-----END RSA PRIVATE KEY-----\n"; 

NSString * tag = @"adpPrivateKey"; 

    NSString *s_key = [NSString string]; 
    NSArray *a_key = [key componentsSeparatedByString:@"\n"]; 
    BOOL  f_key = FALSE; 

    for (NSString *a_line in a_key) { 
     if ([a_line isEqualToString:@"-----BEGIN RSA PRIVATE KEY-----"]) { 
      f_key = TRUE; 
     } 
     else if ([a_line isEqualToString:@"-----END RSA PRIVATE KEY-----"]) { 
      f_key = FALSE; 
     } 
     else if (f_key) { 
      s_key = [s_key stringByAppendingString:a_line]; 
     } 
    } 
    if (s_key.length == 0) return(nil); 

    // This will be base64 encoded, decode it. 
    NSData *d_key = [NSData dataFromBase64String:s_key]; 

if(d_key == nil) return nil; 

    NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]]; 

    // Delete any old lingering key with the same tag 
    NSMutableDictionary *privateKey = [[NSMutableDictionary alloc] init]; 
    [privateKey setObject:(id) kSecClassKey forKey:(id)kSecClass]; 
    [privateKey setObject:(id) kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType]; 
    [privateKey setObject:d_tag forKey:(id)kSecAttrApplicationTag]; 
    SecItemDelete((CFDictionaryRef)privateKey); 

    CFTypeRef persistKey = nil; 

    // Add persistent version of the key to system keychain 
    [privateKey setObject:d_key forKey:(id)kSecValueData]; 
    [privateKey setObject:(id) kSecAttrKeyClassPrivate forKey:(id) 
    kSecAttrKeyClass]; 
    [privateKey setObject:[NSNumber numberWithBool:YES] forKey:(id) 
    kSecReturnPersistentRef]; 

    OSStatus secStatus = SecItemAdd((CFDictionaryRef)privateKey, &persistKey); 
    if (persistKey != nil) CFRelease(persistKey); 

    if ((secStatus != noErr) && (secStatus != errSecDuplicateItem)) { 
     [privateKey release]; 
     return(nil); 
    } 

    // Now fetch the SecKeyRef version of the key 
    SecKeyRef keyRef = nil; 

    [privateKey removeObjectForKey:(id)kSecValueData]; 
    [privateKey removeObjectForKey:(id)kSecReturnPersistentRef]; 
    [privateKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef 
    ]; 
    [privateKey setObject:(id) kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType]; 
    secStatus = SecItemCopyMatching((CFDictionaryRef)privateKey, 
            (CFTypeRef *)&keyRef); 

    if(secStatus != noErr) 
     return nil; 

    [privateKey release]; 

    return keyRef; 
} 

以下のコードは、署名に使用されます。コードの一部は、私は、公開鍵をインポートして確認し、その失敗するhttp://blog.flirble.org/2011/01/05/rsa-public-key-openssl-ios/のコードサンプルを使用したアップル例(http://developer.apple.com/library/ios/#samplecode/CryptoExercise/Listings/Classes_SecKeyWrapper_m.html#//apple_ref/doc/uid/DTS40008019-Classes_SecKeyWrapper_m-DontLinkElementID_17

- (NSData *)getSignatureBytes:(NSString *)plainText { 

OSStatus sanityCheck = noErr; 
NSData * signedHash = nil; 
uint8_t * signedHashBytes = NULL; 
size_t signedHashBytesSize = 0; 
SecKeyRef privateKey = NULL; 

privateKey = [self getPrivateKey]; 

signedHashBytesSize = SecKeyGetBlockSize(privateKey); 

//Create a SHA Encoded 
NSString * shaEncoded = [self sha256:plainText]; 
NSLog(@"%@", shaEncoded); 


// Malloc a buffer to hold signature. 

signedHashBytes = malloc(signedHashBytesSize * sizeof(uint8_t)); 
memset((void *)signedHashBytes, 0x0, signedHashBytesSize); 


NSData *inputData = [self getHashBytes:[plainText dataUsingEncoding:NSUTF8StringEncoding]]; 
int bytesLengthUINT8 = [inputData length]; 

sanityCheck = SecKeyRawSign (privateKey, kSecPaddingPKCS1, (const uint8_t *)inputData, CC_SHA256_DIGEST_LENGTH,(uint8_t *)signedHashBytes, &signedHashBytesSize); 


if(sanityCheck != noErr) 
    return nil; 


signedHash = [NSData dataWithBytes:(const void *)signedHashBytes length:(NSUInteger)signedHashBytesSize];  
NSString *string = [signedHash base64EncodedString]; 

NSLog(@"%@", string); 


if (signedHashBytes) free(signedHashBytes); 
return signedHash; 

} 

からです。

+0

'kSecPaddingPKCS1'の値は何ですか?公開鍵と秘密鍵のモジュラスを試してみてください。 –

+0

こんにちは@私は何をすべきかについて詳しく教えてもらえますか?また、秘密鍵を保存して検索する方法で問題が発生していますか?私が使用できる他のライブラリがあるかどうか教えてください。 –

+0

申し訳ありませんが、私はiosの専門家ではありません。私は今、暗号についてかなりのことをしているので、私はあなたにいくつかの一般的な勧告を与えると思った。例えば。 'kSecPaddingPKCS1'はハッシュを指定せず、SHA-1がデフォルトである可能性があります。秘密鍵と公開鍵の係数が一致しない場合、それらは同じ鍵ペアに属しません。どちらの場合も、署名検証は失敗します。 –

答えて

1

キーチェーンにすべてのキーを格納する代わりに、キーチェーンに単純な文字列(secret_hashとして)を格納するだけで済みます。また、広く普及している一般的なAFNetworkingライブラリを使用して、バックエンドWebサービスへの安全な呼び出しを行います。

秘密鍵を使用してバックエンドサービスへのリクエストに署名する必要がある場合は、(a)サービス呼び出し(AFNetworking)のための堅牢なラッパーライブラリを使用し、(b)アプリケーションにアクセスできる場所にある.pfxファイル(私はプロジェクトのルートに.pfxファイルを残しておきます)

AFHTTPClientの独自のサブクラスを作成し、サブクラスを使用してチャレンジブロックを設定したAFHTTPRequestOperationsを作成します.pfxファイルから抽出した資格情報を使用します。

このようにして、AFHTTPRequestOperationを直接作成するのではなく、AFHTTPClientサブクラスのMySignedAFHTTPRequestOperationメソッドを使用して直接作成します。この方法は、あなたが作成した後

OSStatus myIdentityAndTrustExtractionHelper(CFDataRef inPKCS12Data,   
           SecIdentityRef *mySecIdentityRef, 
           SecTrustRef *myTrustRef) 
{ 
    //modify to get secret-hash from keychain 
    CFStringRef mySecretHash = CFSTR(secret_hash); 
    const void *keys[] = { kSecImportExportPassphrase }; 
    const void *values[] = { mySecretHash }; 


    CFArrayRef pkscItems = CFArrayCreate(NULL, 0, 0, NULL); 
    OSStatus mySecurityError = SecPKCS12Import(inPKCS12Data, 
           CFDictionaryCreate(NULL,keys, values, 1, 
           NULL, NULL), 
           &pkscItems); 
    if (mySecurityError == 0) 
    {         
     CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (pkscItems, 0); 
     const void *tempIdentity = NULL; 
     tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, 
              kSecImportItemIdentity); 
     *mySecIdentityRef = (SecIdentityRef)tempIdentity; 
     const void *tempTrust = NULL; 
     tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust); 
     *myTrustRef = (SecTrustRef)tempTrust; 
    } 

    return mySecurityError; 
} 

...ここ

[myOperationObject setAuthenticationChallengeBlock:^(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge) 
    { 
      NSString * pfxPath = [[NSBundle mainBundle] 
          pathForResource:@“pvtKeyFile” ofType:@"pfx"]; 

      NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile: pfxPath]; 
      CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;  
      SecIdentityRef identity; 
      SecTrustRef trust; 
      myIdentityAndTrustExtractionHelper(inPKCS12Data, &identity, &trust); 

      SecCertificateRef certificate = NULL; 
      SecIdentityCopyCertificate (identity, &certificate); 

      const void *certs[] = {certificate}; 
      CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL); 

      NSURLCredential *credential = [NSURLCredential 
              credentialWithIdentity:identity 
              certificates:(__bridge NSArray*)certArray 
              persistence:NSURLCredentialPersistencePermanent]; 

      [[challenge sender] useCredential:credential 
       forAuthenticationChallenge:challenge]; 
      CFRelease(certArray); 
    } 

は、上記の使用アイデンティティ抽出ヘルパー関数にいくつかの詳細です... AFHTTPRequestOperationを作成し、このような課題のブロックを設定する必要がありますAFHTTPRequest(つまり、AFHTTPClientサブクラスのMySignedAFHTTPRequestOperationメソッドを介して)、実行のためにNSOperationsQueueに追加します(もちろん、操作を作成するときに成功と失敗のハンドラブロックを適切に設定する必要があります)

  • は、あなたのWebサービスが
  • ストアアプリで.pfxファイルとして証明書の秘密鍵を呼び出しを行うために堅牢なAFNetworkingフレームワークを使用して
  • がAFNetworkingを許可する証明書とキーを作成するためにそれを使用します。要するに作成した各操作オブジェクト内の資格情報を設定して、暗号化を実行します。

これが役に立ちます。

+0

秘密鍵をパスワードのないプレーンファイルに格納するのは悪い考えです。それを(モバイル)アプリケーションでファイルとして配布することを提案すると、それが騙されたセキュリティ上の目的を破っているようです。 KeyChainは機密データを格納するためのものであり、使用する必要があります。 –

+0

ポイントを獲得しました。私の解決策は、バックエンドサービスの呼び出しとそのフレームワークへの暗号化(AFNetworking)に焦点を絞っています。キー自体ではなく、キーチェーンのキーのパスフレーズを保存することで、上記のソリューションを更新しました。 – CoolDocMan

+0

キーチェーンは、キーのような機密情報を保存するのに適しています。また、あなたの提案がどのようにポスターを助けるのかは明確ではありません。 –

3

ための受け入れ答えの最後の方法を見てみましょう:Converting NSData to SecKeyRef

問題は、iOSが若干異なる公開鍵と秘密鍵を扱うことです通常存在し、他のセキュリティAPIにより期待されている識別ヘッダ(中Javaなど)は、iOSでは期待されていません。だからあなたはそれらを取り除かなければならない。

0

標準のPHP互換のbase64文字列形式のAES-256 RSA PEMをシステムキーチェーンに保存したいのであれば、これは私にとっては役に立ちます。

たくさんの場所があるので、私はこれを投稿しています.PEMファイルをiOSに直接貼り付けることはできません。それ以外の場合はヘッダーを取り除かなければなりません。しかし、少なくともiOS 9.3では、これは現在動作しています。もし私がこの場所を見たなら、それは私に多くの時間を節約していました。 (注:以下は、のObjective-C-RSAからhttps://github.com/ideawu/Objective-C-RSAの部分の大幅に変更されたバージョンです。該当するライセンスを参照してください、私は裏書を意味しません。多くの人にとって問題です)。

#define BR (__bridge id) 
#define BRD (__bridge CFDictionaryRef) 

+ (SecKeyRef)storePrivateKey:(NSString *)key inSystemKeychainWithTag:(NSString *)tag { 
    NSRange spos; 
    NSRange epos; 
    spos = [key rangeOfString:@"-----BEGIN RSA PRIVATE KEY-----"]; 
    if(spos.length > 0) { 
     epos = [key rangeOfString:@"-----END RSA PRIVATE KEY-----"]; 
    } 
    else { 
     spos = [key rangeOfString:@"-----BEGIN PRIVATE KEY-----"]; 
     epos = [key rangeOfString:@"-----END PRIVATE KEY-----"]; 
    } 
    if(spos.location != NSNotFound && epos.location != NSNotFound){ 
     NSUInteger s = spos.location + spos.length; 
     NSUInteger e = epos.location; 
     NSRange range = NSMakeRange(s, e-s); 
     key = [key substringWithRange:range]; 
    } 
    key = [key stringByReplacingOccurrencesOfString:@"\r" withString:@""]; 
    key = [key stringByReplacingOccurrencesOfString:@"\n" withString:@""]; 
    key = [key stringByReplacingOccurrencesOfString:@"\t" withString:@""]; 
    key = [key stringByReplacingOccurrencesOfString:@" " withString:@""]; 

    // This will be base64 encoded, decode it. 
    NSData *data = [[NSData alloc] initWithBase64EncodedString:key options:0]; 

    if(data == nil){ 
     return nil; 
    } 

    //a tag to read/write keychain storage 
    NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]]; 

    // Delete any old lingering key with the same tag 
    NSMutableDictionary *options = [ 
    @{ 
     BR kSecClass: BR kSecClassKey, 
     BR kSecAttrKeyType: BR kSecAttrKeyTypeRSA, 
     BR kSecAttrApplicationTag: d_tag, 
    } 
    mutableCopy]; 

    SecItemDelete(BRD options); 

    // Add persistent version of the key to system keychain 
    [options addEntriesFromDictionary: 
    @{ 
     BR kSecValueData:data, 
     BR kSecAttrKeyClass: BR kSecAttrKeyClassPrivate, 
     BR kSecReturnPersistentRef: @YES, 
    }]; 

    CFTypeRef persistKey = nil; 
    OSStatus status = SecItemAdd(BRD options, &persistKey); 
    if (persistKey != nil){ 
     CFRelease(persistKey); 
    } 
    if ((status != noErr) && (status != errSecDuplicateItem)) { 
     return nil; 
    } 

    [options removeObjectForKey:BR kSecValueData]; 
    [options removeObjectForKey:BR kSecReturnPersistentRef]; 

    [options addEntriesFromDictionary: 
    @{ 
     BR kSecReturnRef:@YES, 
     BR kSecAttrKeyType:BR kSecAttrKeyTypeRSA, 
    }]; 

    // Now fetch the SecKeyRef version of the key 
    SecKeyRef keyRef = nil; 
    status = SecItemCopyMatching(BRD options, (CFTypeRef *)&keyRef); 
    if(status != noErr){ 
     return nil; 
    } 
    return keyRef; 
} 
関連する問題