Question

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.

Was it helpful?

Solution

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

}

OTHER TIPS

Hope It will work....

-(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;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top