ios - 将 NSData 转换为 SecKeyRef

标签 ios encryption rsa nsdata public-key-encryption

我有一个从远程服务器收集的公钥,我想使用该公钥执行 RSA 加密。但问题是我将公钥数据作为缓冲区中的字节数组获取。我可以将它转换为 NSData 但我不能转换为 SecKeyRef 所以我可以继续加密。我的加密代码是这样的:

+(NSString *)encryptRSA:(NSString *)plainTextString withKey:(SecKeyRef)publicKey {
size_t cipherBufferSize = SecKeyGetBlockSize(publicKey);
uint8_t *cipherBuffer = malloc(cipherBufferSize);
uint8_t *nonce = (uint8_t *)[plainTextString UTF8String];
SecKeyEncrypt(publicKey,
              kSecPaddingOAEP,
              nonce,
              strlen( (char*)nonce ),
              &cipherBuffer[0],
              &cipherBufferSize);
NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:cipherBufferSize];
return [encryptedData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];

如您所见,我需要 SecKeyRef 对象类型来完成我的加密。但是我的 RSA 公钥在 NSData 变量中。那么如何将 NSData 转换为 SecKeyRef 对象类型。提前致谢。

最佳答案

使用这个函数来保存你的公钥。传递您的 RAS 公钥和 peername 的任何名称。

- (void)addPeerPublicKey:(NSString *)peerName keyBits:(NSData *)publicKeyData {

        OSStatus sanityCheck = noErr;
        CFTypeRef persistPeer = NULL;
        [self removePeerPublicKey:peerName];

        NSData * peerTag = [[NSData alloc] initWithBytes:(const void *)[peerName UTF8String] length:[peerName length]];
        NSMutableDictionary * peerPublicKeyAttr = [[NSMutableDictionary alloc] init];
        [peerPublicKeyAttr setObject:(id)kSecClassKey forKey:(id)kSecClass];
        [peerPublicKeyAttr setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
        [peerPublicKeyAttr setObject:peerTag forKey:(id)kSecAttrApplicationTag];
        [peerPublicKeyAttr setObject:publicKeyData forKey:(id)kSecValueData];
        [peerPublicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnData];
        sanityCheck = SecItemAdd((CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef *)&persistPeer);

        if(sanityCheck == errSecDuplicateItem){
            TRC_DBG(@"Problem adding the peer public key to the keychain, OSStatus == %ld.", sanityCheck );
        }

        TRC_DBG(@"SecItemAdd OSStATUS = %ld", sanityCheck);

//        TRC_DBG(@"PersistPeer privatekey data after import into keychain %@", persistPeer);
        persistPeer = NULL;
        [peerPublicKeyAttr removeObjectForKey:(id)kSecValueData];
        sanityCheck = SecItemCopyMatching((CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef*)&persistPeer);

        TRC_DBG(@"SecItemCopying OSStATUS = %ld", sanityCheck);
//        TRC_DBG(@"SecItem copy matching returned this public key data %@", persistPeer);
        // The nice thing about persistent references is that you can write their value out to disk and
        // then use them later. I don't do that here but it certainly can make sense for other situations
        // where you don't want to have to keep building up dictionaries of attributes to get a reference.
        //
        // Also take a look at SecKeyWrapper's methods (CFTypeRef)getPersistentKeyRefWithKeyRef:(SecKeyRef)key
        // & (SecKeyRef)getKeyRefWithPersistentKeyRef:(CFTypeRef)persistentRef.
        [peerTag release];
        [peerPublicKeyAttr release];
        if (persistPeer) CFRelease(persistPeer);
    }

这是检索公钥 ref 的函数。传递用于保存的相同名称。

-(SecKeyRef)getPublicKeyReference:(NSString*)peerName{

       OSStatus sanityCheck = noErr;

       SecKeyRef pubKeyRefData = NULL;
       NSData * peerTag = [[NSData alloc] initWithBytes:(const void *)[peerName UTF8String] length:[peerName length]];
       NSMutableDictionary * peerPublicKeyAttr = [[NSMutableDictionary alloc] init];

       [peerPublicKeyAttr setObject:(id)kSecClassKey forKey:(id)kSecClass];
       [peerPublicKeyAttr setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
       [peerPublicKeyAttr setObject:peerTag forKey:(id)kSecAttrApplicationTag];
       [peerPublicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:       (id)kSecReturnRef];
       sanityCheck = SecItemCopyMatching((CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef*)&pubKeyRefData);
       [peerTag release];
       [peerPublicKeyAttr release];

       TRC_DBG(@"SecItemCopying OSStATUS = %ld", sanityCheck);
       if(pubKeyRefData){
           TRC_DBG(@"SecItem copy matching returned this publickeyref  %@", pubKeyRefData);
           return pubKeyRefData;
       }else{
           TRC_DBG(@"pubKeyRef is NULL");
           return nil;
       }
   }

在 addPeerPublicKey 之前将您的公钥数据传递给此函数

- (NSData *)stripPublicKeyHeader:(NSData *)d_key
{
    // Skip ASN.1 public key header
    if (d_key == nil) return(nil);

    unsigned int len = [d_key length];
    if (!len) return(nil);

    unsigned char *c_key = (unsigned char *)[d_key bytes];
    unsigned int  idx    = 0;

    if (c_key[idx++] != 0x30) return(nil);

    if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
    else idx++;

    // PKCS #1 rsaEncryption szOID_RSA_RSA
    static unsigned char seqiod[] =
    { 0x30,   0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
        0x01, 0x05, 0x00 };
    if (memcmp(&c_key[idx], seqiod, 15)) return(nil);

    idx += 15;

    if (c_key[idx++] != 0x03) return(nil);

    if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
    else idx++;

    if (c_key[idx++] != '\0') return(nil);

    // Now make a new NSData from this buffer
    return([NSData dataWithBytes:&c_key[idx] length:len - idx]);

}

关于ios - 将 NSData 转换为 SecKeyRef,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21308415/

相关文章:

swift - Realm 加密 - 附带预填充数据时如何工作?

c - 如何使用 RSA 加密/解密长输入消息? [OpenSSL, C]

c - OPENSSL 和私钥

objective-c - 如何检查我的IOS App是否支持IOS 3+?关于匿名功能的一些知识

ios - 可以只有一个团队代理吗?苹果/苹果电脑

ios - 界面构建器约束,用于放大屏幕尺寸的按钮

ios - 向客户展示应用程序的测试版

Java AES加解密过程及Initialization Vector的使用

python - 在 Python 中使用 DPAPI?

c++ - rsa加密/解密polarssl c++