3DES Encryption in SWIFT or Cross Platform Method for PHP and SWIFT

I have been using Triple DES Encryption for my C# Project.I'm porting this to Mac.Is there inbuilt Triple DES Support for swift ?

This is how i use 3DES in C#

public string Decrypt3DES(string strString)
  {
  DESCryptoServiceProvider DES = new DESCryptoServiceProvider();


  DES.Key = Encoding.UTF8.GetBytes(this.key);
  DES.Mode = CipherMode.ECB;
  DES.Padding = PaddingMode.Zeros;
  ICryptoTransform DESDecrypt = DES.CreateDecryptor();


  byte[] Buffer = Convert.FromBase64String(strString);
  return UTF8Encoding.UTF8.GetString(DESDecrypt.TransformFinalBlock(Buffer, 0, Buffer.Length));
  }


If there is no alternative please suggest me a cross platform string encryption method that works both in PHP and SWIFT.


Thanks

May have a look here :

h ttps://stackoverflow.com/questions/31786037/how-to-encrypt-using-3des-in-swift

or here:

h ttps://github.com/phynet/Swift-CypherTripleDesEncrypt

I’m going to start by addressing your specific questions, after which I’l move on to big picture stuff.

Is there inbuilt Triple DES Support for swift ?

Kinda.

For examples of how to do standard low-level crypto operations on Apple platforms, check out the CryptoCompatibility sample code. This doesn’t show 3DES (because 3DES is not recommended, something I’ll cover below) but it would be relatively straightforward to change the AES code to use 3DES.

Calling Common Crypto from Swift is a pain right now. I’ve described my recommended approach on this thread.

Finally, a warning about PHP. CryptoCompatibility has test code that checks the results it generates against the results generated by other crypto platforms, namely OpenSSL, Java and PHP. In working with PHP I found that it’s crypto is weird. I recommend that you focus on getting your Swift and C# code to agree first, then move on to PHP.

Coming back to the big picture, I have a couple of top-level questions:

  • What is your high-level goal for this crypto?

  • Are you implementing an existing crypto design? Or is this a custom thing that you designed yourself?

The reason I ask is that the code snippet you posted is very worrying from a cryptographic standpoint. The most immediate problem is that it uses 3DES, something that is no longer considered secure. But there are other things that are more worrying:

  • ECB is almost never the best starting point if for crypto. If you haven’t seen the ECB penguin, you should look it up.

  • Padding with zeros is generally frowned upon.

  • Likewise for encryption without authentication.

If you can explain more about what you’re trying to achieve with this crypto, I should be able to point you in the direction of some standard crypto that achieves that goal.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks a lot for the detailed answer 🙂 i really appreciate it.


What im trying to acheive is


-Send some licensing data to the server (php script) via HTTP POST.The server verifies the licensing information and replies whether the license is valid.

I intend to secure the communication between the client(OSX App) and the server by encrypting the data using a common cryptographic scheme.


Currently what im using is Common Crypto -

I have referred this answer https://stackoverflow.com/a/45507302/848968and added the Bridging Header


extension String {
    func aesEncrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String? {
        if let keyData = key.data(using: String.Encoding.utf8),
            let data = self.data(using: String.Encoding.utf8),
            let cryptData    = NSMutableData(length: Int((data.count)) + kCCBlockSizeAES128) {
            let keyLength              = size_t(kCCKeySizeAES128)
            let operation: CCOperation = UInt32(kCCEncrypt)
            let algoritm:  CCAlgorithm = UInt32(kCCAlgorithmAES128)
            let options:   CCOptions   = UInt32(options)
            var numBytesEncrypted :size_t = 0
            let cryptStatus = CCCrypt(operation,
                                      algoritm,
                                      options,
                                      (keyData as NSData).bytes, keyLength,
                                      iv,
                                      (data as NSData).bytes, data.count,
                                      cryptData.mutableBytes, cryptData.length,
                                      &numBytesEncrypted)
            if UInt32(cryptStatus) == UInt32(kCCSuccess) {
                cryptData.length = Int(numBytesEncrypted)
                let base64cryptString = cryptData.base64EncodedString(options: .lineLength64Characters)
                return base64cryptString
            }
            else {
                return nil
            }
        }
        return nil
    }
    func aesDecrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String? {
        if let keyData = key.data(using: String.Encoding.utf8),
            let data = NSData(base64Encoded: self, options: .ignoreUnknownCharacters),
            let cryptData    = NSMutableData(length: Int((data.length)) + kCCBlockSizeAES128) {
            let keyLength              = size_t(kCCKeySizeAES128)
            let operation: CCOperation = UInt32(kCCDecrypt)
            let algoritm:  CCAlgorithm = UInt32(kCCAlgorithmAES128)
            let options:   CCOptions   = UInt32(options)
            var numBytesEncrypted :size_t = 0
            let cryptStatus = CCCrypt(operation,
                                      algoritm,
                                      options,
                                      (keyData as NSData).bytes, keyLength,
                                      iv,
                                      data.bytes, data.length,
                                      cryptData.mutableBytes, cryptData.length,
                                      &numBytesEncrypted)
            if UInt32(cryptStatus) == UInt32(kCCSuccess) {
                cryptData.length = Int(numBytesEncrypted)
                let unencryptedMessage = String(data: cryptData as Data, encoding:String.Encoding.utf8)
                return unencryptedMessage
            }
            else {
                return nil
            }
        }
        return nil
    }
}


The Data is sent to the server using the following code


var request = var request = URLRequest(url: URL(string: "http://www.example.com/test.php")!)
        request.httpMethod = "POST"
        let akey:String =  txt_key.stringValue;
        let email:String = txt_email.stringValue
        let VAL:String="test"   
        var data="blah"
        let postString = data
        request.httpBody = postString.data(using: .utf8)
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            guard let data = data, error == nil else {                                                 /
                print("error=\(error)")
                return
            }
            if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {           /
                print("statusCode should be 200, but is \(httpStatus.statusCode)")
                print("response = \(response)")
            }
            let responseString = String(data: data, encoding:  .utf8)
            print(responseString)
        }
        task.resume()


All these stuff works .. But im having a hard time finding an Encyption method that is cross compatible with PHP


So far i have tried


mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key256, $text, MCRYPT_MODE_CBC, $iv128);


How should i go forward,Please advice 🙂

Send some licensing data to the server (php script) via HTTP POST.The server verifies the licensing information and replies whether the license is valid.

HTTP? Or HTTPS? If you did this over HTTPS you could avoid the need for doing any crypto at all, which seems like a much more sensible approach to me.

The only gotcha with using HTTPS is that you’ll want to pin your certificate so that the traffic can’t be snooped by a debugging HTTP proxy, but that’s much easier than designing and implementing an effective crypto scheme.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Actually i found a way to encrypt strings that support PHP and SWIFT

http://sketchytech.blogspot.in/2016/02/resurrecting-commoncrypto-in-swift-for.html


This works fine.But im wondering if this will effect the compatibility of the application ie: using bridging and Common Crypto.

I'm currently running XCode 8 on Sierra.Will the resulting application work on older versions of OSX.I want to maximize compatibilty.

------------------------------------------------------------------------------------------------


The domain has HTTPS Cerficate and is set use HTTPS by default.

How can i modify HTTP POST to use only HTTPS.Is man in the middle attack possible ie: Make Spoofed Server and may be send 'Valid' for all activation requests.


Please advice.

But im wondering if this will effect the compatibility of the application ie: using bridging and Common Crypto.

If you have to use CommonCrypto then doing it through a bridging header is fine. There are some drawbacks to this (for example, if you try to do it from a Swift framework) but none of them apply to typical app-level code.

Having said that, I don’t want to get too far into the CommonCrypto details because I’m reticent to help you down a path that’s fundamentally insecure, which is what you seem to be proposing. I’ve already outlined my concerns about your security design (see my 9 Oct post).

Oh, and you can add key management to that list. How do the client app and the PHP code agree on the key to use for this symmetric cypher?

The domain has HTTPS Cerficate and is set use HTTPS by default.

Cool.

How can i modify HTTP POST to use only HTTPS.

If you give it an

https://xxx
URL, it will only use HTTPS.

Is man in the middle attack possible …

Yes. To quote my previous post:

The only gotcha with using HTTPS is that you’ll want to pin your certificate so that the traffic can’t be snooped by a debugging HTTP proxy, but that’s much easier than designing and implementing an effective crypto scheme.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for the update.


I having problems with finding a common crypto as the decrypted string is null


var y=responseString!
  let x:String =  (y.aesDecrypt(key:"123456789012asdsadasd", iv: "iv-salt-string--"))!


Both PHP and SWIFT produces the same encryption result.Dont know why this is happening.


------------------------------------------------------------------------------------------------------------------------------------------------------------


I think i will switch to HTTPS only.Please guide me on this one


If i switch to HTTPS and use the following code.Will the data that is being send from the client- OSX App to the PHP Web Service via POST be Secure(Encrypted)?


Is there a better way to do it? Please help!


var request = var request = URLRequest(url: URL(string: "https://www.example.com/test.php")!) 
        request.httpMethod = "POST" 
        let akey:String =  txt_key.stringValue; 
        let email:String = txt_email.stringValue 
        let VAL:String="test"    
        var data="blah" 
        let postString = data 
        request.httpBody = postString.data(using: .utf8) 
        let task = URLSession.shared.dataTask(with: request) { data, response, error in 
            guard let data = data, error == nil else {                                                 / 
                print("error=\(error)") 
                return 
            } 
            if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {           / 
                print("statusCode should be 200, but is \(httpStatus.statusCode)") 
                print("response = \(response)") 
            } 
            let responseString = String(data: data, encoding:  .utf8) 
            print(responseString) 
        } 
        task.resume()

I having problems with finding a common crypto as the decrypted string is null

You keep asking new CommonCrypto questions but you never answer any of the questions that I ask )-: Let’s start with the big one: in your intended crypto design, how do the client app and the PHP code agree on the key to use for this symmetric cypher?

If i switch to HTTPS and use the following code. Will the data that is being send from the client- OSX App to the PHP Web Service via POST be Secure (Encrypted)?

I’m not sure I understand your question here. It seems like you’re asking “Will an HTTPS request be encrypted?”, in which case the answer is clearly “Yes.” The S stands for Secure after all.

A vanilla HTTPS request will not give you end-to-end security, that is, a debugging HTTP proxy could still see your traffic. To prevent that you’ll have to implement some sort of credential pinning (either certificate pinning or public key pinning). Pasted in below are examples of both.

IMPORTANT Credential pinning has its drawbacks. For example:

  • Your app will not work in certain enterprise HTTP proxy environments, which use the same technique as a debugging HTTP proxy to see inside HTTPS connections.

  • If you change the credential on your server, you’ll have to change your app to match.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
func didReceive(serverTrustChallenge challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    let expectedCer = Bundle.main.certificate(named: "IETF")
    let trust = challenge.protectionSpace.serverTrust!
    if trust.evaluatePinnedTo(serverKey: expectedCer) {
        completionHandler(.performDefaultHandling, nil)
    } else {
        completionHandler(.cancelAuthenticationChallenge, nil)
    }
}

func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {

    // Look for specific authentication challenges and dispatch those to various helper methods.
    //
    // IMPORTANT: It's critical that, if you get a challenge you weren't expecting, 
    // you resolve that challenge with `.performDefaultHandling`.

    switch (challenge.protectionSpace.authenticationMethod, challenge.protectionSpace.host) {
        case (NSURLAuthenticationMethodServerTrust, "www.ietf.org"):
            self.didReceive(serverTrustChallenge: challenge, completionHandler: completionHandler) 
        default:
            completionHandler(.performDefaultHandling, nil)
    }
}
func didReceive(serverTrustChallenge challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    let expectedCer = Bundle.main.certificate(named: "Example")
    let trust = challenge.protectionSpace.serverTrust!
    if trust.evaluatePinnedTo(serverCertificate: expectedCer) { 
        completionHandler(.performDefaultHandling, nil)
    } else {
        completionHandler(.cancelAuthenticationChallenge, nil)
    }
}

func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {

    // Look for specific authentication challenges and dispatch those to various helper methods.
    //
    // IMPORTANT: It's critical that, if you get a challenge you weren't expecting, 
    // you resolve that challenge with `.performDefaultHandling`.

    switch (challenge.protectionSpace.authenticationMethod, challenge.protectionSpace.host) {
        case (NSURLAuthenticationMethodServerTrust, "example.com"):
            self.didReceive(serverTrustChallenge: challenge, completionHandler: completionHandler)
        default:
            completionHandler(.performDefaultHandling, nil)
    }
}
import Foundation

extension SecTrust {

    func evaluate() -> Bool {
        var trustResult: SecTrustResultType = .invalid
        let err = SecTrustEvaluate(self, &trustResult)
        guard err == errSecSuccess else { return false }
        return [.proceed, .unspecified].contains(trustResult)
    }

    func evaluatePinnedTo(serverCertificate expectedCer: SecCertificate) -> Bool {

        // Do an actual trust evaluation.  This is necessary in order to get meaningful 
        // results from `SecTrustGetCertificateAtIndex` and, if we're going to do it 
        // anyway, we may as well pay attention to its result.

        guard self.evaluate() else {
            return false
        }

        // Compare the certificate from the trust evaluation to our expected certificate.

        guard let actualCer = SecTrustGetCertificateAtIndex(self, 0) else { return false }
        if CFEqual(actualCer, expectedCer) {
            return true
        } else {
            return false
        }
    }

    func evaluatePinnedTo(serverKey expectedCer: SecCertificate) -> Bool {

        func publicKey(from certificate: SecCertificate) -> SecKey? {
            var tOpt: SecTrust? = nil
            let err = SecTrustCreateWithCertificates([certificate] as CFArray, SecPolicyCreateBasicX509(), &tOpt)
            guard err == errSecSuccess else { return nil }
            let t = tOpt!

            var trustResult: SecTrustResultType = .invalid
            _ = SecTrustEvaluate(t, &trustResult)

            return SecTrustCopyPublicKey(t)
        }

        // Do a default trust evaluation, just to be sure. 

        guard self.evaluate() else {
            return false
        }

        // Load the expected public key from the server certificate we're given.

        guard let expectedPublicKey = publicKey(from: expectedCer) else { return false }

        // Compare the public key from the trust evaluation to our expected certificate.

        guard let actualPublicKey = SecTrustCopyPublicKey(self) else { return false }
        if CFEqual(actualPublicKey, expectedPublicKey) {
            return true
        } else {
            return false
        }
    }
}
3DES Encryption in SWIFT or Cross Platform Method for PHP and SWIFT
 
 
Q