将NSData转换为SecKeyRef [英] Converting NSData to SecKeyRef

查看:795
本文介绍了将NSData转换为SecKeyRef的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个公共密钥,我从远程服务器收集,我想用该公钥执行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(@将对等公钥添加到钥匙串,OSStatus ==%ld,sanityCheck);
}

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

// TRC_DBG(@PersistPeer导入到钥匙串%@中的私钥数据,persistPeer);
persistPeer = NULL;
[peerPublicKeyAttr removeObjectForKey:(id)kSecValueData];
sanityCheck = SecItemCopyMatching((CFDictionaryRef)peerPublicKeyAttr,(CFTypeRef *)& persistPeer);

TRC_DBG(@SecItemCopying OSStATUS =%ld,sanityCheck);
// TRC_DBG(@SecItem复制匹配返回此公钥数据%@,persistPeer);
//持久引用的好处是可以将它们的值写入磁盘,然后
//然后再使用它们。我不这样做,但是对于其他情况来说肯定是有意义的,你不想不断地建立字典的属性来获得引用。
//
//另请看看SecKeyWrapper的方法(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 
{
//跳过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);

//现在从这个缓冲区创建一个新的NSData
return([NSData dataWithBytes:& c_key [idx] length:len-idx]);

}


i have a public key which i gathered from a remote server and i want to perform RSA encryption with that public key. But the problem is i get the public key data as byte array in buffer. I can convert it to NSData but i can not convert to SecKeyRef so i can keep going with encryption. My encryption code is like:

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

}

As you can see i need SecKeyRef object type to complete my encryption. But my RSA public key is in NSData variable. So how can i convert NSData to SecKeyRef object type. Thanks in advance.

解决方案

Use this function to save your public key. Pass your RAS public key and any name for 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);
    }

This is the function to retrieve the public key ref. Pass the same name which one is used for save.

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

Pass your public key data to this function before 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转换为SecKeyRef的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆