Search code examples
iosswiftencryptionswift3

Encrypt RSA/ECB/OAEPWithSHA-256AndMGF1Padding Swift


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.


Solution

  • 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");
    }