3DES Encryption result different from example - swift

I have an example for a 3DES encryption that I have to follow in order to authenticate on NFC cards. Here is the example:
So 51E764602678DF2B becomes 577293FD2F34CA51 with key = 49454D4B41455242214E4143554F5946 and IV = 0000000000000000
I succeed to have the right result on this site:
http://tripledes.online-domain-tools.com/
I tried on swift with https://github.com/sgl0v/SCrypto as follow:
func testScrypto() {
let plaintext = "51E764602678DF2B".data(using: String.Encoding.utf8)!
let sharedSecretKey = "49454D4B41455242214E4143".data(using: String.Encoding.utf8)!
let IV = "0000000000000000".data(using: String.Encoding.utf8)!
let ciphertext = try! plaintext.encrypt(.tripleDES, options: .PKCS7Padding, key: sharedSecretKey, iv: IV)
let plaintext2 = try! ciphertext.decrypt(.tripleDES, options: .PKCS7Padding, key: sharedSecretKey, iv: IV)
print("cipher = \(ciphertext.hexString())")
print("plaintext2 = \(plaintext2.hexString())")
}
public extension Data {
func bytesArray<T: ExpressibleByIntegerLiteral>() -> [T] {
var bytes = Array<T>(repeating: 0, count: self.count)
(self as NSData).getBytes(&bytes, length:self.count * MemoryLayout<T>.size)
return bytes
}
func hexString() -> String {
let hexString = NSMutableString()
let bytes: [UInt8] = self.bytesArray()
for byte in bytes {
hexString.appendFormat("%02x", UInt(byte))
}
return hexString as String
}
}
and the result is:
cipher = d4c4a9637bcb4a435982330a42d1357b9e4539886a983535
plaintext2 = 35314537363436303236373844463242
35314537363436303236373844463242 is 51E764602678DF2B if i convert from hexstring to plaintext but the other string is not 577293FD2F34CA51 at all
I also tried this lib https://www.example-code.com/swift/crypt2_3des.asp
but the result is still wrong
I don't know if anybody has an idea how to do this on swift or is an expert in encryption ?
thanks !

I succeed to fix the issue
The issue was that the key was only 16 bytes and need to be 24, so I guess it was randomly filled but it was expected to be the first 8 bytes to be put back at the end of the 16 in order to do 24 ?
like this it works:
func fillKey(keyLength: size_t, key: Data) -> Data {
let missingBytes = keyLength - key.count
if missingBytes > 0 {
let keyBytes = (key as NSData).bytes
var bytes = [UInt8](repeating: UInt8(0), count: keyLength)
memccpy(&bytes[0], keyBytes.advanced(by: 0), Int32(key.count), key.count)
memccpy(&bytes[key.count], keyBytes.advanced(by: 0), Int32(missingBytes), missingBytes)
return Data(bytes: bytes)
} else {
return key
}
}
func my3DESEncrypt(encryptData: String, key: String, iv: String) -> Data? {
var myKeyData : Data = key.hexadecimal()!
let myIvData : Data = iv.hexadecimal()!
var myRawData : Data = encryptData.hexadecimal()!
let buffer_size : size_t = myRawData.count + kCCBlockSize3DES
var buffer = [UInt8](repeating: UInt8(0), count: buffer_size)
var num_bytes_encrypted : size_t = 0
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options: CCOptions = 0
let keyLength = size_t(kCCKeySize3DES)
myKeyData = self.fillKey(keyLength: keyLength, key: myKeyData)
let Crypto_status: CCCryptorStatus = CCCrypt(operation, algoritm, options, (myKeyData as NSData).bytes, keyLength, (myIvData as NSData).bytes, (myRawData as NSData).bytes, myRawData.count, &buffer, buffer_size, &num_bytes_encrypted)
if UInt32(Crypto_status) == UInt32(kCCSuccess) {
let data = Data(bytes: buffer, count: num_bytes_encrypted)
return data
} else{
return nil
}
}
func my3DESDecrypt(decryptData : Data, key: String, iv: String) -> Data? {
let mydata_len : Int = decryptData.count
var myKeyData : Data = key.hexadecimal()!
let myIvData : Data = iv.hexadecimal()!
let buffer_size : size_t = mydata_len+kCCBlockSize3DES
var buffer = [UInt8](repeating: UInt8(0), count: buffer_size)
var num_bytes_encrypted : size_t = 0
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options: CCOptions = UInt32(kCCOptionPKCS7Padding)
let keyLength = size_t(kCCKeySize3DES)
myKeyData = self.fillKey(keyLength: keyLength, key: myKeyData)
let decrypt_status : CCCryptorStatus = CCCrypt(operation, algoritm, options, (myKeyData as NSData).bytes, keyLength, (myIvData as NSData).bytes, (decryptData as NSData).bytes, mydata_len, &buffer, buffer_size, &num_bytes_encrypted)
if UInt32(decrypt_status) == UInt32(kCCSuccess){
let data = Data(bytes: buffer, count: num_bytes_encrypted)
return data
} else{
return nil
}
}

The plaintext data and key that have been provided are encoded in hexadecimals. You are however encoding them as UTF-8 text, which is not the same thing.

Related

Java to swift conversion in cryptography

I have a java code, where i used cryptography( Encryption and decryption). I want to use the same process on swift code.
//my java code for encryption in crypto class
class Crypto {
private SecretKeySpec skc;
private final static char[] hexArray = "0123456789abcdef".toCharArray();
String TAG = "TAG";
#RequiresApi(api = Build.VERSION_CODES.O)
Crypto(String token) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(("YourStrongKey" + token).getBytes("UTF-8"));
skc = new SecretKeySpec(thedigest, "AES/ECB/PKCS5Padding");
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
e.printStackTrace();
}
}
private byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len/2];
for(int i = 0; i < len; i+=2){
data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));
}
return data;
}
public byte[] encrypt(String clear) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skc);
byte[] input = clear.getBytes("utf-8");
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
cipher.doFinal(cipherText, ctLength);
Log.d(TAG, "encrypt: ciper: "+cipher.toString());
return cipherText;
}
public byte[] decrypt(byte[] buf, int offset, int len) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skc);
byte[] dec = new byte[cipher.getOutputSize(len - offset)];
int ctLength = cipher.update(buf, offset, len - offset, dec, 0);
cipher.doFinal(dec, ctLength);
Log.d(TAG, "encrypt: dec: "+dec.toString());
return dec;
}
}
//uses of java form main activity class
Crypto crypto;
String token = "Jpc3MiOiJodHRwczovL3NlY3VyZXRva2";
crypto = new Crypto(token);
JSONObject msg = new JSONObject();
msg.put("phoneData", "data1");
msg.put("countryData", "data2");
Log.d(TAG, "startHttpApiRequest: msg: "+msg);
String ss = msg.toString();
byte[] msgD = crypto.encrypt(ss);
//my swift code on playground
class SecretSpec {
var algorithm: String = "AES/ECB/PKCS7padding"
var key = [UInt8]()
func secretSpec(key: [UInt8], algorithm: String){
self.key = key
self.algorithm = algorithm
}
func getAlgorithm() -> String {
return self.algorithm
}
func getFormat() -> String {
return "RAW"
}
func getEncoded() -> [UInt8] {
return self.key
}
func hashCode() -> Int {
var retval: Int = 0
for i in 1...key.count-1 {
retval = retval + Int(key[i]) * Int(i)
}
if (algorithm.lowercased() == "tripledes"){
retval = retval ^ Int("desede".hashValue)
return retval
}else{
retval = retval ^ Int(algorithm.lowercased().hashValue)
return retval
}
}
}
extension String {
func aesEncrypt(key: String) -> 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(kCCOptionECBMode + kCCOptionPKCS7Padding)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation, algoritm, options,
(keyData as NSData).bytes,keyLength,nil, (data as NSData).bytes, data.count,cryptData.mutableBytes, cryptData.length,&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
var bytes = [UInt8](repeating: 0, count: cryptData.length)
cryptData.getBytes(&bytes, length: cryptData.length)
var hexString = ""
for byte in bytes {
hexString += String(format:"%02x", UInt8(byte))
}
return hexString
}
else {
return nil
}
}
return nil
}
}
func MD5(_ string: String) -> String? {
let length = Int(CC_MD5_DIGEST_LENGTH)
var digest = [UInt8](repeating: 0, count: length)
if let d = string.data(using: String.Encoding.utf8) {
_ = d.withUnsafeBytes { (body: UnsafePointer<UInt8>) in
CC_MD5(body, CC_LONG(d.count), &digest)
}
}
return (0..<length).reduce("") {
$0 + String(format: "%02x", digest[$1])
}
}
var token = "YourStrongKeyJpc3MiOiJodHRwczovL3NlY3VyZXRva2"
var algorithm: String = "AES/ECB/PKCS5padding"
var tokenRes = MD5(token)
let digest = hexstringToBytes(tokenRes!)
var skcSpec = SecretSpec()
skcSpec.secretSpec(key: digest!, algorithm: algorithm)
print("hello: \(skcSpec)")
let msg: NSMutableDictionary = NSMutableDictionary()
msg.setValue("data1", forKey: "phoneData")
msg.setValue("data2", forKey: "countryData")
let msgData: NSData
var msgStr: String = ""
var requestUrl: String = ""
do {
msgData = try JSONSerialization.data(withJSONObject: msg, options: JSONSerialization.WritingOptions()) as NSData
msgStr = NSString(data: msgData as Data, encoding: String.Encoding.utf8.rawValue)! as String
} catch _ {
print ("JSON Failure")
}
var str = skcSpec.getEncoded()
print(str)
let skc = NSString(bytes: str, length: str.count, encoding: String.Encoding.ascii.rawValue)! as String
let eneMsg = msgStr.aesEncrypt(key: skc)!
print("encoded: \(eneMsg)")
it does not gives me the same output. please help me to finding same output. nb: java code is fixed for encryption and decryption.
Outputs:
in java:
ffe957f00bdd93cfe1ef1133993cc9d2d8682310c648633660b448d92098e7fa07ae25f600467894ac94ccdcbe4039b8
in swift:
2e130be30aa3d8ff7fdc31dc8ffe1c39afe987ccbf8481caed9c78b49624a31c68df63a899df130128af6852c82d9aea
I have tried to convert your Crypto class directly into Swift, and got this:
import Foundation
import CommonCrypto
func MD5(_ data: Data) -> Data {
let length = Int(CC_MD5_DIGEST_LENGTH)
var digest = Data(count: length)
data.withUnsafeBytes {bytes in
_ = digest.withUnsafeMutableBytes {mutableBytes in
CC_MD5(bytes.baseAddress, CC_LONG(bytes.count), mutableBytes.bindMemory(to: UInt8.self).baseAddress)
}
}
return digest
}
func hexStringToData(_ s: String) -> Data {
let len = s.count
var data = Data(count: len/2)
var start = s.startIndex
for i in 0..<len/2 {
let end = s.index(start, offsetBy: 2)
data[i] = UInt8(s[start..<end], radix: 16)!
start = end
}
return data
}
class Crypto {
private var key: Data
init(_ token: String) {
let theDigest = MD5(("YourStrongKey" + token).data(using: .utf8)!)
key = theDigest
}
public func encrypt(_ clear: String) -> Data? {
let input = clear.data(using: .utf8)!
var cipherText = Data(count: input.count + kCCBlockSizeAES128)
let keyLength = size_t(kCCKeySizeAES128)
assert(key.count >= keyLength)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
var ctLength: size_t = 0
let cryptStatus = key.withUnsafeBytes {keyBytes in
input.withUnsafeBytes {inputBytes in
cipherText.withUnsafeMutableBytes {mutableBytes in
CCCrypt(operation, algoritm, options,
keyBytes.baseAddress, keyLength, nil,
inputBytes.baseAddress, inputBytes.count,
mutableBytes.baseAddress, mutableBytes.count,
&ctLength)
}
}
}
if cryptStatus == CCCryptorStatus(kCCSuccess) {
cipherText.count = Int(ctLength)
return cipherText
} else {
return nil
}
}
public func decrypt(_ buf: Data, _ offset: Int, _ len: Int) -> Data? {
var dec = Data(count: len)
let keyLength = size_t(kCCKeySizeAES128)
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
var ctLength :size_t = 0
let cryptStatus = key.withUnsafeBytes {keyBytes in
buf.withUnsafeBytes {inputBytes in
dec.withUnsafeMutableBytes {mutableBytes in
CCCrypt(operation, algoritm, options,
keyBytes.baseAddress, keyLength, nil,
inputBytes.baseAddress, inputBytes.count,
mutableBytes.baseAddress, mutableBytes.count,
&ctLength)
}
}
}
if cryptStatus == CCCryptorStatus(kCCSuccess) {
dec.count = Int(ctLength)
return dec
} else {
return nil
}
}
}
let token = "Jpc3MiOiJodHRwczovL3NlY3VyZXRva2"
let crypto = Crypto(token)
let msg = [
"phoneData": "data1",
"countryData": "data2",
]
let msgData = try! JSONSerialization.data(withJSONObject: msg)
let ss = String(data: msgData, encoding: .utf8)!
print(ss) //->{"phoneData":"data1","countryData":"data2"}
//### Be careful, this may be different than the result of JSONObject#toString() in Java.
//### Sometimes, outputs->{"countryData":"data2","phoneData":"data1"}
let msgD = crypto.encrypt(ss)!
print(msgD as NSData) //-><ffe957f0 0bdd93cf e1ef1133 993cc9d2 24e8b9a1 162520e5 54a3d8af 8f478db7 07ae25f6 00467894 ac94ccdc be4039b8>
//### When `ss` is {"phoneData":"data1","countryData":"data2"}
let decrypted = crypto.decrypt(msgD, 0, msgD.count)!
print(String(data: decrypted, encoding: .utf8)!) //->{"phoneData":"data1","countryData":"data2"}
In your Java code, your key String ("YourStrongKey" + token) gets two conversions until used as a binary key data for AES:
key: "YourStrongKey" + token
↓
UTF-8 bytes
↓
MD5 digest
But, in your Swift code, you are converting the key more times:
token: "YourStrongKeyJpc3MiOiJodHRwczovL3NlY3VyZXRva2"
↓
UTF-8 bytes (`d` in `MD5(_:)`)
↓
MD5 digest
↓
binary to HEX String conversion (return value from `MD5(_:)`)
↓
UTF-8 bytes (`keyData` in `aesEncrypt(key:)`)
There's no binary to HEX String conversion in your Java code and you should have not done that.
By the way, ECB is not considered to be a safe way to encrypt, you should better update your Java code.

How to encrypt and decrypt in swift like android cipher?

I have an android class which is encoding and decoding my text using a key but I want to create the same class for swift.
“I'm setting up a new server, and want to support UTF-8 fully in my web application. Where do I need to set the encoding/charsets?”
public class EncryptionDecryption {
String strResult;
public String Encrypt(String text, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes = new byte[16];
byte[] b = key.getBytes("UTF-8");
int len = b.length;
if (len > keyBytes.length)
len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] results = cipher.doFinal(text.getBytes("UTF-8"));
Log.v("GET Result from final:", results.toString());
strResult = Base64.encodeToString(results, 1);
Log.v("Encrypt01:", strResult);
Log.v("Encrypt02:", results.toString());
return strResult;
}
public String Decrypt(String text, String key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //this parameters should not be changed
byte[] keyBytes = new byte[16];
byte[] b = key.getBytes("UTF-8");
int len = b.length;
if (len > keyBytes.length)
len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] results = new byte[text.length()];
//BASE64Decoder decoder = new BASE64Decoder();
try {
results = cipher.doFinal(Base64.decode(text, Base64.DEFAULT));
} catch (Exception e) {
Log.i("Error in Decryption", e.toString());
}
Log.i("Data", new String(results, "UTF-8"));
//return new String(results, "UTF-8"); // it returns the result as a String
return new String(results, "UTF-8");
}
For swift 4 I found this answer thanks all
import CommonCrypto
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
}
}
Starting from Xcode 10.1 and Swift 4.2 you can use CommonCrypto pretty easy without to take care about Objective-C to Swift bridging.
just:
import CommonCrypto
read more about framework methods here https://developer.apple.com/security/

Encrypt and decrypt in SWIFT

Im searching for encrypt and decrypt code in SWIFT.
But I cannot found a solution in SWIFT. I need pass a key to encrypt/decrypt in MD5 and convert to BASE64 in ECB mode!
I have this code in C#:
public static string MD5Cripto(string texto, string chave)
{
try
{
TripleDESCryptoServiceProvider sObCripto
= new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider sObjcriptoMd5 = new MD5CryptoServiceProvider();
byte[] sByteHash, sByteBuff;
string sTempKey = chave;
sByteHash = sObjcriptoMd5.ComputeHash(ASCIIEncoding
.UTF8.GetBytes(sTempKey));
sObjcriptoMd5 = null;
sObCriptografaSenha.Key = sByteHash;
sObCriptografaSenha.Mode = CipherMode.ECB;
sByteBuff = ASCIIEncoding.UTF8.GetBytes(texto);
return Convert.ToBase64String(sObCripto.CreateEncryptor()
.TransformFinalBlock(sByteBuff, 0, sByteBuff.Length));
}
catch (Exception ex)
{
return "Digite os valores Corretamente." + ex.Message;
}
}
UPDATE:
I try this but still not working.. What Im doing wrong? (Ignore my prints..)
func myEncrypt(encryptData:String) -> NSData?
{
let myKeyData : NSData = ("mykey" as NSString)
.dataUsingEncoding(NSUTF8StringEncoding)!
let myKeyDataMD5 = "mykey".md5()
let sArrayByte = myKeyDataMD5.hexToByteArray()
let myRawData : NSData = encryptData.dataUsingEncoding(NSUTF8StringEncoding)!
let buffer_size:size_t = myRawData.length + kCCBlockSize3DES
let 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)
let Crypto_status: CCCryptorStatus = CCCrypt(operation, algoritm,
options, sArrayByte, keyLength, nil,
myRawData.bytes, myRawData.length, buffer,
buffer_size, &num_bytes_encrypted)
if Int32(Crypto_status) == Int32(kCCSuccess)
{
let myResult: NSData = NSData(bytes: buffer, length: num_bytes_encrypted)
print("buffer")
let count = myResult.length / sizeof(UInt32)
var array = [UInt32](count: count, repeatedValue: 0)
myResult.getBytes(&array, length:count * sizeof(UInt32))
print(array)
free(buffer)
print("myResult")
print(myResult)
let resultNSString = NSString(data: myResult,
encoding: NSUnicodeStringEncoding)!
let resultString = resultNSString as String
print("resultString")
print(resultString)
let sBase64 = toBase64(String(resultString))
print("sBase64")
print(sBase64)
let data : NSData! = resultNSString
.dataUsingEncoding(NSUnicodeStringEncoding)
let count2 = data.length / sizeof(UInt32)
var array2 = [UInt32](count: count, repeatedValue: 0)
data.getBytes(&array2, length:count2 * sizeof(UInt32))
print("array2")
print(array2)
return myResult
}
else
{
free(buffer)
return nil
}
}
Example question code updated.
Not sure what the output formatting code in the question was trying to accomplish.
Note that the 3DES uses a 24-byte key (kCCKeySize3DES is 24) and MD5 provides a 16-byte (CC_MD5_DIGEST_LENGTH is 16) result so there is a mis-match in key length.
func encrypt(dataString:String, keyString:String) -> NSData?
{
let keyData = md5(keyString)
let data : NSData = dataString.dataUsingEncoding(NSUTF8StringEncoding)!
var numBytesEncrypted : size_t = 0
var encryptedData: NSMutableData! = NSMutableData(length: Int(data.length) + kCCBlockSize3DES)
let encryptedPointer = UnsafeMutablePointer<UInt8>(encryptedData.mutableBytes)
let encryptedLength = size_t(encryptedData.length)
let operation:CCOperation = UInt32(kCCEncrypt)
let algoritm:CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options:CCOptions = UInt32(kCCOptionECBMode + kCCOptionPKCS7Padding)
let keyLength = size_t(kCCKeySize3DES)
let status: CCCryptorStatus = CCCrypt(operation, algoritm, options,
keyData, keyLength,
nil,
data.bytes, data.length,
encryptedPointer, encryptedLength,
&numBytesEncrypted)
if Int32(status) == Int32(kCCSuccess) {
encryptedData.length = Int(numBytesEncrypted)
}
else {
encryptedData = nil
}
return encryptedData;
}
func md5(string: String) -> [UInt8] {
var digest = [UInt8](count: Int(CC_MD5_DIGEST_LENGTH), repeatedValue: 0)
if let data = string.dataUsingEncoding(NSUTF8StringEncoding) {
CC_MD5(data.bytes, CC_LONG(data.length), &digest)
}
return digest
}
Test:
let dataString = "Now is the time"
let keyString = "mykey"
let encryptedData = encrypt(dataString, keyString:keyString)
print("encryptedData: \(encryptedData!)")
let encryptedBase64 = encryptedData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
print("encryptedBase64: \(encryptedBase64)")
Output:
encryptedData: 8d88a2bc 00beb021 f37917c3 75b0ba1a
encryptedBase64: jYiivAC+sCHzeRfDdbC6Gg==
Note:
3DES, ECB mode and MD5 are not recommended and should not be used in new code, instead use AES, CBC mode with a random iv and PBKDF2 respetively.

Encrypting files in using CommonCrypt CCrypto AES256 - cannot decrypt some files

I want to encrypt some files using AES256 in my cocoa application.
The resulting files should be as small as possible.
Here's my code:
static func encryptFile(pathToFile:String, destinationPath:String, key:String) -> Bool {
var error: NSError?
let fileContents = NSData(contentsOfFile: pathToFile, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &error)
if let fileContents = fileContents {
println("Trying to encrypt file \(pathToFile)")
let startTime = NSDate().timeIntervalSince1970
let encryptedContents = FileEncryptor.AES256Encryption(fileContents, key: key)
println("ENCRYPTION TIME: \(NSDate().timeIntervalSince1970 - startTime)")
if let encryptedContents = encryptedContents {
var writeError: NSError?
if (encryptedContents.writeToFile(pathToFile, options: NSDataWritingOptions.DataWritingAtomic, error: &writeError)) {
return true
} else {
if (writeError != nil) {
println("Cannot write to file \(pathToFile). Error: \(writeError)")
} else {
println("Cannot write to file \(pathToFile)")
}
return false
}
} else {
return false
}
} else {
println("Unable to read file \(pathToFile). Error: \(error)");
return false
}
}
static func AES256Encryption(dataToEncrypt:NSData, key:String) -> NSData? {
let keyData: NSData! = (key as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let keyBytes = UnsafeMutablePointer<Void>(keyData.bytes)
print("keyLength = \(keyData.length), keyData = \(keyData)")
let dataLength = size_t(dataToEncrypt.length)
let dataBytes = UnsafeMutablePointer<Void>(dataToEncrypt.bytes)
print("dataLength = \(dataLength)")
let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
let cryptPointer = UnsafeMutablePointer<Void>(cryptData!.mutableBytes)
let cryptLength = size_t(cryptData!.length)
let keyLength = size_t(kCCKeySizeAES256)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionPKCS7Padding + kCCModeCBC)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
keyBytes, keyLength,
nil,
dataBytes, dataLength,
cryptPointer, cryptLength,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
// let x: UInt = numBytesEncrypted
cryptData!.length = Int(numBytesEncrypted)
print("cryptLength = \(numBytesEncrypted)")
return cryptData
} else {
print("Error: \(cryptStatus)")
return nil
}
}
I have an issue with two things:
1. Encrypted file content look like [small part of the file]:
a56f 707a 24cb e965 08dd be3d 1a0d 9e7b
b73f c982 2014 fdae fa29 c63d 4588 ee29
7b03 5fb2 96a5 00be 2871 e3e8 af23 4eac
I would rather have it like:
ã.FrÚQ÷¬_ÄC¯Q%,™˜$žKÝôÙ„gC€È•GBvn&­V9&´fÓ
I cannot decrypt some of the files.
Most of them are fine, however some are not. I've been looking for some kind of pattern, and the only thing I have found is that in most cases, the files which are correct, are larger when encrypted then they are when decrypted/original.
Here's a function I use to decrypt:
static func decryptFile(pathToFile:String, destinationPath:String, key:String) -> Bool {
var error: NSError?
let fileContents = NSData(contentsOfFile: pathToFile, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &error)
if let fileContents = fileContents {
println("Trying to decrypt file \(pathToFile)")
let startTime = NSDate().timeIntervalSince1970
let decryptedContents = FileEncryptor.AES256Decryption(fileContents, key: key)
println("DECRYPTION TIME: \(NSDate().timeIntervalSince1970 - startTime)")
return NSFileManager.defaultManager().createFileAtPath(destinationPath, contents:decryptedContents, attributes:nil)
} else {
println("Unable to read file \(pathToFile). Error: \(error)");
return false
}
}
static func AES256Decryption(data:NSData, key: String) -> NSData? {
let keyData: NSData! = (key as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!
let keyBytes = UnsafeMutablePointer<Void>(keyData.bytes)
print("keyLength = \(keyData.length)")
let dataLength = size_t(data.length)
let dataBytes = UnsafeMutablePointer<Void>(data.bytes)
print("dataLength = \(dataLength), ")
let cryptData = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)
let cryptPointer = UnsafeMutablePointer<Void>(cryptData!.mutableBytes)
let cryptLength = size_t(cryptData!.length)
let keyLength = size_t(kCCKeySizeAES256)
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(kCCOptionPKCS7Padding + kCCModeCBC)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
keyBytes, keyLength,
nil,
dataBytes, dataLength,
cryptPointer, cryptLength,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
// let x: UInt = numBytesEncrypted
cryptData!.length = Int(numBytesEncrypted)
return cryptData
} else {
print("Error: \(cryptStatus)")
return nil
}
}
Almost all of the code has been taken from SO, it seems to work ok, apart from these issues I have.
The password I use is same for all of the files.
Any help will be appreciated!
EDIT:
About issue 2. It seems the code I used was prepared for ECB mode which I have changed to CBC. This means I have to increase size of the encrypted data. After making this change, almost all of the files work perfectly, apart from one... which worked ok when using the smaller value. Damn.

MD5 3DES encryption Swift

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
Ok so I created a new project called newEncrypt.
I chose not to use the header option as the instructions say this is limited to non Framework apps/
I created a folder inside newEncrypt called CommonCrypto, with a module.map file inside. the contents of which are: module CommonCrypto [system] {
header "/usr/include/CommonCrypto/CommonCrypto.h"
export *
}
added ${SRCROOT}/CommonCrypto to swift compiler-search paths-import paths. Debug and release.
This is where the instructions sort of stop. I assume I need to import CommonCrypto into my class. This error with “could not build objective C module ‘CommonCrypto’.
Im also assuming I should have the CommonCrypto library files (from the CommonCryto ‘include’ folder) in "/usr/include/CommonCrypto/CommonCrypto.h" or “/newEncrypt/CommonCrypto/CommonCrypto.h"?
I have tried this, but I just get the same errors.
I have then tried to ad a header file with #import and added -lfoo to other linker flags debug and release (although this may not be the correct one) ust in case this could still be required. But I still get the same could not build objective c error.
Im sure I am doing something wrong thats obvious
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.
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))
}
}