Ios 将NSData转换为SecKeyRef

Ios 将NSData转换为SecKeyRef,ios,encryption,rsa,nsdata,public-key-encryption,Ios,Encryption,Rsa,Nsdata,Public Key Encryption,我有一个从远程服务器收集的公钥,我想用该公钥执行RSA加密。但问题是我将公钥数据作为缓冲区中的字节数组获取。我可以将其转换为NSData,但无法转换为SecKeyRef,因此我可以继续加密。我的加密代码如下: +(NSString *)encryptRSA:(NSString *)plainTextString withKey:(SecKeyRef)publicKey { size_t cipherBufferSize = SecKeyGetBlockSize(publicKey); uint8

我有一个从远程服务器收集的公钥,我想用该公钥执行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);
    }
此函数用于检索公钥引用。传递用于保存的相同名称

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

}

希望它能起作用

-(NSData*)convertIOSKeyToASNFormat:(NSData*)iosKey{

    static const unsigned char _encodedRSAEncryptionOID[15] = {
        /* Sequence of length 0xd made up of OID followed by NULL */
        0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
        0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00
    };

    // OK - that gives us the "BITSTRING component of a full DER
    // encoded RSA public key - we now need to build the rest

    unsigned char builder[15];
    NSMutableData * encKey = [[[NSMutableData alloc] init] autorelease];
    int bitstringEncLength;

    // When we get to the bitstring - how will we encode it?
    if  ([iosKey length ] + 1  < 128 )
        bitstringEncLength = 1 ;
    else
        bitstringEncLength = (([iosKey length ] +1 ) / 256 ) + 2 ;

    // Overall we have a sequence of a certain length
    builder[0] = 0x30;    // ASN.1 encoding representing a SEQUENCE

    // Build up overall size made up of -
    size_t i = sizeof(_encodedRSAEncryptionOID) + 2 + bitstringEncLength +
    [iosKey length];

    size_t j = [self encodeLen:&builder[1] length:i];
    [encKey appendBytes:builder length:j +1];

    // First part of the sequence is the OID
    [encKey appendBytes:_encodedRSAEncryptionOID
                 length:sizeof(_encodedRSAEncryptionOID)];

    // Now add the bitstring
    builder[0] = 0x03;
    j = [self encodeLen:&builder[1] length:[iosKey length] + 1];

    builder[j+1] = 0x00;
    [encKey appendBytes:builder length:j + 2];

    // Now the actual key
    [encKey appendData:iosKey];
    return encKey;
}
-(NSData*)将iosKey转换为SNFORMAT:(NSData*)iosKey{
静态常量无符号字符编码DRSAEncryptionOID[15]={
/*长度为0xd的序列,由OID后跟NULL组成*/
0x30、0x0d、0x06、0x09、0x2a、0x86、0x48、0x86、,
0xf7、0x0d、0x01、0x01、0x01、0x05、0x00
};
//好的-这给了我们完整DER的“位字符串组件”
//编码的RSA公钥-我们现在需要构建其余的
未签名的字符生成器[15];
NSMutableData*encKey=[[NSMutableData alloc]init]autorelease];
int位长度;
//当我们到达位字符串时,我们将如何对其进行编码?
如果([iosKey长度]+1<128)
bitstringEncLength=1;
其他的
bitstringEncLength=([iosKey长度]+1)/256)+2;
//总的来说,我们有一个一定长度的序列
生成器[0]=0x30;//表示序列的ASN.1编码
//建立由以下各项组成的总体规模:-
size\u t i=sizeof(\u encodedrsaencryptionId)+2+位字符串长度+
[密钥长度];
size_t j=[self-encodeLen:&builder[1]长度:i];
[encKey-appendBytes:builder-length:j+1];
//序列的第一部分是OID
[encKey appendBytes:\u encodedRSA EncryptionOID
长度:sizeof(_encodedRSAEncryptionOID)];
//现在添加位字符串
生成器[0]=0x03;
j=[self-encodeLen:&builder[1]长度:[iosKey长度]+1];
生成器[j+1]=0x00;
[encKey-appendBytes:builder-length:j+2];
//现在是实际的关键
[encKey-appendData:iosKey];
返回密钥;
}

谢谢您的回答,但此函数返回nil,我检查了使用NULL初始化的代码peerKeyRef变量,在对该变量不做任何操作后,函数返回它,因此它是NULL。对不起,M.Salich Kocak…第一个方法只是存储公钥(NSData).Second方法返回您的公钥seckeyref。请尝试此操作。您好,我这样写,但仍然将公钥设置为null:
NSData*publicKeyData=[[NSData alloc]initWithBytes:publicKeyBuffer length:publicKeyLen];[self-addPeerPublicKey:@“PeerName”keyBits:publicKeyData];seckeyref publicKey=[self-getPublicKeyReference:@“PeerName”];
我用调试模式检查了publicKeyBuffer,它有正确的值。这没有问题,publicKeyData也没有问题。我不明白我做错了什么。再次感谢。我怀疑如果你的公钥不是由ios生成的,那么你应该在存储公钥之前进行一些转换,然后只有你才能获得SecKeyRef、 我想这会解决你的问题,请参考我的代码added@jailani:此处,encodeLen:length:函数缺失。请同时更新相关函数好吗?