0

I am developing an sdk for iOS 5 at work, and I am communicating with a device via a socket interface. This device requires to be sent a base64 encoded rsa x509 public key of size 2048.

I generate the key pair with the following code:

OSStatus status = noErr;
NSMutableDictionary *privateKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary *publicKeyAttr= [[NSMutableDictionary alloc] init];
NSMutableDictionary *keyPairAttr = [[NSMutableDictionary alloc] init];

NSData * publicTag = [NSData dataWithBytes:publicKeyIdentifier
                                    length:strlen((const char *)publicKeyIdentifier)];
NSData * privateTag = [NSData dataWithBytes:privateKeyIdentifier
                                     length:strlen((const char *)privateKeyIdentifier)];

SecKeyRef publicKey = NULL;
SecKeyRef privateKey = NULL;

[keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA
                forKey:(__bridge id)kSecAttrKeyType];
[keyPairAttr setObject:[NSNumber numberWithInt:2048]
                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];

status = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr,
                            &_publicKey, &_privateKey);

I then use the following code to obtain the raw data for the public key:

NSData* publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];

OSStatus sanityCheck = noErr;
NSData* publicKeyBits = nil;

NSMutableDictionary* queryPublicKey = [[NSMutableDictionary alloc] init];
[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];

// Temporarily add key to the Keychain, return as data:
NSMutableDictionary* attributes = [queryPublicKey mutableCopy];
[attributes setObject:(__bridge id)key forKey:(__bridge id)kSecValueRef];
[attributes setObject:@YES forKey:(__bridge id)kSecReturnData];
CFTypeRef result;
sanityCheck = SecItemAdd((__bridge CFDictionaryRef)attributes, &result);
if (sanityCheck == errSecSuccess) {
    publicKeyBits = CFBridgingRelease(result);

    // Remove from Keychain again:
    (void)SecItemDelete((__bridge CFDictionaryRef)queryPublicKey);
}
return publicKeyBits;

The above code yields NSData of 270 bytes long for the public key; I base64 encode this data and send it to the device, but it is rejected.

My colleague at work has completed implementation of the same functionality for android, and he generates his key pair as follows:

    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
    kpg.initialize(2048);
    KeyPair key = kpg.generateKeyPair();

And he uses:

    key.getPublic().getEncoded() 

To access the public key data, which is 294 bytes long, and which the device accepts.

Also, if I take the raw bytes of his generated public key, and use my base64 encode and send, this is also accepted by the device.

What is the difference here? Why is his key 294 bytes, while mine is 270? And how can I fix this? Any help would be much appreciated.

EDIT

I have just found https://crypto.stackexchange.com/questions/14491/why-is-a-2048-bit-public-rsa-key-represented-by-540-hexadecimal-characters-in-x, that states:

Note that this does not count the encoding that says "this is an RSA public key"; that takes up an additional 24 bytes (including overhead).

This sounds like what I need, although I don't know how to include this information.

Anyone?

Community
  • 1
  • 1
Jon Slater
  • 41
  • 4
  • Very naive observation: base 64 is 64 possibilities, i.e. 6 bits, per byte. So a 294 byte long public key is only 294*6 = 1764 bits of information. Shouldn't you need at least 342 bytes to encode a 2048 bit quantity in base 64? – Tommy Jun 04 '15 at 16:48
  • @Tommy this question has nothing to do with base64 encoding, although I do appreciate your response. – Jon Slater Jun 04 '15 at 17:01
  • Yes, I completely misread the sentence "The above code yields NSData of 270 bytes long for the public key; I base64 encode this data and send it to the device, but it is rejected." mentally to put the base64 step before the 'yields NSData of 270 bytes' step. 270 bytes clearly fits a 2048 bit key plus surrounding information. – Tommy Jun 04 '15 at 18:40
  • @DannyBravo such a good point. I approached the CEO of our multinational, and told him what you said; outraged, he changed the whole development process for our company on both sides of the atlantic. I think he also wants to offer you a job as a chief sorter outerer. – Jon Slater Jun 13 '15 at 14:37
  • @JonSlater: While I appreciate the offer, I must respectfully decline as I am quite content being self employed. It's great, really. I get to prioritize what is really important, choose what I want to work on, and I can avoid having to support an OS that was deprecated 3 years ago by Apple. Incidentally, you might want to show the CEO of your multinational the following stats that I found doing a simple google search, it might give him a good perspective on how much time and money he is spending on supporting an OS with only 1% of active users, instead of focusing on new features for the many. – Danny Bravo Jun 17 '15 at 06:44
  • https://david-smith.org/iosversionstats/ – Danny Bravo Jun 17 '15 at 06:44
  • @DannyBravo heh:) It's only banter, but more seriously, I actually do respect your comment, and I agree with you; It's just not me that makes the rules in this case (and I'm only 4 weeks into this new job). Interestingly, I used Flurry at the last place, which revealed that 0.85% of our customers were on <5.1.1. – Jon Slater Jun 17 '15 at 20:39
  • @JonSlater Thank you for clarifying this. My apologies if my comments sounded harsh, I thought you were just being stubborn. I understand now that your situation is a bit more complicated. I do believe that since developing an app takes a lot of time and effort, it pays off to maximize those efforts by focusing on what creates the biggest impact. I hope you found the solution you were looking for! – Danny Bravo Jun 21 '15 at 12:07

1 Answers1

4

Here's the answer: http://blog.wingsofhermes.org/?p=42

"First off, when you export a key from the iPhone keychain, it’s exported in a cut down format – just the public key and exponent without any of the other ASN.1 stuff you’d expect in a fully encoded public key."

I thought it was something like this; I've been smashing my head against a monitor all day..

Bloody apple.

Jon Slater
  • 41
  • 4
  • Exactly what I was looking for. Same as author I'll greatly appreciate if somebody will figure out how to do that easier. – bgplaya Nov 03 '15 at 08:39