I'm trying to encrypt a piece of text with RSA using a public key.
This is the code so far:
//EncViewController.h
#import <UIKit/UIKit.h>
@interface EncViewController : UIViewController
{
SecKeyRef publicKey;
NSData *publicTag;
}
- (void)encryptWithPublicKey:(uint8_t *)plainBuffer cipherBuffer:(uint8_t *)cipherBuffer;
- (SecKeyRef)getPublicKeyRef;
@end
And the implementation file:
#import "EncViewController.h"
UInt8 privateKeyIdentifier[] = "-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEowIBAAKCAQEAqRU6LMhcarK6sgaTgpPEgldUbyBsszsKKpSCDoYqH8fNDpin\n"
"puYhgR/NDurrZ6t1n3AsyACmmEMbkaxbjJ4Ee8U3zXy3dsbhsshaGWdktlfIipUw\n"
"4b+ybi4M3T/AcKHSonWw6NWKPLmA/R5nARQMg4tIlRQF6qQPlBaVxk1kHE5NEKxz\n"
"JaCC01ODsFHEAglDaEMZtGvjGl/hLxI8nqhgLgQsQpU+5ysM4/cmjgqVrU8YzFHp\n"
"9oMGWdcgQhZR3oJxdrWPn7/Vs5gWKuO6369Pc2kMLv8Tba64uAkNYMQXnMNM+TFy\n"
"DzNGOAUHkHS70pntrnufsGb8/hRv5nEcZxfd6QIDAQABAoIBAGdUfKfvjmL6dRPk\n"
"5vLuwTHykrwS8bsawpzBAzZDEa04Wn2oFxTtIN6bg6KxOEmzw/86+3MCyszUfh2p\n"
"Wo116EGHhhHDPQ+OfVHYFQ/fWvIAdaMTh7r+ftnMtLnlgwKSMnpsOEAieAeiSkzl\n"
"7ob/LKKbVTEd+nup5YdXwhJdK2gMB1xFLURYi3/ziNXXAb/MxUkldB0B9ZOdDa6Y\n"
"Ezh1HD2KT3PedZOGuHfXoU2yDi10KeXFjoN6KsOwEJJmicJ1KWevuzYr5zBvZC2N\n"
"xy6CUHp9iDQONdem1C1cMg/ht4QZpR0Rrz2wRvOxjwUfXd0qel3tBMttHiitRS4u\n"
"sCF3YwECgYEA3Jj94d1kb0XM5k6y5eS/DODBW+QRI2JRudoQOCnrMnNNYdv6KHvO\n"
"WfmIDXyw4gi//5NoEDcNf6BPgb487ImXB4AcjMOI0Ox0vNhH300yKbYHF9XgkrvI\n"
"1aCwE/4QvyBb4zLdt/QxYVxJU9qRC5CsSlqjpsqUBvMhH5mb5DdlMckCgYEAxDfP\n"
"pFOYHRYYCYDj+Plldf6Z9wSbfp7mOm7j2VvXMgVAlG1HixIcXW10GG0vq3Obpl4Z\n"
"Li8bik4aX9pN/rRGEgZxNbOc92QkzwkNO00W4L2yHdwD5ONXT8IB8KW7uq3BILld\n"
"nPm3H9lR+eoLYCbGBJVVAux43uFJHmip8dSKWyECgYAyAxV8AX9losODa1Avwp51\n"
"wvbTaG9iQEYbBo8qzIYgF/fxObgLOZZc26+2rxBDDozI2ph7JKAQ0T11QrX5QnBV\n"
"KPxQBXydMR5+OeKBg7TdtAEDrF+PpLcxh46j2bPeQO3UIpIVxGz1j8CoHCNKJfCJ\n"
"oub7R24r7S8TRPYM1WpB0QKBgBgepC+W9wPcS2gfp+ZbAdXXTiXHMzYFYlecefWm\n"
"DHXhn2afaEP4HfR+F99IzKtOsrtopb+/mqsNnsBZnWzJzDM7B3+KbKkcbknk2vOH\n"
"LmDB8Lsq6G+iYoEzX/ms5b60zSCwqIk7SP9pP2JxGqTfH0hA8wpA9zquhsZuJzXK\n"
"4pcBAoGBAKDJhWP7pM66jrSuxX8+dOlQpb+u6oRkcwEFLEXP7Blz45MJVGGAdjCj\n"
"hYgz9bg5pNywBiwE1MbBDw/CZejcQk5CgSY0AfDqsBRipHJ7N7KR8aZfpJi4JSgy\n"
"c5qnAC1sBY/zDjERsOX0CJQfumr5/ae9y637ezvDXVkHcIoNjRxx\n"
"-----END RSA PRIVATE KEY-----";
SecKeyRef privateKey;
NSData *privateTag;
const size_t BUFFER_SIZE = 64;
const size_t CIPHER_BUFFER_SIZE = 1024;
size_t FINAL_CIPHER_BUFFER_SIZE;
const uint32_t PADDING = kSecPaddingPKCS1;
UInt8 publicKeyIdentifier[] = "-----BEGIN PUBLIC KEY-----\n"
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqRU6LMhcarK6sgaTgpPE\n"
"gldUbyBsszsKKpSCDoYqH8fNDpinpuYhgR/NDurrZ6t1n3AsyACmmEMbkaxbjJ4E\n"
"e8U3zXy3dsbhsshaGWdktlfIipUw4b+ybi4M3T/AcKHSonWw6NWKPLmA/R5nARQM\n"
"g4tIlRQF6qQPlBaVxk1kHE5NEKxzJaCC01ODsFHEAglDaEMZtGvjGl/hLxI8nqhg\n"
"LgQsQpU+5ysM4/cmjgqVrU8YzFHp9oMGWdcgQhZR3oJxdrWPn7/Vs5gWKuO6369P\n"
"c2kMLv8Tba64uAkNYMQXnMNM+TFyDzNGOAUHkHS70pntrnufsGb8/hRv5nEcZxfd\n"
"6QIDAQAB\n"
"-----END PUBLIC KEY-----\n";
@interface EncViewController ()
@end
@implementation EncViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
- (void)viewDidLoad
{
[super viewDidLoad];
privateTag = [[NSData alloc] initWithBytes:privateKeyIdentifier length:sizeof(privateKeyIdentifier)];
publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
const char *plainBuffer;
const char *cipherBuffer;
NSString *textToEncrypt = @"super secret text";
//const char inputString[] = "How to Encrypt data with public key and Decrypt data with private key";
int len = strlen(textToEncrypt.UTF8String);
// TODO: this is a hack since i know inputString length will be less than BUFFER_SIZE
if (len > BUFFER_SIZE) len = BUFFER_SIZE-1;
plainBuffer = calloc(BUFFER_SIZE, sizeof(uint8_t));
cipherBuffer = calloc(CIPHER_BUFFER_SIZE, sizeof(uint8_t));
plainBuffer = [textToEncrypt UTF8String];
NSLog(@"init() plainBuffer: %s", plainBuffer);
[self encryptWithPublicKey:plainBuffer cipherBuffer:cipherBuffer];
NSLog(@"encrypted data: %s", cipherBuffer);
const char *d = cipherBuffer;
int l = strlen(d);
NSLog(@"final length: %d",l);
NSData *encodeData = [[NSData alloc] initWithBytes:cipherBuffer length:FINAL_CIPHER_BUFFER_SIZE];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachePath = [paths objectAtIndex:0];
NSLog(@"cache dir: %@",cachePath);
BOOL written = [encodeData writeToFile:[NSString stringWithFormat:@"%@%@",cachePath,@"/test.txt"] atomically:NO];
NSLog(@"File was writtend: %d",written);
NSString *base64String = [encodeData base64EncodedStringWithOptions:0];
NSLog(@"Encode String Value: %@", base64String);
free(plainBuffer);
free(cipherBuffer);
}
- (NSString *)encryptText:(NSString *)textToEncrypt
{
uint8_t *plainBuffer;
uint8_t *cipherBuffer;
const char *input = [textToEncrypt UTF8String];
int len = strlen(input);
plainBuffer = (uint8_t *)calloc(len, sizeof(uint8_t));
cipherBuffer = (uint8_t *)calloc(CIPHER_BUFFER_SIZE, sizeof(uint8_t));
strncpy( (char *)plainBuffer, input, len);
NSLog(@"init() plainBuffer: %s", plainBuffer);
//NSLog(@"init(): sizeof(plainBuffer): %d", sizeof(plainBuffer));
[self encryptWithPublicKey:(UInt8 *)plainBuffer cipherBuffer:cipherBuffer];
NSLog(@"encrypted data: %s", cipherBuffer);
NSString *s = [NSString stringWithUTF8String:(char *)cipherBuffer];
NSLog(@"encrypted nsstring %@",s);
NSData *data = [[NSData alloc] initWithBytes:cipherBuffer length:sizeof(cipherBuffer)];
NSLog(@"====== /second test =======================================");
free(plainBuffer);
//free(cipherBuffer);
return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
/* Borrowed from:
* https://developer.apple.com/library/mac/#documentation/security/conceptual/CertKeyTrustProgGuide/iPhone_Tasks/iPhone_Tasks.html
*/
- (void)encryptWithPublicKey:(uint8_t *)plainBuffer cipherBuffer:(uint8_t *)cipherBuffer
{
NSLog(@"== encryptWithPublicKey()");
OSStatus status = noErr;
NSLog(@"** original plain text 0: %s", plainBuffer);
size_t plainBufferSize = strlen((char *)plainBuffer);
FINAL_CIPHER_BUFFER_SIZE = CIPHER_BUFFER_SIZE;
NSLog(@"SecKeyGetBlockSize() public = %lu", SecKeyGetBlockSize([self getPublicKeyRef]));
// Error handling
// Encrypt using the public.
status = SecKeyEncrypt([self getPublicKeyRef],
PADDING,
plainBuffer,
plainBufferSize,
&cipherBuffer[0],
&FINAL_CIPHER_BUFFER_SIZE
);
NSLog(@"encryption result code: %ld (size: %lu)", status, FINAL_CIPHER_BUFFER_SIZE);
NSLog(@"encrypted text: %s", cipherBuffer);
}
-(SecKeyRef)getPublicKeyRef {
OSStatus sanityCheck = noErr;
SecKeyRef publicKeyReference = NULL;
if (publicKeyReference == NULL) {
[self generateKeyPair:512];
NSMutableDictionary *queryPublicKey = [[NSMutableDictionary alloc] init];
// Set the public key query dictionary.
[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];
[queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef];
// Get the key.
sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKeyReference);
if (sanityCheck != noErr)
{
publicKeyReference = NULL;
}
// [queryPublicKey release];
} else {
publicKeyReference = publicKey;
}
return publicKeyReference;
}
- (void)generateKeyPair:(NSUInteger)keySize {
OSStatus sanityCheck = noErr;
publicKey = NULL;
privateKey = NULL;
// LOGGING_FACILITY1( keySize == 512 || keySize == 1024 || keySize == 2048, @"%d is an invalid and unsupported key size.", keySize );
// First delete current keys.
// [self deleteAsymmetricKeys];
// Container dictionaries.
NSMutableDictionary * privateKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary * publicKeyAttr = [[NSMutableDictionary alloc] init];
NSMutableDictionary * keyPairAttr = [[NSMutableDictionary alloc] init];
// Set top level dictionary for the keypair.
[keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
[keyPairAttr setObject:[NSNumber numberWithUnsignedInteger:keySize] forKey:(__bridge id)kSecAttrKeySizeInBits];
// Set the private key dictionary.
[privateKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
[privateKeyAttr setObject:privateTag forKey:(__bridge id)kSecAttrApplicationTag];
// See SecKey.h to set other flag values.
// Set the public key dictionary.
[publicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecAttrIsPermanent];
[publicKeyAttr setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
// See SecKey.h to set other flag values.
// Set attributes to top level dictionary.
[keyPairAttr setObject:privateKeyAttr forKey:(__bridge id)kSecPrivateKeyAttrs];
[keyPairAttr setObject:publicKeyAttr forKey:(__bridge id)kSecPublicKeyAttrs];
// SecKeyGeneratePair returns the SecKeyRefs just for educational purposes.
sanityCheck = SecKeyGeneratePair((__bridge CFDictionaryRef)keyPairAttr, &publicKey, &privateKey);
// LOGGING_FACILITY( sanityCheck == noErr && publicKey != NULL && privateKey != NULL, @"Something really bad went wrong with generating the key pair." );
if(sanityCheck == noErr && publicKey != NULL && privateKey != NULL)
{
NSLog(@"Successful");
}
}
@end
Afterwards I'm trying to decrypt the generated encrypted file (test.txt) using the following command from terminal:
cat test.txt | openssl rsautl -pkcs -decrypt -inkey private.pem which should output my decrypted message
but I get instead the following error:
RSA operation error
15328:error:0407106B:rsa routines:RSA_padding_check_PKCS1_type_2:block type is not 02:/SourceCache/OpenSSL098/OpenSSL098-50/src/crypto/rsa/rsa_pk1.c:190:
15328:error:04065072:rsa routines:RSA_EAY_PRIVATE_DECRYPT:padding check failed:/SourceCache/OpenSSL098/OpenSSL098-50/src/crypto/rsa/rsa_eay.c:614:
I don't get why since I use the same padding both for encryption in xcode and for decryption using the openssl command...