+ (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;
}