I applied the category method in the NSData class, which returns the data signature using the SHA-1 hash and then encrypting it with the private key as follows:
- (NSData *)signatureWithKey:(SecKeyRef)keyRef { if (keyRef == NULL) { return nil; } NSData *sha1Digest = [self dataWithSHA1Digest]; size_t maxLength = SecKeyGetBlockSize(keyRef) - 11; if ([sha1Digest length] > maxLength) { NSString *reason = [NSString stringWithFormat:@"Digest is too long to sign with this key, max length is %ld and actual length is %ld", maxLength, (unsigned long)[self length]]; NSException *ex = [NSException exceptionWithName:@"BMInvalidArgumentException" reason:reason userInfo:nil]; @throw ex; } #if TARGET_OS_IPHONE OSStatus status = noErr; uint8_t *plainBuffer = (uint8_t *)[sha1Digest bytes]; size_t plainBufferSize = [sha1Digest length]; size_t cipherBufferSize = SecKeyGetBlockSize(keyRef); uint8_t *cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t)); status = SecKeyRawSign(keyRef, kSecPaddingPKCS1SHA1, plainBuffer, plainBufferSize, &cipherBuffer[0], &cipherBufferSize ); if (status == noErr) { return [NSData dataWithBytesNoCopy:cipherBuffer length:cipherBufferSize freeWhenDone:YES]; } free(cipherBuffer); return nil; #else CFErrorRef error = NULL; SecTransformRef signer = NULL; CFTypeRef signature = NULL; if ((signer = SecSignTransformCreate(keyRef, &error))) { if (SecTransformSetAttribute( signer, kSecTransformInputAttributeName, (CFDataRef)sha1Digest, &error)) { signature = SecTransformExecute(signer, &error); } } if (error) { LogWarn(@"Could not sign: %@", error); CFRelease(error); } if (signer) { CFRelease(signer); } if (signature) { NSData *data = [NSData dataWithData:(NSData *)signature]; CFRelease(signature); return data; } else { return nil; } #endif }
Now itβs strange that with the same private key (downloaded from the p12 file) I get two different results for iOS and MacOSX when signing the same data. I am completely puzzled by this. You may notice that the method described above uses a different implementation for MacOSX using security transformations, but even if I use the iOS implementation on MacOSX (which gives a compilation warning but works fine), I get the same result.
The method used to load the private key from the file is below:
+ (SecKeyRef)newPrivateKeyRefWithPassword:(NSString *)password fromData:(NSData *)data { NSMutableDictionary * options = [[NSMutableDictionary alloc] init]; SecKeyRef privateKeyRef = NULL;
And this is a test case that I use. Note that on iOS and MacOSX two different lines are printed:
NSString *test = @"bla"; NSData *testData = [test dataUsingEncoding:NSUTF8StringEncoding]; NSString *p12Path= [[NSBundle mainBundle] pathForResource:@"private_key" ofType:@"p12"]; NSData *p12Data = [NSData dataWithContentsOfFile:p12Path]; SecKeyRef keyRef = [BMSecurityHelper newPrivateKeyRefWithPassword:@"xxxxxxxx" fromData:p12Data]; NSData *signatureData = [testData signatureWithKey:keyRef]; NSString *signatureString = [BMEncodingHelper base64EncodedStringForData:signatureData withLineLength:0]; if (keyRef) CFRelease(keyRef); NSLog(@"signatureString: %@", signatureString);
source share