Extracting a public key from key pair in key chain - iphone

The Problem: Retrieving a public key
For an iPhone App, I need to create a rsa key pair, store it in the key chain and retrieve the public key.
Fortunately, Apple released a Crypto Exercise Sample where everything i need can be found (class SecKeyWrapper, functions generateKeyPair and getPublicKeyBits).
But after trying to use these functions, I always get the same output for my public key for different key pairs (instead of different public key bits for different key pairs).
Implementation of my generateKeyPair and getPublicKeyBits Function:
I first create a key pair by calling generateKeyPairWithKeySizeInBits (which seems to work fine), afterwards I extract the public key bits with getPublicKeyBits and NSLog them...
- (void) generateKeyPairWithKeySizeInBits:(int)bits withPublicIdentifier:(NSString *)publicIdentifier andPrivateIdentifier:(NSString *)privateIdentifier
{
NSLog(#"begin generating key...");
OSStatus status = noErr;
NSMutableDictionary* privateKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary* publicKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary* keyPairAttr = [[NSMutableDictionary alloc] init];
NSData* publicTag = [publicIdentifier dataUsingEncoding:NSUTF8StringEncoding];
NSData* privateTag = [privateIdentifier dataUsingEncoding:NSUTF8StringEncoding];
SecKeyRef publicKey = NULL;
SecKeyRef privateKey = NULL;
[keyPairAttr setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id) kSecAttrKeyType];
[keyPairAttr setObject:[NSNumber numberWithInt:bits] forKey:(__bridge id) kSecAttrKeySizeInBits];
[privateKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id) kSecAttrIsPermanent];
[privateKeyAttr setObject:privateTag forKey:(__bridge id) kSecAttrApplicationTag];
[publicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
[publicKeyAttr setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
[keyPairAttr setObject:privateKeyAttr forKey:(__bridge id)kSecPrivateKeyAttrs];
[keyPairAttr setObject:publicKeyAttr forKey:(__bridge id)kSecPublicKeyAttrs];
SecItemDelete((__bridge CFDictionaryRef)keyPairAttr);
status = SecKeyGeneratePair((__bridge CFDictionaryRef) keyPairAttr, &publicKey, &privateKey);
if(status != noErr){
NSLog(#"status = %#",status);
}
if(publicKey){
NSLog(#"public key %#",publicKey);
}
if(privateKey){
NSLog(#"private key %#",privateKey);
}
[self getPublicKeyBits:publicIdentifier];
}
- (NSData *)getPublicKeyBits: (NSString*) publicKeyIdentifier {
OSStatus sanityCheck = noErr;
NSData * publicKeyBits = nil;
CFTypeRef pk;
NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];
NSData* publicTag = [publicKeyIdentifier dataUsingEncoding:NSUTF8StringEncoding];
// Set the public key query dictionary.
[queryPublicKey setObject:(__bridge_transfer id)kSecClassKey forKey:(__bridge_transfer id)kSecClass];
[queryPublicKey setObject:publicTag forKey:(__bridge_transfer id)kSecAttrApplicationTag];
[queryPublicKey setObject:(__bridge_transfer id)kSecAttrKeyTypeRSA forKey:(__bridge_transfer id)kSecAttrKeyType];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge_transfer id)kSecReturnData];
// Get the key bits.
sanityCheck = SecItemCopyMatching((__bridge_retained CFDictionaryRef)queryPublicKey, &pk);
if (sanityCheck != noErr)
{
publicKeyBits = nil;
}
publicKeyBits = (__bridge_transfer NSData*)pk;
NSLog(#"public bits %#",publicKeyBits);
return publicKeyBits;
}
Output (the "public bits"-part (last line) is always the same):
2012-07-13 10:39:28.391 [12279:707] begin generating key...
2012-07-13 10:39:39.376 [12279:707] public key <SecKeyRef: 0xeb56e00>
2012-07-13 10:39:39.381 [12279:707] private key <SecKeyRef: 0xeb57800>
2012-07-13 10:39:39.397 [12279:707] public bits <3082010a 02820101 00ea41ec 12780dff 20a55d67 62ec9890 028ed031 eccd1163 5b4bd039 01adffb5 766f37b8 31be8d03 4a41240b 4e127b75 bc4dd8fb 5b404d4d ad18d711 5cf64a04 61c49970 1fef5434 215f80e4 efee8894 1f282f77 8ea5f7e3 35673260 80ee5f80 818d19d3 b7b15e5c f013ad7d 5ff5dd33 b3e57544 de50dc02 f28aa2ae d4b9590a 1e71bd05 79e81fb7 2a9cd592 cf412fe1 db7a89d4 05bd1731 f95f7aae 56ec4171 e9f352ec c26c3c15 05a0e84b 16c5e89d cec8b1a3 24365d4e dcea88a2 92d8c2e6 8f0e9aee e83703bc e66418af aa9dceea 1129f669 cf069b87 edde4cf7 5e313212 80f44e04 d5b5e2db 9e7f26ae 9b8ef8ee 2e177702 18673b1a f125d3c8 d9ddf978 fb020301 0001>

So Your SecItemDelete code does not work as you expect it to. If you want to delete all the items in your keychain (for testing purposes, obviously), you should look at the code in -[Credentials resetCredentials] method in the AdvancedURLConnections sample code.
https://developer.apple.com/library/ios/#samplecode/AdvancedURLConnections/
You might also find the -dumpCredentials method handy during debugging.
So The problem with SecItemDelete means that SecKeyGeneratePair is generating a new set of keys each time you run the app. Each of these keys has the same application tag, making it indeterminate as to which key is returned by your SecItemCopyMatching call in -getPublicKeyBits:. In turns out that on current system software you're always getting back the first key, so you always get the same public key bits.

Public key will be having two components Exponent and Modulus.You can try this
after getting PublickeyBits method
- (NSData *)getPublicKeyExp
{
NSData* pk = [self getPublicKeyBits];
if (pk == NULL) return NULL;
int iterator = 0;
iterator++; // TYPE - bit stream - mod + exp
[self derEncodingGetSizeFrom:pk at:&iterator]; // Total size
iterator++; // TYPE - bit stream mod
int mod_size = [self derEncodingGetSizeFrom:pk at:&iterator];
iterator += mod_size;
iterator++; // TYPE - bit stream exp
int exp_size = [self derEncodingGetSizeFrom:pk at:&iterator];
return [pk subdataWithRange:NSMakeRange(iterator, exp_size)];
return pk;
}
- (NSData *)getPublicKeyMod
{
NSData* pk = [self getPublicKeyBits];
if (pk == NULL) return NULL;
int iterator = 0;
iterator++; // TYPE - bit stream - mod + exp
[self derEncodingGetSizeFrom:pk at:&iterator]; // Total size
iterator++; // TYPE - bit stream mod
int mod_size = [self derEncodingGetSizeFrom:pk at:&iterator];
return [pk subdataWithRange:NSMakeRange(iterator, mod_size)];
return pk;
NSLog(#"public size: %d",pk.length);
}
- (int)derEncodingGetSizeFrom:(NSData*)buf at:(int*)iterator
{
const uint8_t* data = [buf bytes];
int itr = *iterator;
int num_bytes = 1;
int ret = 0;
if (data[itr] > 0x80) {
num_bytes = data[itr] - 0x80;
itr++;
}
for (int i = 0 ; i < num_bytes; i++)
ret = (ret * 0x100) + data[itr + i];
*iterator = itr + num_bytes;
return ret;
}

Related

public key in ios keychain changes on each get

I have followed the apple developer documents and specifically the examples showing how to generate key pair, encrypt with the public key and decrypt with the private key. They have three example methods in the guide for this (page 19 onwards here).
I have copied an pasted these three methods into my project, only changing them to be public class methods, added logging and hooked up buttons to call them feeding the output of the encryption into the decrypt:
In the viewcontroller:
-(IBAction)generateKey:(UIButton*)sender
{
[CryptoClass generateKeyPairPlease];
}
-(IBAction)encryptAndDecrypt
{
NSData *data = [CryptoClass encryptWithPublicKey];
[CryptoClass decryptWithPrivateKey:data];
}
The code for the three methods are:
static const UInt8 publicKeyIdentifier[] = "com.apple.sample.publickey\0";
static const UInt8 privateKeyIdentifier[] = "com.apple.sample.privatekey\0";
+ (NSData *)encryptWithPublicKey
{
OSStatus status = noErr;
size_t cipherBufferSize;
uint8_t *cipherBuffer; // 1
// [cipherBufferSize]
const uint8_t dataToEncrypt[] = "the quick brown fox jumps "
"over the lazy dog\0"; // 2
size_t dataLength = sizeof(dataToEncrypt)/sizeof(dataToEncrypt[0]);
SecKeyRef publicKey = NULL; // 3
NSData * publicTag = [NSData dataWithBytes:publicKeyIdentifier
length:strlen((const char *)publicKeyIdentifier)]; // 4
NSMutableDictionary *queryPublicKey =
[[NSMutableDictionary alloc] init]; // 5
[queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
[queryPublicKey setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
[queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
// 6
status = SecItemCopyMatching
((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKey); // 7
// Allocate a buffer
cipherBufferSize = SecKeyGetBlockSize(publicKey);
cipherBuffer = malloc(cipherBufferSize);
// Error handling
if (cipherBufferSize < sizeof(dataToEncrypt)) {
// Ordinarily, you would split the data up into blocks
// equal to cipherBufferSize, with the last block being
// shorter. For simplicity, this example assumes that
// the data is short enough to fit.
printf("Could not decrypt. Packet too large.\n");
return NULL;
}
// Encrypt using the public.
status = SecKeyEncrypt( publicKey,
kSecPaddingPKCS1,
dataToEncrypt,
(size_t) dataLength,
cipherBuffer,
&cipherBufferSize
); // 8
// Error handling
// Store or transmit the encrypted text
if (publicKey) CFRelease(publicKey);
NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:dataLength];
free(cipherBuffer);
return encryptedData;
}
+ (void)generateKeyPairPlease
{
OSStatus status = noErr;
NSMutableDictionary *privateKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary *publicKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary *keyPairAttr = [[NSMutableDictionary alloc] init];
// 2
NSData * publicTag = [NSData dataWithBytes:publicKeyIdentifier
length:strlen((const char *)publicKeyIdentifier)];
NSData * privateTag = [NSData dataWithBytes:privateKeyIdentifier
length:strlen((const char *)privateKeyIdentifier)];
// 3
SecKeyRef publicKey = NULL;
SecKeyRef privateKey = NULL; // 4
[keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA
forKey:(__bridge id)kSecAttrKeyType]; // 5
[keyPairAttr setObject:[NSNumber numberWithInt:1024]
forKey:(__bridge id)kSecAttrKeySizeInBits]; // 6
[privateKeyAttr setObject:[NSNumber numberWithBool:YES]
forKey:(__bridge id)kSecAttrIsPermanent]; // 7
[privateKeyAttr setObject:privateTag
forKey:(__bridge id)kSecAttrApplicationTag]; // 8
[publicKeyAttr setObject:[NSNumber numberWithBool:YES]
forKey:(__bridge id)kSecAttrIsPermanent]; // 9
[publicKeyAttr setObject:publicTag
forKey:(__bridge id)kSecAttrApplicationTag]; // 10
[keyPairAttr setObject:privateKeyAttr
forKey:(__bridge id)kSecPrivateKeyAttrs]; // 11
[keyPairAttr setObject:publicKeyAttr
forKey:(__bridge id)kSecPublicKeyAttrs]; // 12
status = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr,
&publicKey, &privateKey); // 13
// error handling...
if(publicKey) CFRelease(publicKey);
if(privateKey) CFRelease(privateKey); // 14
}
+ (void)decryptWithPrivateKey: (NSData *)dataToDecrypt
{
OSStatus status = noErr;
size_t cipherBufferSize = [dataToDecrypt length];
uint8_t *cipherBuffer = (uint8_t *)[dataToDecrypt bytes];
size_t plainBufferSize;
uint8_t *plainBuffer;
SecKeyRef privateKey = NULL;
NSData * privateTag = [NSData dataWithBytes:privateKeyIdentifier
length:strlen((const char *)privateKeyIdentifier)];
NSMutableDictionary *queryPrivateKey = [[NSMutableDictionary alloc] init];
// Set the private key query dictionary.
[queryPrivateKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
[queryPrivateKey setObject:privateTag forKey:(__bridge id)kSecAttrApplicationTag];
[queryPrivateKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[queryPrivateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
// 1
status = SecItemCopyMatching
((__bridge CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKey); // 2
// Allocate the buffer
plainBufferSize = SecKeyGetBlockSize(privateKey);
plainBuffer = malloc(plainBufferSize);
if (plainBufferSize < cipherBufferSize) {
// Ordinarily, you would split the data up into blocks
// equal to plainBufferSize, with the last block being
// shorter. For simplicity, this example assumes that
// the data is short enough to fit.
printf("Could not decrypt. Packet too large.\n");
return;
}
// Error handling
status = SecKeyDecrypt( privateKey,
kSecPaddingPKCS1,
cipherBuffer,
cipherBufferSize,
plainBuffer,
&plainBufferSize
); // 3
// Error handling
// Store or display the decrypted text
NSLog(#"Plain: %#",[NSString stringWithUTF8String:(const char *)plainBuffer]);
if(privateKey) CFRelease(privateKey);
}
I have been trying many different guides and read a lot of posts here trying to get this to work. I also tried Apples KeyChainWrapperItem to store and retrieve the keys with no luck. I also found a post here describing and showing the exact code to get the key in data-format, but that returns nil for some reason.
The last thing I did was using Matt Gallagher's NSData+Base64 category to print the encrypted string and can visually see that the string is wildly different for each pass even if I do not generate a new key with this code:
-(IBAction)encryptAndDecrypt
{
NSData *data = [CryptoClass encryptWithPublicKey];
NSLog(#"String: %#", [data base64EncodedString]); // Print encrypted data as base64
[CryptoClass decryptWithPrivateKey:data];
}
FYI I'm currently only running on the simulator if that is of importance. And I reset it to clear the keychain before each generation.
Can anyone please help me understand this?
Errors in provided code
In + (NSData *)encryptWithPublicKey, this line will strip the encrypted data (and destroy it)
NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:dataLength];
It should be
NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:cipherBufferSize];
Different result each time
It is not an error to see different results each time. The PKCS#1 encryption algorithm uses some random seed to make the cipher-text different each time. This is called padding and protects against several attacks, e.g. frequency analysis and ciphertext matching. See this Wikipedia article section: http://en.wikipedia.org/wiki/RSA_(algorithm)#Padding_schemes

How can I save a NSString public key in the key chain and then get a SecKeyRef of it?

I have a NSString which is supposed to be a public key. I want to store it in the keychain and then get a SecKeyRef of it, in order to use it in other security related functions like SecKeyEncrypt, etc.
For storing I use the SecItemAdd supposing that I also have an identifier for the public key. I tried to get a persistent ref and then with this get a SecKeyRef with SecItemCopyMatching. I use the below two functions. Before I pass the string of key to putKey I converted it to NSData.
-(SecKeyRef)putKey:(NSData *)key withIdentifier:(NSString *)identifier
{
OSStatus status = noErr;
SecKeyRef keyRef = nil;
CFTypeRef persKey = nil;
NSData * identifierTag = [[NSData alloc] initWithBytes:(const void *)[identifier UTF8String] length:[identifier length]];
NSMutableDictionary *queryKey = [[NSMutableDictionary alloc] init];
[queryKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
[queryKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[queryKey setObject:identifierTag forKey:(__bridge id)kSecAttrApplicationTag];
[queryKey setObject:key forKey:(__bridge id)kSecValueData];
[queryKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnPersistentRef];
status = SecItemAdd((__bridge CFDictionaryRef)queryKey, (CFTypeRef *)&persKey);
if (status == errSecDuplicateItem) NSLog(#"Key %# already exists in the KeyStore, OSStatus = %ld.", identifier, status);
else if (status != noErr) NSLog(#"Error putting key %# in KeyStore, OSStatus = %ld.", identifier, status);
keyRef = [self getKeyRefWithPersistentKeyRef:persKey];
return keyRef;
}
- (SecKeyRef)getKeyRefWithPersistentKeyRef:(CFTypeRef)persistentRef
{
OSStatus sanityCheck = noErr;
SecKeyRef keyRef = NULL;
if (persistentRef == NULL) NSLog(#"persistentRef object cannot be NULL.");
NSMutableDictionary * queryKey = [[NSMutableDictionary alloc] init];
// Set the SecKeyRef query dictionary.
[queryKey setObject:(__bridge id)persistentRef forKey:(__bridge id)kSecValuePersistentRef];
[queryKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
// Get the key reference.
sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryKey, (CFTypeRef *)&keyRef);
return keyRef;
}
The SecItemAdd returns successfully a persistent key ref.
But SecItemCopyMatching returns 0x0. Anyone knows why?
Checkout Apple's Crypto Exercise. In order to add a public key to the KeyChain, it is necessary to strip off the header that is attached to it. Apple's example shows doing just that, and the code is easy to reuse.

How to find out the modulus and exponent of RSA Public Key on iPhone/Objective C

Is there a possible way to find out the modulus and exponent of the Public Key, created with SecKeyGeneratePair (the Security Framework in general)?
Busted my head on this, but here's a solution I've found (without using any external packages).
First, go to Apple's CryptoExercise example. Download the "SecKeyWrapper" class from there. The interesting function in that class is getPublicKeyBits.
Link to the example: http://developer.apple.com/library/ios/#samplecode/CryptoExercise/Introduction/Intro.html
The bits you will receive is a DER encoded (wiki it) public key containing both the modulus and exp. Here's a code that will decode it for you, pretty easy:
- (NSData *)getPublicKeyExp
{
NSData* pk = [self getPublicKeyBits];
if (pk == NULL) return NULL;
int iterator = 0;
iterator++; // TYPE - bit stream - mod + exp
[self derEncodingGetSizeFrom:pk at:&iterator]; // Total size
iterator++; // TYPE - bit stream mod
int mod_size = [self derEncodingGetSizeFrom:pk at:&iterator];
iterator += mod_size;
iterator++; // TYPE - bit stream exp
int exp_size = [self derEncodingGetSizeFrom:pk at:&iterator];
return [pk subdataWithRange:NSMakeRange(iterator, exp_size)];
}
- (NSData *)getPublicKeyMod
{
NSData* pk = [self getPublicKeyBits];
if (pk == NULL) return NULL;
int iterator = 0;
iterator++; // TYPE - bit stream - mod + exp
[self derEncodingGetSizeFrom:pk at:&iterator]; // Total size
iterator++; // TYPE - bit stream mod
int mod_size = [self derEncodingGetSizeFrom:pk at:&iterator];
return [pk subdataWithRange:NSMakeRange(iterator, mod_size)];
}
- (int)derEncodingGetSizeFrom:(NSData*)buf at:(int*)iterator
{
const uint8_t* data = [buf bytes];
int itr = *iterator;
int num_bytes = 1;
int ret = 0;
if (data[itr] > 0x80) {
num_bytes = data[itr] - 0x80;
itr++;
}
for (int i = 0 ; i < num_bytes; i++) ret = (ret * 0x100) + data[itr + i];
*iterator = itr + num_bytes;
return ret;
}
I tried this approach and it works fine for extracting the exponent. It is 3 bytes in size as expected but the extracted modulus is not the correct size. The size of the modulus is 129 bytes instead of 128 bytes.
The code is as follows:
- (NSData *)getPublicKeyBits: (NSString*) publicKeyIdentifier {
OSStatus sanityCheck = noErr;
NSData * publicKeyBits = nil;
CFTypeRef pk;
NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];
NSData* publicTag = [publicKeyIdentifier dataUsingEncoding:NSUTF8StringEncoding];
// Set the public key query dictionary.
[queryPublicKey setObject:(__bridge_transfer id)kSecClassKey forKey:(__bridge_transfer id)kSecClass];
[queryPublicKey setObject:publicTag forKey:(__bridge_transfer id)kSecAttrApplicationTag];
[queryPublicKey setObject:(__bridge_transfer id)kSecAttrKeyTypeRSA forKey:(__bridge_transfer id)kSecAttrKeyType];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge_transfer id)kSecReturnData];
// Get the key bits.
sanityCheck = SecItemCopyMatching((__bridge_retained CFDictionaryRef)queryPublicKey, &pk);
if (sanityCheck != noErr)
{
publicKeyBits = nil;
}
publicKeyBits = (__bridge_transfer NSData*)pk;
//NSLog(#"public bits %#",publicKeyBits);
return publicKeyBits;
}
- (NSData *)getPublicKeyExp
{
NSData* pk = [self getPublicKeyBits:#"RSA Public Key"];
if (pk == NULL) return NULL;
int iterator = 0;
iterator++; // TYPE - bit stream - mod + exp
[self derEncodingGetSizeFrom:pk at:&iterator]; // Total size
iterator++; // TYPE - bit stream mod
int mod_size = [self derEncodingGetSizeFrom:pk at:&iterator];
iterator += mod_size;
iterator++; // TYPE - bit stream exp
int exp_size = [self derEncodingGetSizeFrom:pk at:&iterator];
return [pk subdataWithRange:NSMakeRange(iterator, exp_size)];
return pk;
}
- (NSData *)getPublicKeyMod
{
NSData* pk = [self getPublicKeyBits:#"RSA Public Key"];
if (pk == NULL) return NULL;
int iterator = 0;
iterator++; // TYPE - bit stream - mod + exp
[self derEncodingGetSizeFrom:pk at:&iterator]; // Total size
iterator++; // TYPE - bit stream mod
int mod_size = [self derEncodingGetSizeFrom:pk at:&iterator];
return [pk subdataWithRange:NSMakeRange(iterator, mod_size)];
return pk;
NSLog(#"public size: %d",pk.length);
}
- (int)derEncodingGetSizeFrom:(NSData*)buf at:(int*)iterator
{
const uint8_t* data = [buf bytes];
int itr = *iterator;
int num_bytes = 1;
int ret = 0;
if (data[itr] > 0x80) {
num_bytes = data[itr] - 0x80;
itr++;
}
for (int i = 0 ; i < num_bytes; i++)
ret = (ret * 0x100) + data[itr + i];
*iterator = itr + num_bytes;
return ret;
}
Something like the following is much more reliable:
+ (NSInteger)keyModulusSize:(NSData *)keyData
{
NSString *randomTag = [NSString ptk_randomStringOfLength:32];
SecKeyRef key = [self addPublicKeyRef:keyData withTag:randomTag];
NSInteger size = 0;
if (key) {
size = SecKeyGetBlockSize(key);
[self removePublicKeyRef:randomTag];
}
return size;
}
I removed that extra byte at the beginning, now it works fine. In my case it was always extracting 129 bytes modulus.
- (NSData *)getPublicKeyModFromKeyData:(NSData*)pk
{
if (pk == NULL) return NULL;
int iterator = 0;
iterator++; // TYPE - bit stream - mod + exp
[self derEncodingGetSizeFrom:pk at:&iterator]; // Total size
iterator++; // TYPE - bit stream mod
int mod_size = [self derEncodingGetSizeFrom:pk at:&iterator];
// return [pk subdataWithRange:NSMakeRange(iterator, mod_size)];
NSData* subData=[pk subdataWithRange:NSMakeRange(iterator, mod_size)];
return [subData subdataWithRange:NSMakeRange(1, subData.length-1)];
}

CryptoExcercise Encryption/Decryption Problem

I am using apples "cryptoexcercise" (Security.Framework) in my application to encrypt and decrypt a data of numeric value. When I give the input 950,128 the values got encrypted, but it is not getting decrypted and exists with the encrypted value only. This happens only with the mentioned numeric values. Could you please check this issue and give the solution to solve this problem?
here is my code
(void)testAsymmetricEncryptionAndDecryption {
uint8_t *plainBuffer; uint8_t *cipherBuffer; uint8_t *decryptedBuffer;
const char inputString[] = "950"; int len = strlen(inputString);
if (len > BUFFER_SIZE) len = BUFFER_SIZE-1;
plainBuffer = (uint8_t *)calloc(BUFFER_SIZE, sizeof(uint8_t)); cipherBuffer = (uint8_t *)calloc(CIPHER_BUFFER_SIZE, sizeof(uint8_t)); decryptedBuffer = (uint8_t *)calloc(BUFFER_SIZE, sizeof(uint8_t));
strncpy( (char *)plainBuffer, inputString, len);
NSLog(#"plain text : %s", plainBuffer);
[self encryptWithPublicKey:(UInt8 *)plainBuffer cipherBuffer:cipherBuffer];
NSLog(#"encrypted data: %s", cipherBuffer);
[self decryptWithPrivateKey:cipherBuffer plainBuffer:decryptedBuffer];
NSLog(#"decrypted data: %s", decryptedBuffer);
free(plainBuffer); free(cipherBuffer); free(decryptedBuffer); }
(void)encryptWithPublicKey:(uint8_t *)plainBuffer cipherBuffer:(uint8_t *)cipherBuffer {
OSStatus status = noErr;
size_t plainBufferSize = strlen((char *)plainBuffer); size_t cipherBufferSize = CIPHER_BUFFER_SIZE;
NSLog(#"SecKeyGetBlockSize() public = %d", SecKeyGetBlockSize([self getPublicKeyRef])); // Error handling // Encrypt using the public. status = SecKeyEncrypt([self getPublicKeyRef], PADDING, plainBuffer, plainBufferSize, &cipherBuffer[0], &cipherBufferSize ); NSLog(#"encryption result code: %d (size: %d)", status, cipherBufferSize); NSLog(#"encrypted text: %s", cipherBuffer); }
(void)decryptWithPrivateKey:(uint8_t *)cipherBuffer plainBuffer:(uint8_t *)plainBuffer { OSStatus status = noErr;
size_t cipherBufferSize = strlen((char *)cipherBuffer);
NSLog(#"decryptWithPrivateKey: length of buffer: %d", BUFFER_SIZE); NSLog(#"decryptWithPrivateKey: length of input: %d", cipherBufferSize);
// DECRYPTION size_t plainBufferSize = BUFFER_SIZE;
// Error handling status = SecKeyDecrypt([self getPrivateKeyRef], PADDING, &cipherBuffer[0], cipherBufferSize, &plainBuffer[0], &plainBufferSize ); NSLog(#"decryption result code: %d (size: %d)", status, plainBufferSize); NSLog(#"FINAL decrypted text: %s", plainBuffer);
}
(SecKeyRef)getPublicKeyRef { OSStatus sanityCheck = noErr; SecKeyRef publicKeyReference = NULL;
if (publicKeyRef == NULL) { NSMutableDictionary *queryPublicKey = [[NSMutableDictionary alloc] init];
// Set the public key query dictionary.
[queryPublicKey setObject:(id)kSecClassKey forKey:(id)kSecClass];
[queryPublicKey setObject:publicTag forKey:(id)kSecAttrApplicationTag];
[queryPublicKey setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef];
// Get the key.
sanityCheck = SecItemCopyMatching((CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKeyReference);
if (sanityCheck != noErr)
{
publicKeyReference = NULL;
}
[queryPublicKey release];
} else { publicKeyReference = publicKeyRef; }
return publicKeyReference; }
(SecKeyRef)getPrivateKeyRef { OSStatus resultCode = noErr; SecKeyRef privateKeyReference = NULL;
if(privateKeyRef == NULL) { NSMutableDictionary * queryPrivateKey = [[NSMutableDictionary alloc] init];
// Set the private key query dictionary.
[queryPrivateKey setObject:(id)kSecClassKey forKey:(id)kSecClass];
[queryPrivateKey setObject:privateTag forKey:(id)kSecAttrApplicationTag];
[queryPrivateKey setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
[queryPrivateKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef];
// Get the key.
resultCode = SecItemCopyMatching((CFDictionaryRef)queryPrivateKey, (CFTypeRef *)&privateKeyReference);
NSLog(#"getPrivateKey: result code: %d", resultCode);
if(resultCode != noErr)
{
privateKeyReference = NULL;
}
[queryPrivateKey release];
} else { privateKeyReference = privateKeyRef; }
return privateKeyReference; }
I am sorry for the late reply... but your example worked perfectly for me, except the fact,
1) for privateTag and publicTag I had to declare
NSData *privateTag = [NSData dataWithBytes:privateKeyIdentifier length:strlen((const char *)privateKeyIdentifier)];
NSData *publicTag = [NSData dataWithBytes:publicKeyIdentifier length:strlen((const char *)privateKeyIdentifier)];
2) and also changing privateKey == NULL rather than privateKeyRef ==NULL in the key reference IF condition..

Converting Raw RSA Key value to SecKeyRef Object for Encryption

I have a RSa publicKey value in base64 , how do i convert to SecKeyRef Object without adding to Keychain
Can i add a RSA Raw value to Keychain which is not in X509 format ???
thanks in advance
The following code comes from Apple's CryptoExercise example, in SecKeyWrapper.m. It assumes the "publicKey" NSData object is the binary DER-encoded ASN.1 object, not base-64 encoded. So you'll have to get a base-64 decoder and apply it first. You might also want to read this post in the Apple Developer Forums.
- (SecKeyRef)addPeerPublicKey:(NSString *)peerName keyBits:(NSData *)publicKey {
OSStatus sanityCheck = noErr;
SecKeyRef peerKeyRef = NULL;
CFTypeRef persistPeer = NULL;
LOGGING_FACILITY( peerName != nil, #"Peer name parameter is nil." );
LOGGING_FACILITY( publicKey != nil, #"Public key parameter is nil." );
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:publicKey forKey:(id)kSecValueData];
[peerPublicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnPersistentRef];
sanityCheck = SecItemAdd((CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef *)&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.
LOGGING_FACILITY1( sanityCheck == noErr || sanityCheck == errSecDuplicateItem, #"Problem adding the peer public key to the keychain, OSStatus == %d.", sanityCheck );
if (persistPeer) {
peerKeyRef = [self getKeyRefWithPersistentKeyRef:persistPeer];
} else {
[peerPublicKeyAttr removeObjectForKey:(id)kSecValueData];
[peerPublicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef];
// Let's retry a different way.
sanityCheck = SecItemCopyMatching((CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef *)&peerKeyRef);
}
LOGGING_FACILITY1( sanityCheck == noErr && peerKeyRef != NULL, #"Problem acquiring reference to the public key, OSStatus == %d.", sanityCheck );
[peerTag release];
[peerPublicKeyAttr release];
if (persistPeer) CFRelease(persistPeer);
return peerKeyRef;
}
In case someone comes across this question and is looking for the Cocoa answer:
NSData *privateKeyPEMData = [privateKeyPEM dataUsingEncoding:NSUTF8StringEncoding];
CFArrayRef imported = NULL;
SecKeychainRef importedKeychain = NULL;
OSStatus err = 0;
SecExternalFormat format = kSecFormatOpenSSL;
SecKeyRef privateKey = NULL;
[privateKeyString dataUsingEncoding:NSUTF8StringEncoding];
err = SecItemImport((__bridge CFDataRef)(privateKeyPEMData), (CFStringRef)#"pem", &format, NULL, kNilOptions, kNilOptions, importedKeychain, &imported);
NSLog(#"%# ERROR: %#", self.class, [NSError errorWithDomain:NSOSStatusErrorDomain code:err userInfo:nil]);
assert(err == errSecSuccess);
assert(CFArrayGetCount(imported) == 1);
privateKey = (SecKeyRef)CFArrayGetValueAtIndex(imported, 0);