{"id":42,"date":"2010-07-11T14:01:16","date_gmt":"2010-07-11T04:01:16","guid":{"rendered":"http:\/\/blog.wingsofhermes.org\/?p=42"},"modified":"2015-02-25T15:54:11","modified_gmt":"2015-02-25T05:54:11","slug":"importing-an-iphone-rsa-public-key-into-a-java-app","status":"publish","type":"post","link":"https:\/\/blog.wingsofhermes.org\/?p=42","title":{"rendered":"Importing an iPhone RSA public key into a Java app"},"content":{"rendered":"<p style=\"clear: both;\">I&#8217;ve spent the last two days working through this &#8211; and couldn&#8217;t find any easy code at all on the net. So to save others the time here is what I found.<\/p>\n<p style=\"clear: both;\">First off, when you export a key from the iPhone keychain, it&#8217;s exported in a cut down format &#8211; just the public key and exponent without any of the other ASN.1 stuff you&#8217;d expect in a fully encoded public key. The java crypto functions generally expect a fully encoded key (OID and all). So I quickly whipped up some Objective C code to take the exported key and expand it out to a fully interoperable key in the X.509 format.<\/p>\n<p style=\"clear: both;\">I&#8217;m darn sure there is an easier way to do this, I just couldn&#8217;t for the life of me find it. Please let me know what I&#8217;ve missed or any bugs\/errors\/plain sillies in the attached following code<\/p>\n<p style=\"clear: both;\">First off a simple function to encode ASN.1 length fields:<\/p>\n<pre style=\"clear: both;\"><code>\/\/ Helper function for ASN.1 encoding\r\n\r\nsize_t encodeLength(unsigned char * buf, size_t length) {\r\n\r\n    \/\/ encode length in ASN.1 DER format\r\n    if (length &lt; 128) {\r\n        buf[0] = length;\r\n        return 1;\r\n    }\r\n\r\n    size_t i = (length \/ 256) + 1;\r\n    buf[0] = i + 0x80;\r\n    for (size_t j = 0 ; j &lt; i; ++j) {         buf[i - j] = length &amp; 0xFF;         length = length &gt;&gt; 8;\r\n    }\r\n\r\n    return i + 1;\r\n}\r\n\r\n<\/code><\/pre>\n<p style=\"clear: both;\">OK &#8211; with that in place, some code to actually do the encoding. The following is a full copy of a function from something I&#8217;m working on. The <strong>Base64<\/strong> class is a very simple encoding\/decoding class I built.<\/p>\n<pre style=\"clear: both;\"><code>\r\n#define _MY_PUBLIC_KEY_TAG \"my_key_identifier\"\r\n\r\n- (NSString *) getRSAPublicKeyAsBase64 {\r\n\r\n    static const unsigned char _encodedRSAEncryptionOID[15] = {\r\n\r\n        \/* Sequence of length 0xd made up of OID followed by NULL *\/\r\n        0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,\r\n        0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00\r\n\r\n    };\r\n    \r\n    NSData * publicTag =\r\n        [NSData dataWithBytes:_MY_PUBLIC_KEY_TAG\r\n                       length:strlen((const char *) _MY_PUBLIC_KEY_TAG)];\r\n\r\n    \/\/ Now lets extract the public key - build query to get bits\r\n    NSMutableDictionary * queryPublicKey =\r\n        [[NSMutableDictionary alloc] init];\r\n\r\n    [queryPublicKey setObject:(id)kSecClassKey\r\n                       forKey:(id)kSecClass];\r\n    [queryPublicKey setObject:publicTag\r\n                       forKey:(id)kSecAttrApplicationTag];\r\n    [queryPublicKey setObject:(id)kSecAttrKeyTypeRSA\r\n                       forKey:(id)kSecAttrKeyType];\r\n    [queryPublicKey setObject:[NSNumber numberWithBool:YES]\r\n                       forKey:(id)kSecReturnData];\r\n\r\n    NSData * publicKeyBits;\r\n    OSStatus err =\r\n        SecItemCopyMatching((CFDictionaryRef)queryPublicKey,\r\n                            (CFTypeRef *)&amp;publicKeyBits);\r\n\r\n    if (err != noErr) {\r\n        return nil;\r\n    }\r\n\r\n    \/\/ OK - that gives us the \"BITSTRING component of a full DER\r\n    \/\/ encoded RSA public key - we now need to build the rest\r\n\r\n    unsigned char builder[15];\r\n    NSMutableData * encKey = [[NSMutableData alloc] init];\r\n    int bitstringEncLength;\r\n\r\n    \/\/ When we get to the bitstring - how will we encode it?\r\n    if  ([publicKeyBits length ] + 1  &lt; 128 )\r\n        bitstringEncLength = 1 ;\r\n    else\r\n        bitstringEncLength = (([publicKeyBits length ] +1 ) \/ 256 ) + 2 ; \r\n\r\n    \/\/ Overall we have a sequence of a certain length\r\n    builder[0] = 0x30;    \/\/ ASN.1 encoding representing a SEQUENCE\r\n    \/\/ Build up overall size made up of -\r\n    \/\/ size of OID + size of bitstring encoding + size of actual key\r\n    size_t i = sizeof(_encodedRSAEncryptionOID) + 2 + bitstringEncLength +\r\n               [publicKeyBits length];\r\n    size_t j = encodeLength(&amp;builder[1], i);\r\n    [encKey appendBytes:builder length:j +1];\r\n\r\n    \/\/ First part of the sequence is the OID\r\n    [encKey appendBytes:_encodedRSAEncryptionOID\r\n                 length:sizeof(_encodedRSAEncryptionOID)];\r\n\r\n    \/\/ Now add the bitstring\r\n    builder[0] = 0x03;\r\n    j = encodeLength(&amp;builder[1], [publicKeyBits length] + 1);\r\n    builder[j+1] = 0x00;\r\n    [encKey appendBytes:builder length:j + 2];\r\n\r\n    \/\/ Now the actual key\r\n    [encKey appendData:publicKeyBits];\r\n\r\n    \/\/ Now translate the result to a Base64 string\r\n    Base64 * base64 = [[Base64 alloc] init];\r\n    NSString * ret = [base64 base64encode:[encKey bytes]\r\n                                   length:[encKey length]];\r\n    [base64 release];\r\n\u00a0\u00a0\u00a0 [encKey release];\r\n    return ret;\r\n}\r\n\r\n<\/code><\/pre>\n<p style=\"clear: both;\">As I said &#8211; I&#8217;m very sure there is an easier way to do this. If someone can tell me what it is I&#8217;d be most grateful!<\/p>\n<p style=\"clear: both;\">And if you need some code to import into a Java key &#8211; the following is a cut from the java app I am building. Clearly you will want to get a bit prettier on the exception handling :).<\/p>\n<pre style=\"clear: both;\"><code>        byte[] decodedPublicKey;\r\n        try {\r\n            \/\/ Now lets encrypt the nonce\r\n            decodedPublicKey = Base64.decode(d.getPublicKey());\r\n        } catch (Base64DecodingException ex) {\r\n            logger.log(Level.WARNING,\r\n               \"getDeviceInfo - error decoding public key for device:{0}\",\r\n               deviceId);\r\n            return di;\r\n        }\r\n        PublicKey publicKey;\r\n        try {\r\n            publicKey = KeyFactory.getInstance(\"RSA\").\r\n                generatePublic(new X509EncodedKeySpec(decodedPublicKey));\r\n        } catch (Exception ex) {\r\n            logger.log(Level.WARNING,\r\n               \"getDeviceInfo - error importing public key for device:{0}\",\r\n                deviceId);\r\n            return di;\r\n        }\r\n\r\n<\/code><\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve spent the last two days working through this &#8211; and couldn&#8217;t find any easy code at all on the net. So to save others the time here is what I found. First off, when you export a key from the iPhone keychain, it&#8217;s exported in a cut down format &#8211; just the public key&hellip; <span class=\"clear\"><\/span><a href=\"https:\/\/blog.wingsofhermes.org\/?p=42\" class=\"more-link read-more\" rel=\"bookmark\">Continue Reading <span class=\"screen-reader-text\">Importing an iPhone RSA public key into a Java app<\/span><i class=\"fa fa-arrow-right\"><\/i><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[13,4,16,15],"tags":[12,11],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pX0hd-G","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/blog.wingsofhermes.org\/index.php?rest_route=\/wp\/v2\/posts\/42"}],"collection":[{"href":"https:\/\/blog.wingsofhermes.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.wingsofhermes.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.wingsofhermes.org\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.wingsofhermes.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=42"}],"version-history":[{"count":10,"href":"https:\/\/blog.wingsofhermes.org\/index.php?rest_route=\/wp\/v2\/posts\/42\/revisions"}],"predecessor-version":[{"id":151,"href":"https:\/\/blog.wingsofhermes.org\/index.php?rest_route=\/wp\/v2\/posts\/42\/revisions\/151"}],"wp:attachment":[{"href":"https:\/\/blog.wingsofhermes.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=42"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.wingsofhermes.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=42"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.wingsofhermes.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=42"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}