2013-07-19 26 views
0

我遵循了蘋果開發者文檔,特別是顯示如何生成密鑰對的示例,使用公鑰進行加密並使用私鑰進行解密。在本指南中有三個示例方法(第19頁起here)。ios keychain中的公鑰更改得到

我抄了這三種方法粘貼到我的項目,只有改變它們是公共類的方法,添加記錄並迷上了按鈕來調用它們的加密輸出送入解密:

在視圖 - 控制:

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

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

三個方法的代碼是:

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

我一直在嘗試許多不同的指南和閱讀,大量鄰f這裏的帖子試圖讓這個工作。我也試過Apples KeyChainWrapperItem來存儲和檢索沒有運氣的鍵。我還在這裏發現了一篇文章,描述並顯示了以數據格式獲取密鑰的確切代碼,但由於某種原因返回nil。

我所做的就是用馬特加拉格爾的NSData的+ Base64編碼類打印的加密字符串,可以直觀地看到該字符串是非常不同的每個通過,即使我不會產生與此代碼一個新的關鍵的最後一件事:

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

僅供參考目前,我目前只在模擬器上運行,如果這是重要的。我重置它以在每一代之前清除鑰匙串。

任何人都可以幫我理解嗎?

回答

2

錯誤中提供的代碼

+ (NSData *)encryptWithPublicKey,這條線將剝離加密的數據(並摧毀它)

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

它應該是

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

不同的結果lt每次

每次看到不同的結果都不是錯誤。 PKCS#1加密算法使用一些隨機種子來使密文每次都不同。這稱爲填充並防止多次攻擊,例如頻率分析和密文匹配。看到這篇維基百科文章部分:http://en.wikipedia.org/wiki/RSA_(algorithm)#Padding_schemes