0

I know there is a lot of questions and answers similar on here, but I have searched and cannot find one that works for me.

I have a service I want to consume in IOS (6), provided by a third party of which I have no control.

In order to authenticate with the service I need to send my user credentials as an RSA encrypted string, encrypted with their RSA public key.

They have supplied me with an XML file with the following format

<BitStrength>1024</BitStrength>
<RSAKeyValue>
<Modulus>xxxxxxxxxxxxxxxxxxxxx</Modulus>
<Exponent>xxxx</Exponent>
</RSAKeyValue>

What do I need to do in order to encrypt the string? I am from a DOTNET background so most of the complexity has been obscured for me up to now.

I have tried examples such as this: RSA implementations in Objective C but there is no way to build the objects from what I have, they seem to need a cert

i have tried using this tool to convert it to a PEM file, but again the code will not build the cert object. https://superdry.apphb.com/tools/online-rsa-key-converter

Thanks in advance for any help.

**** EDIT **** This is part of a method I have created using the examples provided, it runs without error but I cant decode the output:

   SStatus status = noErr;

size_t cipherBufferSize;
uint8_t *cipherBuffer;

// [cipherBufferSize]
size_t dataSize = [plainTextString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
const uint8_t* textData = [[plainTextString dataUsingEncoding:NSUTF8StringEncoding] bytes];

NSAssert(publicKey, @"The public key being referenced by tag must have been stored in the keychain before attempting to encrypt data using it!");

//  Allocate a buffer

cipherBufferSize = SecKeyGetBlockSize(publicKey);
// plain text block size must be 11 less than cipher buffer size because of
// the PKSC1 padding used:
const size_t blockSizeMinusPadding = cipherBufferSize - 11;
cipherBuffer = malloc(cipherBufferSize);

NSMutableData* accumulatedEncryptedData = [NSMutableData dataWithCapacity:0];

for (int ii = 0; ii*blockSizeMinusPadding < dataSize; ii++) {
    const uint8_t* dataToEncrypt = (textData+(ii*blockSizeMinusPadding));
    const size_t subsize = (((ii+1)*blockSizeMinusPadding) > dataSize) ? blockSizeMinusPadding-(((ii+1)*blockSizeMinusPadding) - dataSize) : blockSizeMinusPadding;

    // Encrypt using the public key.
    status = SecKeyEncrypt(publicKey,
                           kSecPaddingOAEP,
                           dataToEncrypt,
                           subsize,
                           cipherBuffer,
                           &cipherBufferSize
                           );

    [accumulatedEncryptedData appendBytes:cipherBuffer length:cipherBufferSize];
}

if (publicKey) CFRelease(publicKey);

free(cipherBuffer);

// return accumulatedEncryptedData; return [accumulatedEncryptedData base64EncodedString];

Community
  • 1
  • 1
Ben
  • 165
  • 2
  • 14
  • 1
    "*signed with their RSA public key*" --> You mean *encrypted*, right? – Duncan Jones Jan 30 '13 at 15:33
  • 1
    @H2CO3 You cannot sign with an RSA public key. You can either encrypt data or verify data that has already been signed with the corresponding private key. My point may have sounded pedantic, but I wanted to ensure the OP didn't respond with "Oh, sorry, I mean sign with *my* key" or similar. – Duncan Jones Jan 30 '13 at 15:40
  • 2
    @DuncanJones Okay, I see. (I'm not pedantic about others being pedantic. Correct terminology is important.) –  Jan 30 '13 at 15:41
  • Typically, one would authenticate by signing with one's own key. The service would often have provided a certificate for that key, in order to mark it as trusted. I wondered if the OP is referring to signing with his/her key. – Duncan Jones Jan 30 '13 at 15:45
  • I have updated the Q to reflect, that yes, I meant encrypted, I have been going around the bend with this one and my terms were a little mixed up! I have been asked to encrypt with their public key before I send to their service. It is a large company and as such, I am getting very little help otehr than the standard dot.net/php examples, both of which can use a modulus and exponent as input parameters – Ben Jan 30 '13 at 20:16
  • 1
    I think we require more input regarding the expected format. There are at least two encryption formats (specified in PKCS#1 v2.1) for starters, and they expect binary input - and I presume the credentials are strings or whatever. – Maarten Bodewes Jan 30 '13 at 20:32

2 Answers2

1

Get the PEM string for the public key using the converter you mentioned, or write some code to do the transformation yourself.

EDIT: Sorry, I pasted the wrong link. Changed it now: Then, Grab the code found here and use it to add the public key to the iOS keychain.

You can get the public key reference back from the keychain using the following code:

+ (SecKeyRef)copyPublicKeyForTag:(NSString*)tag
{
    SecKeyRef publicKey = NULL;

    NSData * publicTag = [NSData dataWithBytes:[tag cStringUsingEncoding:NSUTF8StringEncoding]
                                        length:[tag length]];

    NSMutableDictionary *queryPublicKey =
    [[NSMutableDictionary alloc] init];

    [queryPublicKey setObject:(id)kSecClassKey forKey:(id)kSecClass];
    [queryPublicKey setObject:publicTag forKey:(id)kSecAttrApplicationTag];
    [queryPublicKey setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
    [queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnRef];

    OSStatus status = SecItemCopyMatching
    ((CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKey);

    if (status != noErr) {
        return nil;
    }

    return publicKey;
}

Now you can use the code I wrote to encrypt data using a public key, found here. Note that I am using PKCS1 padding and you may not be. If you are, then depending on whether you want your code to work for iOS 5 or just iOS 6, the rest of the information in the blog post I just linked to will be relevant or not.

Mathew
  • 1,788
  • 15
  • 27
  • Hi, Thanks for that, I have built up a method that does (maybe) what i want, it seems to encrypt without any errors at least, but trying to decrypt it at the other end it is giving me an "Error occured while decoding OAEP padding" Would you mind just looking at the code i have attached ot the original question (I couldnt work out how to put large code blocks in a comment) and see if you can see anything obvious? – Ben Feb 01 '13 at 11:27
  • I think it may be the line const size_t blockSizeMinusPadding = cipherBufferSize - 11; do you know what this would be on IOS 6 for kSecPaddingOAEP – Ben Feb 01 '13 at 15:16
  • Are you trying to decrypt your result in iOS right away in order to verify that the encryption worked? If so, you would need to be using the private key to decrypt, not the public key you encrypted it with. – Mathew Feb 01 '13 at 18:24
  • I am using a DOTNET function to do the decrypt, and that is what is failing, and I am guessing it is to do with the length of the string I am trying to encrypt and the padding applied. Below is teh dotnet function to do an encrypt, it would seem that is also doing some voodoo programing to the chunck size, but with the number 42 where as yours is doing -11 – Ben Feb 04 '13 at 07:50
  • var maxLength = keySize - 42; //get the max length of the chunks that'll be encrypted
    var dataLength = bytes.Length; //total length of the input string in bytes
    var iterations = dataLength / maxLength; //how many chunks
    – Ben Feb 04 '13 at 07:51
  • OK. I did a little more research on OAEP because I am not familiar with it. Two things: 1) I am not entirely sure iOS supports it -- the listed options for padding are: kSecPaddingNone = 0, kSecPaddingPKCS1 = 1, kSecPaddingPKCS1MD2 = 0x8000, kSecPaddingPKCS1MD5 = 0x8001, kSecPaddingPKCS1SHA1 = 0x8002, 2) If iOS does support it, there does not appear to be a standard amount of padding that is always used like is the case for PKCS1, so you should definitely try using `42` like you found in the DOTNET encrypt function. – Mathew Feb 04 '13 at 19:02
  • I take that back. `kSecPaddingOAEP` **does** get defined in the same header as `kSecPaddingPKCS1` for iOS, so it does appear to be supported. – Mathew Feb 04 '13 at 19:06
  • Hi Guys, thanks for this, in the end we went with http://www.chilkatsoft.com/rsa-objc.asp as is was completely seamless, and for the price, I was burning more money trying to get iOS to do it natively – Ben Feb 26 '13 at 15:46
0

In the end we went with http://chilkatsoft.com/rsa-objc.asp as is was completely seamless, and for the price, I was burning more money trying to get iOS to do it natively.

It will take the modulus and exponent parts and or a cert. Mathews code did seem to work when I encrypted on IOS but never got it to decrypt on the service successfully.

Ben
  • 165
  • 2
  • 14