7

I'm looking to generate a rsa public key (pem) from both the modulus and exponent in Objective-C. This function can be done in Java by the following;

PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(modulus, exponent));

Although I'm having some trouble writing this for the iOS platform. Am aware of OpenSSL, but I couldn't find a successful method and am still unable to generate this key. Also took a look at SCZ-BasicEncodingRules-iOS but this returns a NSData value and I'm stuck trying to figure out how to try convert it to a NSString.

Harry
  • 3,301
  • 7
  • 27
  • 33
  • 1. Not all `NSData` can be converted to a `NSString` (or in general not all 8-bit bytes can be converted into unicode characters. 2. Please provide a test modulus and exponent, what format are the, hex, Base62, other? – zaph Apr 16 '15 at 15:14
  • I don't usually cast a close vote using "unclear what you are asking", but this one falls into that category. What, exactly, is the problem? You can't run Java on iOS? Or you can't convert an `NSData` to an `NSString`? Also, an RSA public key ***is*** the modulus and public exponent, so its not even clear what you are trying to do. – jww Apr 19 '15 at 22:52
  • Please use this C# class from this ref: [enter link description here](https://stackoverflow.com/questions/23734792/c-sharp-export-private-public-rsa-key-from-rsacryptoserviceprovider-to-pem-strin/23739932#23739932) – Trí Chồn May 28 '18 at 00:34

1 Answers1

9

If you want to create a .PEM format you need to base64 encode the output from the berData method. You also need to add the header and footer lines.

Test data and code, see the end of the answer for bytesFromHexString:

NSString *modulusString =  @"c19bccae1e67743fab1c978f03122fb1a78ef05d565a2964728062ad0365e4751b8253df5fd13ab4ecb95c81ff17b91f969e4fb3d8274c30533338684278f6e5548027df775c055943a24a4117b0274c296c68b722c71670d4b21489a3da05d37ba06f2fb771b671a2c746bae4a049dc718fba19a75f1fb8ae1dd715b33d66a3";
NSString *exponentString = @"010001";

NSData *pubKeyModData = bytesFromHexString(modulusString);
NSData *pubKeyExpData = bytesFromHexString(exponentString);
NSArray *keyArray = @[pubKeyModData, pubKeyExpData];

//Given that you are using SCZ-BasicEncodingRules-iOS:
NSData *berData = [keyArray berData];
NSLog(@"berData:\n%@", berData);

NSString *berBase64 = [berData base64EncodedStringWithOptions:0];
NSString *preamble = @"-----BEGIN CERTIFICATE REQUEST-----";
NSString *postamble = @"-----END CERTIFICATE REQUEST-----";
NSString *pem = [NSString stringWithFormat:@"%@\n%@\n%@", preamble, berBase64, postamble];
NSLog(@"pem:\n%@", pem);

Output with test data:

berData:
30818802 8180c19b ccae1e67 743fab1c 978f0312 2fb1a78e f05d565a 29647280 62ad0365 e4751b82 53df5fd1 3ab4ecb9 5c81ff17 b91f969e 4fb3d827 4c305333 38684278 f6e55480 27df775c 055943a2 4a4117b0 274c296c 68b722c7 1670d4b2 1489a3da 05d37ba0 6f2fb771 b671a2c7 46bae4a0 49dc718f ba19a75f 1fb8ae1d d715b33d 66a30203 010001

pem:
-----BEGIN CERTIFICATE REQUEST-----
  MIGIAoGAwZvMrh5ndD+rHJePAxIvsaeO8F1WWilkcoBirQNl5HUbglPfX9E6tOy5XIH/F7kflp5Ps9gnTDBTMzhoQnj25VSAJ993XAVZQ6JKQRewJ0wpbGi3IscWcNSyFImj2gXTe6BvL7dxtnGix0a65KBJ3HGPuhmnXx+4rh3XFbM9ZqMCAwEAAQ==
-----END CERTIFICATE REQUEST-----

Convert hex-ascii to data:

NSData* bytesFromHexString(NSString * aString) {
    NSString *theString = [[aString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] componentsJoinedByString:nil];

    NSMutableData* data = [NSMutableData data];
    int idx;
    for (idx = 0; idx+2 <= theString.length; idx+=2) {
        NSRange range = NSMakeRange(idx, 2);
        NSString* hexStr = [theString substringWithRange:range];
        NSScanner* scanner = [NSScanner scannerWithString:hexStr];
        unsigned int intValue;
        if ([scanner scanHexInt:&intValue])
            [data appendBytes:&intValue length:1];
    }
    return data;
}
zaph
  • 111,848
  • 21
  • 189
  • 228
  • May I ask what test data you used in the array? More specifically, the correct format to go from a string to nsdata in this instance. – Harry Apr 16 '15 at 22:39
  • This is good, but do you know of an easy way to convert the Array to PEM format that will work in a pure Swift project (without bridging to Objective-C)? Thanks – qtyq Jan 04 '17 at 07:07
  • I have tried to do the same in swift, but it outputs wrong key size. Could you check this question? http://stackoverflow.com/questions/43637323/rsa-public-key-generation-swift – Anton Kashpor Apr 27 '17 at 08:22
  • berData function definition? – Raj Aggrawal Jun 13 '17 at 14:46
  • See [BER/CER/DER Encodings](http://www.cisco.com/c/en/us/support/docs/security/vpn-client/116039-pki-data-formats-00.pdf) *The ITU-T has defined a standard way of encoding data structures described in ASN.1 into binary data. X.690 defines **Basic Encoding Rules (BER)*** and [RSA Key Formats](https://www.cryptosys.net/pki/rsakeyformats.html) *Binary DER-encoded format. This is sometimes called ASN.1 **BER-encoded** (there is a subtle difference between BER- and DER-encodings: DER is just a stricter subset of BER)* – zaph Jun 13 '17 at 15:43
  • 2
    any swift conversion? – Milad Faridnia Jan 23 '18 at 13:08