Firmar datos usando la key privada rsa

Sé que es Navidad pero tengo un gran problema que tengo que resolver, y estoy buscando mi milagro navideño aquí …

He leído la documentation de las manzanas y solo había guías sobre cómo crear keys públicas y privadas de RSA a partir de certificates. En mi caso, solo tengo la key privada RSA en el file .pem. Entonces mi pregunta es suya: ¿cómo debo firmar los datos usando esa key? No quiero usar openssl . Lo he intentado sin suerte, y creo que es posible firmar datos con RSA, utilizando las API de las manzanas.

Así es como se ve mi llave:

-----BEGIN RSA PRIVATE KEY----- .............................. -----END RSA PRIVATE KEY----- 

Esto es lo que he hecho hasta ahora:

 -(NSString *)signing:(NSString *)dataString { NSString *filePath = [[NSBundle mainBundle] pathForResource:@"PrestaMobilekey" ofType:@"pem"]; NSData *data = [[NSData alloc]initWithContentsOfFile:filePath]; SecKeyRef privateKey = (__bridge SecKeyRef)(data); uint8_t *signedHashBytes = NULL; // calculate private key size size_t signedHashBytesSize = SecKeyGetBlockSize(privateKey); // create space to put signature signedHashBytes = (uint8_t *)malloc(signedHashBytesSize * sizeof(uint8_t)); memset((void *)signedHashBytes, 0x0, signedHashBytesSize); OSStatus status = NULL; // sign data status = SecKeyRawSign(privateKey, kSecPaddingPKCS1SHA1, [[[dataString dataUsingEncoding:NSUTF8StringEncoding] SHA1] bytes], CC_SHA1_DIGEST_LENGTH, signedHashBytes, &signedHashBytesSize); if (privateKey) { CFRelease(privateKey); } // get signature hash NSData *signedHash = [NSData dataWithBytes:(const void *)signedHashBytes length:(NSUInteger)signedHashBytesSize]; // release created space if (signedHashBytes) { free(signedHashBytes); } if (status != errSecSuccess) { return @""; } // return Base64 encoded signature string return [Base64 encode:signedHash]; } 

Realmente espero que alguien me ayude, con buena información y respuestas.

Gracias.

No necesita usar OpenSSL. Puedes firmar tus datos usando tu método con algunos retoques. No creo que simplemente pueda tender un puente y lanzar un object NSData a un SecKeyRef . Lo más probable es que primero lo guardes en el llavero.

Puedes hacerlo con este método:

 - (SecKeyRef)saveKeyToKeychain:(NSData *)key keySize:(NSUInteger)keySize private:(BOOL)isPrivate { OSStatus sanityCheck = noErr; NSData *tag; id keyClass; if (isPrivate) { tag = privateTag; keyClass = (__bridge id) kSecAttrKeyClassPrivate; } else { tag = publicTag; keyClass = (__bridge id) kSecAttrKeyClassPublic; } NSDictionary *saveDict = @{ (__bridge id) kSecClass : (__bridge id) kSecClassKey, (__bridge id) kSecAttrKeyType : (__bridge id) kSecAttrKeyTypeRSA, (__bridge id) kSecAttrApplicationTag : tag, (__bridge id) kSecAttrKeyClass : keyClass, (__bridge id) kSecValueData : key, (__bridge id) kSecAttrKeySizeInBits : [NSNumber numberWithUnsignedInteger:keySize], (__bridge id) kSecAttrEffectiveKeySize : [NSNumber numberWithUnsignedInteger:keySize], (__bridge id) kSecAttrCanDerive : (__bridge id) kCFBooleanFalse, (__bridge id) kSecAttrCanEncrypt : (__bridge id) kCFBooleanTrue, (__bridge id) kSecAttrCanDecrypt : (__bridge id) kCFBooleanFalse, (__bridge id) kSecAttrCanVerify : (__bridge id) kCFBooleanTrue, (__bridge id) kSecAttrCanSign : (__bridge id) kCFBooleanFalse, (__bridge id) kSecAttrCanWrap : (__bridge id) kCFBooleanTrue, (__bridge id) kSecAttrCanUnwrap : (__bridge id) kCFBooleanFalse }; SecKeyRef savedKey = NULL; sanityCheck = SecItemAdd((__bridge CFDictionaryRef) saveDict, (CFTypeRef *)&savedKey); if (sanityCheck != errSecSuccess) { LOGGING_FACILITY1(sanityCheck != noErr, @"Problem saving the key to keychain, OSStatus == %d.", sanityCheck); } return savedKey; } 

Si no desea get la reference inmediatamente, puede cambiar el tipo de método para void y eliminar la statement de devolución. Cambie (CFTypeRef *)&savedKey a NULL .

A continuación, puede recuperar la key guardada de la siguiente manera:

 - (SecKeyRef)getKeyRef:(BOOL)isPrivate { OSStatus sanityCheck = noErr; NSData *tag; id keyClass; if (isPrivate) { if (privateKeyRef != NULL) { // already exists in memory, return return privateKeyRef; } tag = privateTag; keyClass = (__bridge id) kSecAttrKeyClassPrivate; } else { if (publicKeyRef != NULL) { // already exists in memory, return return publicKeyRef; } tag = publicTag; keyClass = (__bridge id) kSecAttrKeyClassPublic; } NSDictionary *queryDict = @{ (__bridge id) kSecClass : (__bridge id) kSecClassKey, (__bridge id) kSecAttrKeyType : (__bridge id) kSecAttrKeyTypeRSA, (__bridge id) kSecAttrApplicationTag : tag, (__bridge id) kSecAttrKeyClass : keyClass, (__bridge id) kSecReturnRef : (__bridge id) kCFBooleanTrue }; SecKeyRef keyReference = NULL; sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef) queryDict, (CFTypeRef *) &keyReference); if (sanityCheck != errSecSuccess) { NSLog(@"Error trying to retrieve key from server. isPrivate: %d. sanityCheck: %li", isPrivate, sanityCheck); } if (isPrivate) { privateKeyRef = keyReference; } else { publicKeyRef = keyReference; } return keyReference; } 

Además, una manera más fácil de devolver una cadena codificada base64 es hacer esto:

 NSString *signatureString = [signedHash base64EncodedStringWithOptions:nil]; 

Acerca de privateTag y publicTag

privateTag y publicTag se utilizan para marcar kSecAttrApplicationTag que define la aplicación que utiliza esta key. Desea tener un privateTag y publicTag para diferenciar entre su key privada y su key pública.

Es un poco intrincado porque seguí el código de ejemplo, pero privateTag mi privateTag y publicTag esta manera:

SecKeyWrapper.h

 #define kPublicKeyTag "com.sample.app.publickey" #define kPrivateKeyTag "com.sample.app.privatekey" 

SecKeyWrapper.m

 // just under @implementation or @synthesize lines static const uint8_t publicKeyIdentifier[] = kPublicKeyTag; static const uint8_t privateKeyIdentifier[] = kPrivateKeyTag; - (id)init { if (self = [super init]) { // Tag data to search for keys. privateTag = [[NSData alloc] initWithBytes:privateKeyIdentifier length:sizeof(privateKeyIdentifier)]; publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)]; } return self; } 

Luego use el privateTag y publicTag como lo haría en las muestras de código que proporcioné anteriormente.

Ok, o encontré una solución para este problema yo mismo. Espero que esto ayude a los demás … esto es lo que me ayudó. Pensé que podía hacer esto sin openssl, pero estaba equivocado. Pero aún así, al hacer como en esa publicación, no necesitarás una biblioteca adicional en tu proyecto. Usar terminal