4
votes

My requirements are:

Requirement 1: Share public key to java server.

Steps:

  1. Generate public-private keys in iOS app.
  2. Store the generated keys in keychain.
  3. Send generated public key to java server.
  4. Java server shall be able to store shared public key in database.

Requirement 2: Store public key sent by java server.

Steps:

  1. Java server sends public key of other user.
  2. Process data sent by java server and generate public key from it.
  3. Store generated key in keychain, which can be later retrieved for encrypting message to be transferred.

I am able to achieve steps 1-2 in requirement 1 by using below method defined in SecKeyWrapper class (CommonCrypto sample):

- (void)generateKeyPair:(NSUInteger)keySize

Question 1: Now problem is- how shall I send that key to java server?

We have getPublicKeyBits method in the same class, which returns an NSData object, on some googling I found that it is in DER encoded format.

Question 2: If I send the same NSData object to server, which I guess it will interpret as ByteBuffer object, will it be possible for other devices, in my case it could be android, to interpret that data?

Question 3: What is the best way to share public key in above scenarios?

This is what I am trying to achieve from some days now:

Approach #1: Trying to generate public key from exponent and modulus

Android End

  1. Generated public and private key at an android device (using an openssl wrapper)
  2. Got modulus and exponent from the generated public key

iOS End

  1. Generated public key from modulus and exponent, at ios end, using code specified in this link: https://stackoverflow.com/a/10643962/217586
  2. Converted some sample string to an object of NSData using NSUTF8StringEncoding
  3. Used - wrapSymmetricKey:keyRef: method defined in SecKeyWrapper class (CryptoExercise example) for encryption, and passed key obtained from step 1 and data to encrypt obtained from step 2 to it
  4. Converted NSData (encrypted data) obtained in previous step to base64encoded string, shared the same to android guy

Android End

  1. Tried to decrypt the base64encoded string, using related private key

Problem:

getting error - too much data for RSA block

Approach #2: (Got to know from this link that - https://github.com/superwills/iOSRSAPublicKeyEncryption, we are not supposed to load public keys in iOS from anything other than a certificate, so tried a different approach)

Terminal End

  1. Generated certificate using openssl commands specified in this url: https://stackoverflow.com/a/17295321/217586

iOS End

  1. Obtained public key as specified in above url
  2. Used below code to encrypt the data:

    SecKeyWrapper *secKeyWrapper = [SecKeyWrapper sharedWrapper]; SecKeyRef obtainedPublicKey = [secKeyWrapper getPublicKeyRefFromDerCertificate:kCertificatePath]; NSData *dataToBeEncrypted = [kStringToBeEncrypted dataUsingEncoding:NSUTF8StringEncoding]; NSData *encryptedText = [secKeyWrapper wrapSymmetricKey:dataToBeEncrypted keyRef:obtainedPublicKey];

  3. Converted NSData to base64encoded string

Terminal End

  1. Used below command to convert it back to original string:

    echo | openssl rsautl -decrypt -inkey rsaPrivate.pem

Problem:

getting error - rsa routines:RSA_EAY_PRIVATE_DECRYPT:data greater than mod len:/SourceCache/OpenSSL098/OpenSSL098-47.1/src/crypto/rsa/rsa_eay.c

Any suggestions?

1

1 Answers

0
votes

Your first approach is almost the same I used in a project time ago. The difference is that I was not sharing the modulus and exponent but the whole public key encoded in base 64 (without the -----BEGIN/END PUBLIC KEY----- header/footer), converting it back and forth to the appropriate classes in the end device. Basically the same concept is applied to encrypted data, always share Base64 encoded data to avoid conversion issues. So far your approach thus should be fine if you hadn't any conversion issue (and you can find issues easily by converting the public keys to its base64 representation, on both android and iOS the string should be exactly the same, otherwise something bad happened). The problem you have (getting error - too much data for RSA block) is because the text you are encrypting is too large for the key size you provided. RSA can only encrypt messages that are several bytes shorter than the modulus of the key pair thus the error. What you should be doing is, generate a one-time encryption symmetric key used to encrypt/decrypt the data, exchange the data encrypted with the symmetric key and the key encrypted using RSA. This is how roughly any correctly designed RSA encryption scheme works.

Anyway I think that if you try your first approach with a shorter fixed string you should observe that the first approach is probably working (unless you implemented things wrong, as you explained are theoretically correct but is hard to tell without seeing some code).

Antonio