iOS verify digital signature

In my application, I have a public key (represented as string), plain message and digital signature, represented as base64 encoded string, hashed with SHA256 and encrypted with RSA).
Now, I need to verify digital signature. I was trying to do as follows:

  1. create SecKeyRef from NSString (taken from here)
  2. create SHA256 digest from original message
  3. verify signature using SecKeyRawVerify function

(I am trying to avoid using OpenSSL function)

  • AES encryption in swift
  • iOS: How to create PKCS12 (P12) keystore from private key and x509certificate in application programmatically?
  • Verifying RSA Signature iOS
  • Does iPhone support hardware-accelerated AES Encryption?
  • Elliptic Curve Crypto in iOS
  • What is the difference between the different padding types on iOS?
  • Additionally, my digital signature was created using Java’s SHA256withRSA method. I was reading here that SHA256WithRSA appends algorithm identifier with the actual hash. Now, I am not sure whether or not I need to append it to the hash.

    Anyway, in both cases I get error -50, which according to Apple’s documentations means One
    or more parameters passed to a function were not valid.

    Here is my code:

    -(BOOL) verifySignature:(NSString*) rawData andKey:(NSString*) key andSignature:(NSString*)signature {
    
        NSData* originalData = [rawData dataUsingEncoding:NSUTF8StringEncoding];
        NSData *signatureData = [NSData dataFromBase64String:signature];
    
        SecKeyRef publicKey = [self generatePublicKey:key];
    
        uint8_t sha2HashDigest[CC_SHA256_DIGEST_LENGTH];
        CC_SHA256([originalData bytes], [originalData length], sha2HashDigest);
    
        //DO I NEED THIS?
        NSString *algIdentifier = @"1.3.14.3.2.26";
        NSData *algData = [algIdentifier dataUsingEncoding:NSUTF8StringEncoding];
        NSData* d_hash = [NSData dataWithBytes:sha2HashDigest length:CC_SHA256_DIGEST_LENGTH];
    
        NSMutableData *concatenatedData = [NSMutableData data];
        [concatenatedData appendData:algData];
        [concatenatedData appendData:d_hash];
    
        OSStatus verficationResult =  SecKeyRawVerify (publicKey,
                         kSecPaddingPKCS1SHA256,
                         (const uint8_t *)[d_hash bytes],
                         (size_t)[d_hash length],
                         (const uint8_t *)[signatureData bytes],
                         (size_t)[signatureData length]
                         );
    
    
        CFRelease(publicKey);
    
        if (verficationResult == errSecSuccess){
            NSLog(@"Verified");
            return YES;
        }
        return NO;
    
    }
    
    - (SecKeyRef)generatePublicKey:(NSString *)key
    {
    
        // This will be base64 encoded, decode it.
        NSData *d_key = [NSData dataFromBase64String:key];
        d_key = [self stripPublicKeyHeader:d_key];
        if (d_key == nil) return(nil);
    
        NSData *d_tag = [NSData dataWithBytes:[@"pubKey" UTF8String] length:[@"pubKey" length]];
    
        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(nil);
        }
    
        // 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];
        return keyRef;
    
    }
    

    Solutions Collect From Internet About “iOS verify digital signature”

    Maybe this answer is a little late but I had the same problem.

    It turns out that Java handles the hashing for you, but iOS does not.

    So if you have a plaintext called plainText you might generate a signature on it in Java doing this:

    public static byte[] sign(PrivateKey key, byte[] plainText) {
        try {
            Signature signature = Signature.getInstance("SHA256withRSA");
            signature.initSign(key);
            signature.update(plainText);
            return signature.sign();
        } catch (Exception e) {
            return null;
        }
    }
    

    But then to verify it in iOS you need to manually take a hash of the plaintext like so:

    + (BOOL)verifySignature:(uint8_t*)signature signatureLen:(size_t)sLen
                withPlainText:(uint8_t*)plainText plainTextLen:(size_t)pLen
                andKey:(SecKeyRef)key {
        uint8_t hash[32];
        CC_SHA256(plainText, pLen, hash);
        OSStatus returnCode = SecKeyRawVerify(key,
                                              kSecPaddingPKCS1SHA256,
                                              hash,
                                              32,
                                              signature,
                                              sLen);
        return returnCode == 0;
    }
    

    In the above method, signature is the bytes generated by the Java method.

    Of course, you may not want to hardcode parameters such as the the hash function used (and length of hash).