Decrypting Des with Commoncrypto in Swift 3

Decrypting DES with CommonCrypto in Swift 3

When you encrypt or decrypt from String to String, you need 3 steps, as modern encryption algorithms work on only binary data.

Encoding:

[original String]
↓(encode in UTF-8)
[original binary]
↓(encrypt)
[encrypted binary]
↓(encode in base64)
[encrypted String]

(I guess you have a base64 encoded String as your == in the encrypted String is suggesting.)

So, when decoding, you need all these steps in reverse.

Decoding:

[encrypted String]
↓(decode in base64)
[encrypted binary]
↓(decrypt)
[original binary]
↓(decode in UTF-8)
[original String]

You are doing the first step of decoding in a wrong way. (See #1 of the code below.)


One more, when you want to receive data into mutable (var) Data, set count (not only capacity) of the Data. (#2 and #3)


UPDATED
And, as told by zaph, you need to specify IV for CBC mode (default) or use ECB mode (#4).

Your code should be something like this:

if
let key = "12345678".data(using: .utf8),
let data = Data(base64Encoded: encrypted, options: .ignoreUnknownCharacters) //<-#1
{
var numBytesDecrypted: size_t = 0
var result = Data(count: data.count) //<-#2

let err = result.withUnsafeMutableBytes {resultBytes in
data.withUnsafeBytes {dataBytes in
key.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(kCCDecrypt), CCAlgorithm(kCCAlgorithmDES), CCOptions(kCCOptionPKCS7Padding|kCCModeECB), keyBytes, kCCKeySizeDES, nil, dataBytes, data.count, resultBytes, result.count, &numBytesDecrypted) //<-#4
}
}
}

if err != CCCryptorStatus(kCCSuccess) {
NSLog("Decryption failed! Error: \(err.description)")
}

print(numBytesDecrypted)
result.count = numBytesDecrypted //<-#3
print(result as NSData) //`as NSData` is good for debugging.

return String(data: result, encoding: .utf8) ?? "???"
}
return "???"

DES/ECB/NoPadding in swift 3.1 using Common Crypto

So it seems like there's no NoPadding options available, in the end I just removed '+ kCCBlockSizeDES' from 'cryptData' initialization and added '0' characters to my string before encrypting it to reach a right size (for example a length multiple of 8) and then after decryption I just removed the zeros to get the original string.

how to add triple des encryption decryption in swift

Unfortunately, there's currently no pre-defined Swift module for CommonCrypto, which means that you'll either have to create one yourself in a module.modulemap file, or import it in your bridging header. If you're making an app and not a framework, the latter is the easiest: just create a bridging header (if you don't have one, just add an Objective-C source file to the project and it'll offer to create one automatically; you can delete the Objective-C source file afterwards). Next, add this to the bridging header:

#import <CommonCrypto/CommonCrypto.h>

Note that if you're making a framework, the bridging header won't work and you'll have to make a modulemap instead (let me know if this is the case, and I'll edit something into the answer).

Anyway, the above will get rid of all the errors about kCC things not being found. Now that that's done, there are still a few things in the code that need fixing.

First of all, get rid of the unnecessary use of NS classes. Change:

let keyData: NSData! = (keyString as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData!

to:

let keyData = keyString.data(using: .utf8)!

The ! is acceptable in this case, since we know what keyString is and we know that it's definitely always convertible to UTF-8.

Now, do the same thing for data. Unfortunately in this case, message depends on user input, so we shouldn't use !—if the message turns out not to be convertible to UTF-8, ! will cause your app to crash, which usually isn't what you want. It's better to use guard let and then bail if the conversion fails, either by making your function's return value optional and returning nil or adding throws to your function's return value and throwing an error:

guard let data = message.data(using: .utf8) else {
return nil
OR:
throw CocoaError(.fileReadInapplicableStringEncoding) // or some custom error
}

The next issue is the use of bytes on your Data object. In Swift, this is not allowed, because it's unsafe; if the Data is deallocated before you're done with bytes, you'll crash or run into other weird behavior. Instead, you should use withUnsafeBytes, and do the work requiring the bytes inside a closure. This is safer, since the Data is guaranteed to be valid at least until the closure returns. Since we have three separate Datas that we need the bytes of, this is kind of unwieldy with a triple-nested closure, but we can do it:

let cryptStatus = keyData.withUnsafeBytes { (keyBytes: UnsafePointer<UInt8>) in
data.withUnsafeBytes { (dataBytes: UnsafePointer<UInt8>) in
cryptData.withUnsafeMutableBytes { (cryptBytes: UnsafeMutablePointer<UInt8>) in
CCCrypt(operation,
algoritm,
options,
keyBytes,
keyLength,
nil,
dataBytes,
data.count,
cryptBytes,
cryptData.count,
&numBytesEncrypted)
}
}
}

After that, you've just got some more Objective-C-isms to make properly Swifty, and your encrypt function should be done:

cryptData.count = Int(numBytesEncrypted)

// Not all data is a UTF-8 string so Base64 is used
var base64cryptString = cryptData.base64EncodedString(options: .lineLength64Characters)

The only problem I see in the encode function is a few Objective-C-isms that you should modernize:

let customAllowedSet = CharacterSet(charactersIn: "==\n").inverted
let escapedString = str.addingPercentEncoding(withAllowedCharacters: customAllowedSet)

There's also the calling convention of your encode function; func encodeString(str: String) means you'll have to call it like return encodeString(str: base64cryptString) with the label present. If you want to call it without the label, you can change the signature to func encodeString(_ str: String).

DES Encryption and decryption algorithm in swift

Got Solution by changing the code

import UIKit
import CommonCrypto
var message: String?

public class IAppEncryptionUtitlity: NSObject {

//Calling method to encrypt using extensions
public func methodToCallEncryption( stringToEncrypt : String ) ->String {
let iVValue:String = "nzug8FrX"
let keyValue = IAppConfig.key //DyfmgL9p
let encoded = stringToEncrypt.desEncrypt( key : keyValue , iv : iVValue )
return encoded!
}

public func methodToCallDecryption( stringToDecrypt : String ) -> String{
let iVValue:String = "nzug8FrX"
let keyValue = IAppConfig.key //DyfmgL9p
let decoded = stringToDecrypt.desEncrypt( key : keyValue , iv : iVValue )
return decoded!
}
}
extension String {

func desEncrypt(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)) + kCCBlockSizeDES) {

let keyLength = size_t(kCCKeySizeDES)
let operation: CCOperation = UInt32(kCCEncrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmDES)
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 desDecrypt(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)) + kCCBlockSizeDES) {

let keyLength = size_t(kCCKeySizeDES)
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmDES)
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
}
}

Thanks everyone for the help

AES Encrypt and Decrypt

I found the solution, it is a good library.

Cross platform 256bit AES encryption / decryption.

This project contains the implementation of 256 bit AES encryption which works on all the platforms (C#, iOS, Android). One of the key objective is to make AES work on all the platforms with simple implementation.

Platforms Supported:
iOS ,
Android ,
Windows (C#).

https://github.com/Pakhee/Cross-platform-AES-encryption

MD5 3DES encryption Swift

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.

IOS Swift3 DES,ECB,Padding Encryption

Find an AES or DES Common Crypto example here on SO and make changes as necessary to 3DES. Be sure the key is 24-bytes.

Change:

  • algorithm: CCAlgorithm3DES
  • mode: kCCModeECB
  • options: ccPKCS7Padding

If the key is 16-bytes it is two-key 3DES, duplicate and append the first 8-bytes to the end of the key to create a 24-byte key.

Note: DESede known as 3DES or Tripple-DES.

3DES is really not secure, especially 2-key 3DES. If at all possible update to AES-CBC with a random IV.

Here is untested Swift 3 (Should also work with Swift4)code, note the warning about the key length above:

func trippleDESCrypt(data:Data, keyData:Data, ivData:Data, operation:Int) -> Data? {
let cryptLength = size_t(data.count + kCCBlockSize3DES)
var cryptData = Data(repeating:0, count:cryptLength)
var numBytesEncrypted :size_t = 0

let keyLength = keyData.count
let algoritm: CCAlgorithm = UInt32(kCCAlgorithm3DES)
let options: CCOptions = UInt32(kCCOptionPKCS7Padding | kCCModeECB)

let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
data.withUnsafeBytes {dataBytes in
ivData.withUnsafeBytes {ivBytes in
keyData.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(operation),
algoritm,
options,
keyBytes, keyLength,
ivBytes,
dataBytes, data.count,
cryptBytes, cryptLength,
&numBytesEncrypted)
}
}
}
}

if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.count = numBytesEncrypted
}
else {
print("Error: \(cryptStatus)")
return nil
}

return cryptData
}

As usual you need to have a Bridging Header file that contains the import:

#import <CommonCrypto/CommonCrypto.h>

and you need to include the framework:

Security.framework.


Related Topics



Leave a reply



Submit