Question

I am trying to verify a data with a public key, using the exact method mentioned on http://blog.flirble.org/2011/01/05/rsa-public-key-openssl-ios/.

I tested my code with simulator iOS 6.1, iOS 4.3 and iOS 5.0. It is working on iOS 6.1 but it is not working on iOS 4.3 and iOS 5.0. On iOS 4.3 and iOS 5.0, the SecKeyRawVerify fails with error code -50(one of the input params is wrong).

Any one having any idea what is wrong here?

Below is the code of the verify function which I am using. Please see the definition of the functions used here

Code:

+ (SecKeyRef)getPublicKeyRef:(NSString*)key
{
    NSString* tag = @"com.publickey";

    NSString *s_key = [NSString string];
    NSArray  *a_key = [key componentsSeparatedByString:@"\n"];
    BOOL     f_key  = FALSE;

    for (NSString *a_line in a_key) {
        if ([a_line isEqualToString:@"-----BEGIN PUBLIC KEY-----"]) {
            f_key = TRUE;
        }
        else if ([a_line isEqualToString:@"-----END PUBLIC KEY-----"]) {
            f_key = FALSE;
        }
        else if (f_key) {
            s_key = [s_key stringByAppendingString:a_line];
        }
    }
    if (s_key.length == 0) return(FALSE);

    // This will be base64 encoded, decode it.
    NSData *d_key = [Base64 decode:s_key];//[NSData dataFromBase64String:s_key];
    d_key = [CryptoUtil stripPublicKeyHeader:d_key];
    if (d_key == nil) return(FALSE);

    NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]];

    // Delete any old lingering key with the same tag
    NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init];
    [publicKey setObject:(id) kSecClassKey forKey:(id)kSecClass];
    [publicKey setObject:(id) kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
    [publicKey setObject:d_tag forKey:(id)kSecAttrApplicationTag];
    SecItemDelete((CFDictionaryRef)publicKey);

    CFTypeRef persistKey = nil;

    // Add persistent version of the key to system keychain
    [publicKey setObject:d_key forKey:(id)kSecValueData];
    [publicKey setObject:(id) kSecAttrKeyClassPublic forKey:(id)kSecAttrKeyClass];
    [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnPersistentRef];

    OSStatus secStatus = SecItemAdd((CFDictionaryRef)publicKey, &persistKey);
    if (persistKey != nil) CFRelease(persistKey);

    if ((secStatus != noErr) && (secStatus != errSecDuplicateItem)) {
        [publicKey release];
        return(FALSE);
    }

    // Now fetch the SecKeyRef version of the key
    SecKeyRef keyRef = nil;

    [publicKey removeObjectForKey:(id)kSecValueData];
    [publicKey removeObjectForKey:(id)kSecReturnPersistentRef];
    [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef];
    [publicKey setObject:(id) kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
    secStatus = SecItemCopyMatching((CFDictionaryRef)publicKey,(CFTypeRef *)&keyRef);

    [publicKey release];

    if (keyRef == nil) return(FALSE);

    return keyRef;
}

+ (BOOL)verifyMessage:(NSString *)msg forSignature:(NSString*)signature forPublicKey:(NSString*)publicKey
{
    // Search for the two sections: Data and a signature.
    NSString *s_data = msg, *s_signature = signature;

    if ((s_data.length == 0) || (s_signature.length == 0)) return(FALSE);

    // These will be base64 encoded, decode them.
    NSData *d_data = [s_data dataUsingEncoding:NSUTF8StringEncoding];
    if (d_data == nil) return(FALSE);

    NSData *d_signature = [Base64 decode:s_signature];
    if (d_signature == nil) return(FALSE);

    // Make SHA-256 hash of the data
    uint8_t h_data[CC_SHA256_DIGEST_LENGTH];
    CC_SHA256(d_data.bytes, d_data.length, h_data);
    NSData* d_hash = [NSData dataWithBytes:h_data length:CC_SHA256_DIGEST_LENGTH];

    // The signature is generated against the binary form of the data, validate
    //it.
    BOOL valid = FALSE;

    OSStatus secStatus = SecKeyRawVerify([CryptoUtil getPublicKeyRef:publicKey],
                                     kSecPaddingPKCS1SHA256,
                                     d_hash.bytes, d_hash.length,
                                     d_signature.bytes,
                                     d_signature.length);
    if (secStatus == errSecSuccess) {
        valid = TRUE;
    }

    return(valid);
}

Error code: The SecKeyRawVerify fails with error code -50(one of the input params is wrong) on iOS 5.0 and iOS 4.3, but the call succeeds on iOS 6.1.

Thanks in advance.

Was it helpful?

Solution

Found the reason why it was not working, kSecPaddingPKCS1SHA256 is supported iOS 6.0 above only. http://developer.apple.com/library/ios/#releasenotes/General/iOS60APIDiffs/index.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top