Question

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...

Était-ce utile?

La solution

It turned out that's quite tricky to handle keys using chars.

It's much easier to use .DER format of the public key/certificate, as CommonCrypto supports it already. I solved my problem using the .DER directly. You can load it like this:

SecCertificateRef certificate = SecCertificateCreateWithData(kCFAllocatorDefault, ( __bridge CFDataRef)publicKeyFileContent);

where publicKeyFileContent is an NSData instance containing your .DER content.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top