Reputation: 491
I have an app that must send login credentials that have been encrypted first by MD5 and then by 3DES.
I have managed to use CryptoSwift to encrypt the string by MD5. However I cannot find anything to encrypt by 3DES on Swift.
I have tried CommonCrypto. As far as I can tell this is in C but could be imported into Objective C with a bridging header.
I have found a few articles and tutorials that tell me how to import CommonCrypto into Swift, either by a bridging header(with the warning it will not work with frameworks) or by Model.map. However neither are working. Im not sure if this is a limitation in the latest versions of iOS or Xcode.
Could someone please advise an alternative?
Thanks
EDITED
Hi, please see the below steps I have taken
Upvotes: 2
Views: 6292
Reputation: 21
Building on the solution by @ThundercatChris and @DarkDust, I had to make a change to their solution as I was working with hex strings. There was a need to enforce the triple DES key length as the encryption/decryption was not working correctly without it.
import Foundation
extension Data {
private func tripleDesKey() -> Data? {
if self.count == 24 {
return self
}
if self.count == 16 {
var key = Data(capacity: 24)
key.append(self.subdata(in: 0..<16))
key.append(self.subdata(in: 0..<8))
return key
}
return nil
}
private func tripleDesOp(key: Data, operation: CCOperation, options: CCOptions) -> Data? {
guard let tempKey = key.tripleDesKey() else {
return nil
}
let keyData = NSData(data: tempKey)
let valueData = NSData(data: self)
let bufferSize = valueData.length + (UInt32(kCCEncrypt) == operation ? kCCBlockSize3DES : kCCBlockSizeAES128)
let buffer = UnsafeMutablePointer<NSData>.allocate(capacity: bufferSize)
var bytes_encrypted: size_t = 0
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let keyLength = size_t(kCCKeySize3DES)
let ccStatus: CCCryptorStatus = CCCrypt(operation, algoritm, options, keyData.bytes, keyLength, nil, valueData.bytes, valueData.length, buffer, bufferSize, &bytes_encrypted)
guard ccStatus == CCCryptorStatus(kCCSuccess) else {
free(buffer)
return nil
}
let dataOut = Data(bytes: buffer, count: bytes_encrypted)
free(buffer)
return dataOut
}
func tripleDesEncrypt(with key: Data) -> Data? {
return tripleDesOp(key: key,operation: UInt32(kCCEncrypt), options: UInt32(kCCOptionECBMode))
}
func tripleDesDecrypt(with key: Data) -> Data?{
return tripleDesOp(key: key, operation: UInt32(kCCDecrypt), options: UInt32(kCCOptionECBMode))
}
}
Upvotes: 0
Reputation: 491
So it turns out I was completely overcomplicating this.
There is a really useful article already http://www.stackoverflow.dluat.com/questions/31004609/how-to-convert-common-crypto-code-from-objective-c-to-swift
I didn't need to import any external libraries or SDKs, all I needed was a bridging header and to #import <CommonCrypto/CommonCrypto.h>
override func viewDidLoad() {
super.viewDidLoad()
myEncrypt("my string to encrypt")
}
func myEncrypt(encryptData:String) -> NSData?{
var myKeyData : NSData = ("myEncryptionKey" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
var myRawData : NSData = encryptData.dataUsingEncoding(NSUTF8StringEncoding)!
var iv : [UInt8] = [56, 101, 63, 23, 96, 182, 209, 205] // I didn't use
var buffer_size : size_t = myRawData.length + kCCBlockSize3DES
var buffer = UnsafeMutablePointer<NSData>.alloc(buffer_size)
var num_bytes_encrypted : size_t = 0
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
let keyLength = size_t(kCCKeySize3DES)
var Crypto_status: CCCryptorStatus = CCCrypt(operation, algoritm, options, myKeyData.bytes, keyLength, nil, myRawData.bytes, myRawData.length, buffer, buffer_size, &num_bytes_encrypted)
if UInt32(Crypto_status) == UInt32(kCCSuccess){
var myResult: NSData = NSData(bytes: buffer, length: num_bytes_encrypted)
free(buffer)
println("my result \(myResult)") //This just prints the data
let keyData: NSData = myResult
let hexString = keyData.toHexString()
println("hex result \(hexString)") // I needed a hex string output
myDecrypt(myResult) // sent straight to the decryption function to test the data output is the same
return myResult
}else{
free(buffer)
return nil
}
}
func myDecrypt(decryptData : NSData) -> NSData?{
var mydata_len : Int = decryptData.length
var keyData : NSData = ("myEncryptionKey" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!
var buffer_size : size_t = mydata_len+kCCBlockSizeAES128
var buffer = UnsafeMutablePointer<NSData>.alloc(buffer_size)
var num_bytes_encrypted : size_t = 0
var iv : [UInt8] = [56, 101, 63, 23, 96, 182, 209, 205] // I didn't use
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
let keyLength = size_t(kCCKeySize3DES)
var decrypt_status : CCCryptorStatus = CCCrypt(operation, algoritm, options, keyData.bytes, keyLength, nil, decryptData.bytes, mydata_len, buffer, buffer_size, &num_bytes_encrypted)
if UInt32(decrypt_status) == UInt32(kCCSuccess){
var myResult : NSData = NSData(bytes: buffer, length: num_bytes_encrypted)
free(buffer)
println("decrypt \(myResult)")
var stringResult = NSString(data: myResult, encoding:NSUTF8StringEncoding)
println("my decrypt string \(stringResult!)")
return myResult
}else{
free(buffer)
return nil
}
}
I hope this helps someone.
Upvotes: 11