0

私はアップルの開発者ドキュメント、特にキーペアを生成し、公開キーで暗号化し、秘密キーで復号化する方法を示す例に従いました。このためのガイドには、3 つのメソッドの例があります (19 ページ以降はこちら)。

これら 3 つのメソッドをコピーして自分のプロジェクトに貼り付けました。それらをパブリック クラス メソッドに変更するだけで、ログを追加し、それらを呼び出して暗号化の出力を復号化にフィードするためのボタンを接続しました。

ビューコントローラーで:

-(IBAction)generateKey:(UIButton*)sender
{
    [CryptoClass generateKeyPairPlease];
}

-(IBAction)encryptAndDecrypt
{
    NSData *data = [CryptoClass encryptWithPublicKey]; 
    [CryptoClass decryptWithPrivateKey:data];
}

3 つのメソッドのコードは次のとおりです。

static const UInt8 publicKeyIdentifier[] = "com.apple.sample.publickey\0";
static const UInt8 privateKeyIdentifier[] = "com.apple.sample.privatekey\0";

+ (NSData *)encryptWithPublicKey
{
    OSStatus status = noErr;

    size_t cipherBufferSize;
    uint8_t *cipherBuffer;                     // 1

    // [cipherBufferSize]
    const uint8_t dataToEncrypt[] = "the quick brown fox jumps "
    "over the lazy dog\0"; // 2
    size_t dataLength = sizeof(dataToEncrypt)/sizeof(dataToEncrypt[0]);

    SecKeyRef publicKey = NULL;                                 // 3

    NSData * publicTag = [NSData dataWithBytes:publicKeyIdentifier
                                        length:strlen((const char *)publicKeyIdentifier)]; // 4

    NSMutableDictionary *queryPublicKey =
    [[NSMutableDictionary alloc] init]; // 5

    [queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
    [queryPublicKey setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
    [queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    [queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
    // 6

    status = SecItemCopyMatching
    ((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKey); // 7

    //  Allocate a buffer

    cipherBufferSize = SecKeyGetBlockSize(publicKey);
    cipherBuffer = malloc(cipherBufferSize);

    //  Error handling

    if (cipherBufferSize < sizeof(dataToEncrypt)) {
        // Ordinarily, you would split the data up into blocks
        // equal to cipherBufferSize, with the last block being
        // shorter. For simplicity, this example assumes that
        // the data is short enough to fit.
        printf("Could not decrypt.  Packet too large.\n");
        return NULL;
    }

    // Encrypt using the public.
    status = SecKeyEncrypt(    publicKey,
                           kSecPaddingPKCS1,
                           dataToEncrypt,
                           (size_t) dataLength,
                           cipherBuffer,
                           &cipherBufferSize
                           );                              // 8

    //  Error handling
    //  Store or transmit the encrypted text

    if (publicKey) CFRelease(publicKey);

    NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:dataLength];

    free(cipherBuffer);

    return encryptedData;
}


+ (void)generateKeyPairPlease
{
    OSStatus status = noErr;
    NSMutableDictionary *privateKeyAttr = [[NSMutableDictionary alloc] init];
    NSMutableDictionary *publicKeyAttr = [[NSMutableDictionary alloc] init];
    NSMutableDictionary *keyPairAttr = [[NSMutableDictionary alloc] init];
    // 2

    NSData * publicTag = [NSData dataWithBytes:publicKeyIdentifier
                                        length:strlen((const char *)publicKeyIdentifier)];
    NSData * privateTag = [NSData dataWithBytes:privateKeyIdentifier
                                         length:strlen((const char *)privateKeyIdentifier)];
    // 3

    SecKeyRef publicKey = NULL;
    SecKeyRef privateKey = NULL;                                // 4

    [keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA
                    forKey:(__bridge id)kSecAttrKeyType]; // 5
    [keyPairAttr setObject:[NSNumber numberWithInt:1024]
                    forKey:(__bridge id)kSecAttrKeySizeInBits]; // 6

    [privateKeyAttr setObject:[NSNumber numberWithBool:YES]
                       forKey:(__bridge id)kSecAttrIsPermanent]; // 7
    [privateKeyAttr setObject:privateTag
                       forKey:(__bridge id)kSecAttrApplicationTag]; // 8

    [publicKeyAttr setObject:[NSNumber numberWithBool:YES]
                      forKey:(__bridge id)kSecAttrIsPermanent]; // 9
    [publicKeyAttr setObject:publicTag
                      forKey:(__bridge id)kSecAttrApplicationTag]; // 10

    [keyPairAttr setObject:privateKeyAttr
                    forKey:(__bridge id)kSecPrivateKeyAttrs]; // 11
    [keyPairAttr setObject:publicKeyAttr
                    forKey:(__bridge id)kSecPublicKeyAttrs]; // 12

    status = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr,
                                &publicKey, &privateKey); // 13
    //    error handling...


    if(publicKey) CFRelease(publicKey);
    if(privateKey) CFRelease(privateKey);                       // 14
}

+ (void)decryptWithPrivateKey: (NSData *)dataToDecrypt
{
    OSStatus status = noErr;

    size_t cipherBufferSize = [dataToDecrypt length];
    uint8_t *cipherBuffer = (uint8_t *)[dataToDecrypt bytes];

    size_t plainBufferSize;
    uint8_t *plainBuffer;

    SecKeyRef privateKey = NULL;

    NSData * privateTag = [NSData dataWithBytes:privateKeyIdentifier
                                         length:strlen((const char *)privateKeyIdentifier)];

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

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

    status = SecItemCopyMatching
    ((__bridge CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKey); // 2

    //  Allocate the buffer
    plainBufferSize = SecKeyGetBlockSize(privateKey);
    plainBuffer = malloc(plainBufferSize);

    if (plainBufferSize < cipherBufferSize) {
        // Ordinarily, you would split the data up into blocks
        // equal to plainBufferSize, with the last block being
        // shorter. For simplicity, this example assumes that
        // the data is short enough to fit.
        printf("Could not decrypt.  Packet too large.\n");
        return;
    }

    //  Error handling

    status = SecKeyDecrypt(    privateKey,
                           kSecPaddingPKCS1,
                           cipherBuffer,
                           cipherBufferSize,
                           plainBuffer,
                           &plainBufferSize
                           );                              // 3

    //  Error handling
    //  Store or display the decrypted text
    NSLog(@"Plain: %@",[NSString stringWithUTF8String:(const char *)plainBuffer]);
    if(privateKey) CFRelease(privateKey);
}

私はさまざまなガイドを試しており、これを機能させるためにここで多くの投稿を読んでいます。また、Apples KeyChainWrapperItem を試して、キーを保存および取得しましたが、うまくいきませんでした。また、データ形式でキーを取得するための正確なコードを説明および表示する投稿を見つけましたが、何らかの理由で nil を返します。

私が最後に行ったことは、Matt Gallagher の NSData+Base64 カテゴリを使用して暗号化された文字列を出力することでした。このコードで新しいキーを生成しなくても、パスごとに文字列が大幅に異なることが視覚的にわかります。

-(IBAction)encryptAndDecrypt
{
    NSData *data = [CryptoClass encryptWithPublicKey]; 
    NSLog(@"String: %@", [data base64EncodedString]); // Print encrypted data as base64
    [CryptoClass decryptWithPrivateKey:data];
}

参考までに、それが重要な場合、私は現在シミュレータでのみ実行しています。そして、各世代の前にキーチェーンをクリアするためにリセットしました。

誰でもこれを理解するのを手伝ってもらえますか?

4

1 に答える 1

2

提供されたコードのエラー

では+ (NSData *)encryptWithPublicKey、この行は暗号化されたデータを削除 (および破棄) します。

NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:dataLength];

そのはず

NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:cipherBufferSize];

毎回違う結果

毎回異なる結果が表示されてもエラーではありません。PKCS#1 暗号化アルゴリズムは、ランダム シードを使用して毎回異なる暗号文を作成します。これはパディングと呼ばれ、頻度分析や暗号文照合などのいくつかの攻撃から保護します。このウィキペディアの記事セクションを参照してください: http://en.wikipedia.org/wiki/RSA_(algorithm)#Padding_schemes

于 2013-08-17T14:13:33.100 に答える