8

I am going to say in advance i don't know too much about cryptography (Basics only). I am trying to Implement a Credential OpenHome Service and I want to encrypt a password to send it to the device.

The device provides a function written in C that returns a public key String that looks like that:

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCzjFGuEKD0uWxzb47oRbiSP2uDwVJPeWU7m9VXi626V6lameTzdtwj2eYVZTIAsAW7yW4or2skn7oHqFG4GvhMzgMwoQjKFxeCPPFXRSotnt26AN1DhvFJp3V/d+MpmkzI07iWcD5eNe4EVNK9GSE4JOEHhJ/JYBVMiu04XE5aqwIDAQAB

The Android implementation has been already done and the specs given are

RSA/ECB/OAEPWithSHA-256AndMGF1Padding

also there is a web site that gives "instructions" when encrypting

http://wiki.openhome.org/wiki/Av:Developer:CredentialsService

I have tried so far these libraries:

SwiftyRSA, Heimdall, SwCrypt

I really thing that one of my main failures are I don't understand what I have, what do I need and finally how to achieve it using swift.

ideally at the end i will have a functions like

func encryptMessage(message:String, whithPublicKey key:String)->String

thank you very much.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Reimond Hill
  • 4,278
  • 40
  • 52
  • Not sure what your error or roadblock is! The process looks like you need to take the public key shared by the server which is in RSA using ECB block cipher and OAEP padding to generate an encrypted message of the password and send it back to the server. OAEPWithSHA-256AndMGF1Padding is quite an unusual one so just check which libraries support this. – carbonr Nov 11 '17 at 11:59
  • the public key is given by the server. So I assume the server has a private key for decypting the message. I would like to know how I can encrypt the the message with the public key provided and the with specs. – Reimond Hill Nov 11 '17 at 12:39
  • "I have tried so far these libraries..." ...and? What went wrong? Where is your code for one of these attempts? – President James K. Polk Nov 11 '17 at 13:37
  • [Using Keys for Encryption](https://developer.apple.com/documentation/security/certificate_key_and_trust_services/keys/using_keys_for_encryption) – President James K. Polk Nov 11 '17 at 13:54
  • Look at `SecKeyCreateEncryptedData` with the algorithm `rsaEncryptionOAEPSHA256`. If it works out of the box, and you understand how to use it, great. If you need more help, it's beyond what I can do in a StackOverflow answer, and may require non-trivial code on iOS (a lot of crypto algorithms are supported only on macOS). If no one else can walk you through it, and you have some budget, I'd be happy to discuss a consulting agreement. Note that the standard algo here is SHA-1, and is more broadly supported. If you can change the server, that might help you. – Rob Napier Nov 11 '17 at 15:14
  • asn1ParsingFailed is one of the errors i get – Reimond Hill Nov 11 '17 at 15:36

1 Answers1

10

After a long research i have just implemented my own solution rather than using libraries and not understanding what was going on. It is always good to know what happens and it this case it is not rocket science.

On iOS if you want to encrypt/decrypt you need to use a key stored on the keychain. If, in my case, i have been given the public key i can import it and also I can do the same with the private key. Please see my HelperClass Here.

Then, and from only from iOS 10, you can call this 2 methods for encrypting and decrypting

        let error:UnsafeMutablePointer<Unmanaged<CFError>?>? = nil
        let plainData = "A Plain text...".data(using: .utf8)
        if let encryptedMessageData:Data = SecKeyCreateEncryptedData(publicSecKey, .rsaEncryptionOAEPSHA256, plainData! as CFData,error) as Data?{
            print("We have an encrypted message")

            let encryptedMessageSigned = encryptedMessageData.map { Int8(bitPattern: $0) }
            print(encryptedMessageSigned)
            
            if let decryptedMessage:Data = SecKeyCreateDecryptedData(privateSecKey, .rsaEncryptionOAEPSHA256, encryptedMessageData as CFData,error) as Data?{
                print("We have an decrypted message \(String.init(data: decryptedMessage, encoding: .utf8)!)")
            }
            else{
                print("Error decrypting")
            }

        }
        else{
            print("Error encrypting")
        }

Also, if you want before iOS 10 you have the functions:

func SecKeyEncrypt(_ key: SecKey, 
             _ padding: SecPadding, 
             _ plainText: UnsafePointer<UInt8>, 
             _ plainTextLen: Int, 
             _ cipherText: UnsafeMutablePointer<UInt8>, 
             _ cipherTextLen: UnsafeMutablePointer<Int>) -> OSStatus

And

func SecKeyDecrypt(_ key: SecKey, 
             _ padding: SecPadding, 
             _ cipherText: UnsafePointer<UInt8>, 
             _ cipherTextLen: Int, 
             _ plainText: UnsafeMutablePointer<UInt8>, 
             _ plainTextLen: UnsafeMutablePointer<Int>) -> OSStatus

But these give less options and They are quite resticted.

Worth mentioning that my public and private key where generate on android using

public static String createStringFromPublicKey(Key key) throws Exception {
  X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key.getEncoded());
  return new String(Base64.encode(x509EncodedKeySpec.getEncoded(), Base64.NO_WRAP), "UTF-8");
}

and

public static String createStringFromPrivateKey(Key key) throws Exception {
  PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key.getEncoded());
  return new String(Base64.encode(pkcs8EncodedKeySpec.getEncoded(), Base64.NO_WRAP), "UTF-8");
}
beryllium
  • 29,669
  • 15
  • 106
  • 125
Reimond Hill
  • 4,278
  • 40
  • 52
  • which keyformat are you using for andriod? .Der or .Pem or .BKS thanks – PPShein Mar 16 '18 at 09:50
  • I did not do the code for android. I was given de public key as String... PKCS1 gives you more clue? – Reimond Hill Mar 16 '18 at 13:52
  • 1
    I've tried with your code and gave to Java, found `BadPadding` error from java. – PPShein Mar 16 '18 at 14:38
  • private static String createStringFromPublicKey(Key key) throws Exception { X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(key.getEncoded()); return new String(Base64.encode(x509EncodedKeySpec.getEncoded(), Base64.NO_WRAP), "UTF-8"); } private static String createStringFromPrivateKey(Key key) throws Exception { PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(key.getEncoded()); return new String(Base64.encode(pkcs8EncodedKeySpec.getEncoded(), Base64.NO_WRAP), "UTF-8"); } – Reimond Hill Mar 16 '18 at 14:48
  • you might be using different padding in android. – Reimond Hill Mar 16 '18 at 14:49
  • I need to make publicSecKey as SecKey?? – vaibby Jan 22 '19 at 07:03
  • Does this encryption cover "mgf1 padding", Same process showed me with error decryption in server side due to padding error. . rsaEncryptionOAEPSHA256 - Does this cover mgf1 padding. – rjndra Mar 14 '19 at 06:35
  • Glad I help! This code is quite old I might think to update it! :) – Reimond Hill Feb 07 '20 at 09:34
  • I receive public key from server. How do i change it into Seckey? I have searched all over, cant seem to find a solution. – Kunal Gupta Mar 18 '20 at 12:48
  • Have you clicked in "Here"? – Reimond Hill Mar 19 '20 at 09:02
  • @rjndra are u able to resolve it ? does rsaEncryptionOAEPSHA256 includes mgfi padding as well ? – Muhammad Waqas Bhati Sep 10 '20 at 05:59