1
votes

I have a exponent and a modulus. How do i encrypt a NSString using RSA algorithm. I have gone through many forums. But still find it confusing. Can anyone give me the right way to encrypt a NSString using RSA algorithm with the exponent and modulus?

I currently try this. But still get a wrong encrypted string

publicTag = [self PublicKeyItems];
SecKeyRef publicKeyData = [self getPublicKeyRef];

NSString* result = (NSString*)[self encryptRSA:@"Shob" key:publicKeyData];

And the following implementations

- (NSData *)PublicKeyItems
{
    NSMutableArray *publicarray = [[NSMutableArray alloc] init];
    [publicarray addObject:encryptionExponent];
    [publicarray addObject:encryptionModulus];
    NSData *testData = [publicarray berData];
    NSLog(@"testdata = %@",testData);
    return testData;
}

-(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 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: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");
}
//  [privateKeyAttr release];
//  [publicKeyAttr release];
//  [keyPairAttr release];
}

-(NSString *)encryptRSA:(NSString *)plainTextString key:(SecKeyRef)publicKeyNext {
size_t cipherBufferSize = SecKeyGetBlockSize(publicKeyNext);
uint8_t *cipherBuffer = malloc(cipherBufferSize);
uint8_t *nonce = (uint8_t *)[plainTextString UTF8String];
SecKeyEncrypt(publicKeyNext,
              kSecPaddingOAEP,
              nonce,
              strlen( (char*)nonce ),
              &cipherBuffer[0],
              &cipherBufferSize);
NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:cipherBufferSize];
NSString* encryptedString       =   [NSString stringWithFormat:@"%@",encryptedData];
return encryptedString;
}
1
What if you use [testPubKey bytes] instead? - Till
That really is just a stab in the dark, hence a comment.... You are providing the NSData object as a whole. I would definitely try providing the raw data it wraps instead (aka using bytes) when calling your encryptRSA... implementation. - Till

1 Answers

0
votes

The easy way

Use Chilkat iOS RSA Library. One major downside: cost $189! :O

The hard way

Parse the XML, use SCZ-BasicEncodingRules-iOS to generate a public key data out of the modulus and exponent. If that works, create a dummy keychain using that public key (follow sample code here), extract the public key now in SecKeyRef format and pass it to the encryptRSA method in the question. Finally, cleanup, remove the dummy keychain. Sounds good in theory, but I have never tested this thoroughly, if you do, let me know!