Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

chrono1081

macrumors G3
Original poster
Jan 26, 2008
8,811
5,684
Isla Nublar
Hi guys,

I've been wracking my brain for weeks on RSA encryption and it turns out the key I had isn't the key at all, its an exponent and I need to use the exponent and modulus I have to generate a key, however it doesn't seem (from what I've found) that Apple has a way of doing that in iOS.

Does anyone happen to know if indeed it does or how I would go about doing this? Any help is hugely appreciated.
 
I use openssl for this because the Apple APIs didn't provide a way to do that.
Also at the time I had to implement this Apple's APIs did not support OAEP padding which is what the .net code that was decrypting this was expecting.

This code is pre-ARC and RSAPublic key is just a class that contains NSData for the modulus and exponent. The modulus and exponent in my case are provided in string format from .net and I base64 decode them to get my NSData.

It uses the crypto library from openssl.

Code:
+ (NSData *)RSAEncryptDataWithKey:(RSAPublicKey *)rsaPublicKey plainText:(NSData *)plainText error:(NSError **)anError
{
    BIGNUM * bn_mod = NULL;
    BIGNUM * bn_exp = NULL;
  
    // Convert to modulus and exponent to BIG.
    bn_mod = BN_bin2bn([rsaPublicKey.modulus bytes], (int)[rsaPublicKey.modulus length], NULL);
    bn_exp = BN_bin2bn([rsaPublicKey.exponent bytes], (int)[rsaPublicKey.exponent length], NULL);
  
    // Create a new RSA key.
    RSA *rsaKey = RSA_new();
    if (rsaKey == NULL)
    {
        if (anError != NULL)
        {
            unsigned long opensslError = ERR_peek_last_error();
            *anError = [ErrorUtil errorWithUnderlyingCategory:@"openssl" underlyingErrorCode:opensslError category:@"Encryption" errorCode:-1 description:@"RSA_new failed"];
        }
      
        return nil;
    }
  
    // Assign the modulus.
    rsaKey->n = bn_mod;
    // Assign the exponent.
    rsaKey->e = bn_exp;
    rsaKey->d = NULL;
    rsaKey->p = NULL;
    rsaKey->q = NULL;
  
    // Calculate the length of the cipher text.
    int maxRsaSize = RSA_size(rsaKey);
  
    // Create a NSMutableData with the calculated size.
    NSMutableData *cipherData = [[[NSMutableData alloc] initWithLength:maxRsaSize] autorelease];
    if (cipherData == nil)
    {
        if (anError != NULL)
        {
            *anError = [ErrorUtil errorWithCategory:@"Memory" errorCode:-1 description:@"NSMutableData initWithLength failed"];
        }
        RSA_free(rsaKey);
        return nil;
    }
  
    // Encrypt the plain text using RSA public encryption using the passed in Key. Use OAEP padding because thats what the .net side expects.
    int ret = RSA_public_encrypt((int)[plainText length], (unsigned char*)[plainText bytes], [cipherData mutableBytes], rsaKey, RSA_PKCS1_OAEP_PADDING);
    if (ret == -1)
    {
        if (anError != NULL)
        {
            unsigned long opensslError = ERR_peek_last_error();
            *anError = [ErrorUtil errorWithUnderlyingCategory:@"openssl" underlyingErrorCode:opensslError category:@"Encryption" errorCode:ret description:@"RSA_public_encrypt failed"];
        }
      
        RSA_free(rsaKey);
        return nil;
    }
  
    // Free the RSA key.
    RSA_free(rsaKey);
  
    return cipherData;
}
 
  • Like
Reactions: chrono1081
I use openssl for this because the Apple APIs didn't provide a way to do that.
Also at the time I had to implement this Apple's APIs did not support OAEP padding which is what the .net code that was decrypting this was expecting.

This code is pre-ARC and RSAPublic key is just a class that contains NSData for the modulus and exponent. The modulus and exponent in my case are provided in string format from .net and I base64 decode them to get my NSData.

It uses the crypto library from openssl.

Code:
+ (NSData *)RSAEncryptDataWithKey:(RSAPublicKey *)rsaPublicKey plainText:(NSData *)plainText error:(NSError **)anError
{
    BIGNUM * bn_mod = NULL;
    BIGNUM * bn_exp = NULL;
 
    // Convert to modulus and exponent to BIG.
    bn_mod = BN_bin2bn([rsaPublicKey.modulus bytes], (int)[rsaPublicKey.modulus length], NULL);
    bn_exp = BN_bin2bn([rsaPublicKey.exponent bytes], (int)[rsaPublicKey.exponent length], NULL);
 
    // Create a new RSA key.
    RSA *rsaKey = RSA_new();
    if (rsaKey == NULL)
    {
        if (anError != NULL)
        {
            unsigned long opensslError = ERR_peek_last_error();
            *anError = [ErrorUtil errorWithUnderlyingCategory:@"openssl" underlyingErrorCode:opensslError category:@"Encryption" errorCode:-1 description:@"RSA_new failed"];
        }
     
        return nil;
    }
 
    // Assign the modulus.
    rsaKey->n = bn_mod;
    // Assign the exponent.
    rsaKey->e = bn_exp;
    rsaKey->d = NULL;
    rsaKey->p = NULL;
    rsaKey->q = NULL;
 
    // Calculate the length of the cipher text.
    int maxRsaSize = RSA_size(rsaKey);
 
    // Create a NSMutableData with the calculated size.
    NSMutableData *cipherData = [[[NSMutableData alloc] initWithLength:maxRsaSize] autorelease];
    if (cipherData == nil)
    {
        if (anError != NULL)
        {
            *anError = [ErrorUtil errorWithCategory:@"Memory" errorCode:-1 description:@"NSMutableData initWithLength failed"];
        }
        RSA_free(rsaKey);
        return nil;
    }
 
    // Encrypt the plain text using RSA public encryption using the passed in Key. Use OAEP padding because thats what the .net side expects.
    int ret = RSA_public_encrypt((int)[plainText length], (unsigned char*)[plainText bytes], [cipherData mutableBytes], rsaKey, RSA_PKCS1_OAEP_PADDING);
    if (ret == -1)
    {
        if (anError != NULL)
        {
            unsigned long opensslError = ERR_peek_last_error();
            *anError = [ErrorUtil errorWithUnderlyingCategory:@"openssl" underlyingErrorCode:opensslError category:@"Encryption" errorCode:ret description:@"RSA_public_encrypt failed"];
        }
     
        RSA_free(rsaKey);
        return nil;
    }
 
    // Free the RSA key.
    RSA_free(rsaKey);
 
    return cipherData;
}


Thanks so much! I'll give this a try.
I wonder why Apple doesn't have an easier way to do this.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.