Derive An AWS Signing Key For Signature Version 4 - swift

I am attempting to generate a signing key for AWS according to AWS's documentation here for an iOS application. The documentation is pretty good however, it doesn't provide an example using Swift. Apple provides CryptoKit which should be the right framework, but I haven't been able to puzzle it out.
Ruby Example
def getSignatureKey key, dateStamp, regionName, serviceName
kDate = OpenSSL::HMAC.digest('sha256', "AWS4" + key, dateStamp)
kRegion = OpenSSL::HMAC.digest('sha256', kDate, regionName)
kService = OpenSSL::HMAC.digest('sha256', kRegion, serviceName)
kSigning = OpenSSL::HMAC.digest('sha256', kService, "aws4_request")
kSigning
end
Sample Inputs from AWS Docs
key = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'
dateStamp = '20120215'
regionName = 'us-east-1'
serviceName = 'iam'
Should output
kSecret = '41575334774a616c725855746e46454d492f4b374d44454e472b62507852666943594558414d504c454b4559'
kDate = '969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d'
kRegion = '69daa0209cd9c5ff5c8ced464a696fd4252e981430b10e3d3fd8e2f197d7a70c'
kService = 'f72cfd46f26bc4643f06a11eabb6c0ba18780c19a8da0c31ace671265e3c87fa'
kSigning = 'f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d'
My attempt (note you have to append AWS to the key according to the docs)
import Foundation
import CryptoKit
let key = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"
let dateStamp = "20120215"
let regionName = "us-east-1"
let serviceName = "iam"
let keyData = Data("AWS\(key)".utf8)
let symmetricKey = SymmetricKey(data: keyData)
let dateStampData = Data(dateStamp.utf8)
let signature = HMAC<SHA256>.authenticationCode(for: dateStampData, using: symmetricKey)
let skeyString = keyData.map { String(format: "%02hhx", $0) }.joined()
print("kSecret \t= \(skeyString)")
let kDateString = Data(signature).map { String(format: "%02hhx", $0) }.joined()
print("kDate \t\t= \(kDateString)")
The first one is correct, so it seems I have the initial key correct, but when trying to apply it to dateStamp it doesn't match.
Outputs
kSecret = 415753774a616c725855746e46454d492f4b374d44454e472b62507852666943594558414d504c454b4559
kDate = 2226579f8b317a03ec325a8c8b3d27cf465ce52787455e1880039824b4ba0e25

Of course the moment I post the question I find the issue. The original issue was I was appending AWS instead of AWS4 the string appeared to be correct for kSecret because I was looking at the first set and last set of digits. Here is the solution for anyone looking to do the same.
import Foundation
import CryptoKit
let key = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"
let dateStamp = "20120215"
let regionName = "us-east-1"
let serviceName = "iam"
let keyData = Data("AWS4\(key)".utf8)
let dateStampData = Data(dateStamp.utf8)
let regionNameData = Data(regionName.utf8)
let serviceNameData = Data(serviceName.utf8)
let signingData = Data("aws4_request".utf8)
var symmetricKey = SymmetricKey(data: keyData)
let dateSHA256 = HMAC<SHA256>.authenticationCode(for: dateStampData, using: symmetricKey)
symmetricKey = SymmetricKey(data: Data(dateSHA256))
let regionSHA256 = HMAC<SHA256>.authenticationCode(for: regionNameData, using: symmetricKey)
symmetricKey = SymmetricKey(data: Data(regionSHA256))
let serviceNameSHA256 = HMAC<SHA256>.authenticationCode(for: serviceNameData, using: symmetricKey)
symmetricKey = SymmetricKey(data: Data(serviceNameSHA256))
let signingSHA256 = HMAC<SHA256>.authenticationCode(for: signingData, using: symmetricKey)
let skeyString = keyData.map { String(format: "%02hhx", $0) }.joined()
print("kSecret \t= \(skeyString)")
let kDateString = Data(dateSHA256).map { String(format: "%02hhx", $0) }.joined()
print("kDate \t\t= \(kDateString)")
let kRegionString = Data(regionSHA256).map { String(format: "%02hhx", $0) }.joined()
print("kRegion \t= \(kRegionString)")
let kServiceString = Data(serviceNameSHA256).map { String(format: "%02hhx", $0) }.joined()
print("kService \t= \(kServiceString)")
let kSigningString = Data(signingSHA256).map { String(format: "%02hhx", $0) }.joined()
print("kSigning \t= \(kSigningString)")
Outputs
kSecret = 41575334774a616c725855746e46454d492f4b374d44454e472b62507852666943594558414d504c454b4559
kDate = 969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d
kRegion = 69daa0209cd9c5ff5c8ced464a696fd4252e981430b10e3d3fd8e2f197d7a70c
kService = f72cfd46f26bc4643f06a11eabb6c0ba18780c19a8da0c31ace671265e3c87fa
kSigning = f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d

Related

Signature Version 4 Issue on Swift

I really try hard to solve this problem on my project. But I can't.
I try to sign URLRequest headers and body by Amazon AWS Signature Version 4. And send it to server with Alamofire SDK.
But only headers without body work correctly.
I dunno why I get the response "403 forbidden" from server when I put httpBody into URLRequest.
Here is my source.
...
var request = URLRequest(url: convUrl)
if let jsonString = String(data: jsonData, encoding: .utf8) {
AWS4Signer().aws4Sign(request: &request, method: httpMethodType, payload: jsonString, query: [:], path: url.replacingOccurrences(of: self.url.host, with: ""))
}
AF.request(request).responseData { response in
}
func aws4Sign(request: inout URLRequest, method: HttpMethodType, payload: String?, query: [String:String]?, path: String) {
var headers = [String:String]()
let requested_date_time = self.getAmzDate(date: Date())
headers["x-amz-date"] = requested_date_time
// x-amz-content-sha256
var payload_hash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" // empty
if let payload {
let utf8Data = payload.data(using: .utf8) ?? Data()
payload_hash = SHA256.hash(data: utf8Data).hexDigest()
if !payload.isEmpty {
headers["x-amz-content-sha256"] = payload_hash
request.httpBody = utf8Data
}
}
let canonical_querystring = ""
headers["host"] = "hosthost.com"
let sortedHeaders = headers.filter { ["host", "x-amz-date", "x-amz-content-sha256"].contains($0.key) }
.sorted { $0.key < $1.key }
let canonical_headers = sortedHeaders.map { "\($0.key.lowercased()):\($0.value)" }.joined(separator: "\n") + "\n"
let signed_headers = sortedHeaders.map { $0.key.lowercased() }.joined(separator: ";")
let canonical_uri = path
let canonical_request = "\(method.rawValue)\n\(canonical_uri)\n\(canonical_querystring)\n\(canonical_headers)\n\(signed_headers)\n\(payload_hash)"
let hashed_canonical_request = SHA256.hash(data: canonical_request.data(using: .utf8)!).hexDigest()
let algorithm = "AWS4-HMAC-SHA256"
let nowDate = Date().getString(format: "YYYYMMdd", timeZone: TimeZone(identifier: "UTC")!)
let credential_scope = "\(nowDate)/\(Const.key.awsRegion)/\(Const.key.awsServiceType)/aws4_request"
let string_to_sign = "\(algorithm)\n\(requested_date_time)\n\(credential_scope)\n\(hashed_canonical_request)"
let signing_key = self.getSignatureKey(key: Const.key.awsSecretAccessKey, dateStamp: nowDate, regionName: Const.key.awsRegion, serviceName: Const.key.awsServiceType)
let signature = self.sign(key: signing_key, msg: string_to_sign).hexDigest()
let authorization_header = "\(algorithm) Credential=\(Const.key.awsAccessKeyID)/\(credential_scope), SignedHeaders=\(signed_headers), Signature=\(signature)"
request.addValue(requested_date_time, forHTTPHeaderField: "X-amz-date")
request.addValue(authorization_header, forHTTPHeaderField: "Authorization")
}
func getSignatureKey(key: String, dateStamp: String, regionName: String, serviceName: String) -> Data {
let keyData = Data("AWS4\(key)".utf8)
let dateStampData = Data(dateStamp.utf8)
let regionNameData = Data(regionName.utf8)
let serviceNameData = Data(serviceName.utf8)
let signingData = Data("aws4_request".utf8)
var symmetricKey = SymmetricKey(data: keyData)
let dateSHA256 = HMAC<SHA256>.authenticationCode(for: dateStampData, using: symmetricKey)
symmetricKey = SymmetricKey(data: Data(dateSHA256))
let regionSHA256 = HMAC<SHA256>.authenticationCode(for: regionNameData, using: symmetricKey)
symmetricKey = SymmetricKey(data: Data(regionSHA256))
let serviceNameSHA256 = HMAC<SHA256>.authenticationCode(for: serviceNameData, using: symmetricKey)
symmetricKey = SymmetricKey(data: Data(serviceNameSHA256))
let signingSHA256 = HMAC<SHA256>.authenticationCode(for: signingData, using: symmetricKey)
let skeyString = keyData.map { String(format: "%02hhx", $0) }.joined()
let kDateString = Data(dateSHA256).map { String(format: "%02hhx", $0) }.joined()
let kRegionString = Data(regionSHA256).map { String(format: "%02hhx", $0) }.joined()
let kServiceString = Data(serviceNameSHA256).map { String(format: "%02hhx", $0) }.joined()
let kSigningString = Data(signingSHA256).map { String(format: "%02hhx", $0) }.joined()
return Data(signingSHA256)
}
func sign(key: Data, msg: String) -> Data {
let hmac = HMAC<SHA256>.authenticationCode(for: msg.data(using: .utf8)!, using: SymmetricKey(data: key))
return Data(hmac)
}
func getAmzDate(date: Date) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyyMMdd'T'HHmmss'Z'"
formatter.timeZone = TimeZone(identifier: "UTC")
return formatter.string(from: date)
}
func getCanonicalQuerystring(query: [String: String]) -> String {
let sortedParameters = query.sorted { $0.0 < $1.0 }
let encodedQueryParameters = sortedParameters.map { (key, value) in
return "\(key.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")=\(value.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")"
}
let canonicalQuerystring = encodedQueryParameters.joined(separator: "&")
return canonicalQuerystring
}
The "Authorization" data has it.
"AWS4-HMAC-SHA256 Credential=ACCESS_KEY_ID/20230213/ap-northeast-2/execute-api/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=cfa667aa18472d3d5a419f67aa2c321977428abac391a33f9f3e31839bcb4665"
ACCESS_KEY_ID is my access_key_id of AWS.
So far, only the POST method is tested.

Import a pkcs12 in mac osx Swift

I would need to import a pkcs12 into the osx keychain and make the private key non-extractable
Is this possible?
this is my example code
let keyString = "MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgQCVXkvZifORfS8VVEp+BQTrnXu2a2+KL+Rw5FPHeSAOXjrS5DoC0GxK29jTKPGkJrg2WOiL/ZSbKvTq8wBUZzoUGaJQ+kzBJ40ShVtbJYGNFixubuKrSjUNQB149t25lxHnJia0i9i1sLfzrPnqPJ4ABf7lnhkTbNt8g/KriwoqmQICAQE="
let keyData = NSData(base64Encoded: keyString, options: .ignoreUnknownCharacters)!
var hostError: Unmanaged<CFError>?
guard let hostPrivateKey = SecKeyCreateRandomKey(optionDict as CFDictionary, &hostError) else {
fatalError("😡 Could not generate the private key.")
}
let passphrase = "Password" as CFString
let keyDict1 = SecKeyCopyAttributes(hostPrivateKey)
var keyParams = SecItemImportExportKeyParameters()
keyParams.version = UInt32(SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION)
keyParams.passphrase = Unmanaged.passUnretained(passphrase)
/*
keyParams.keyAttributes=?? <---- ????
*/
var inputFormat :SecExternalFormat = .formatPKCS12
var itemType :SecExternalItemType = .itemTypeUnknown
var itemsCFArray :CFArray? = nil
let error = SecItemImport(hostPrivateKey as! CFData , nil, &inputFormat, &itemType, SecItemImportExportFlags(rawValue: UInt32(0)), &keyParams, "login" as! SecKeychain, &itemsCFArray)

Decrypt data using AES.GCM.SealedBox in Swift

I am trying to decrypt data using AES.GCM.The encrypted data works fine but when I try to decrypt the data using the same key it gives authentication error.
Below is the code to decrypt
func decryptData(decryptToData: Data, key: SymmetricKey) -> String {
var decryptedString: String!
let combinedData = decryptToData // Previous sealed bo
let sealedBoxToOpen = try! AES.GCM.SealedBox(combined: decryptToData)
if let decryptedData = try? AES.GCM.open(sealedBoxToOpen, using: key) {
decryptedString = String(data: decryptedData, encoding: .utf8)!
print(decryptedString)
} else {
print("error", CryptoKitError.self)
// Ouch, doSomething() threw an error.
}
return decryptedString
}
The following is my encryption code
let iv = AES.GCM.Nonce()
var encryptedData: Data!
let key = SymmetricKey(size: .bits128)
func encryptData(encryptString: String, key: SymmetricKey) -> Data {
var encryptedData: Data?
do {
let datatoEncrypt1 = encryptString.data(using: .utf8)!
let mySealedBox = try AES.GCM.seal(datatoEncrypt1, using: key, nonce: iv)
encryptedData = mySealedBox.combined
} catch {
print("Error")
}
return encryptedData
}
import XCTest
import CryptoKit
import Foundation
class CryptoKitUnitTest: XCTestCase {
func testEncryptandDecrypt(){
let secret = "my-256-bit-secret-my-secret-my-s"
let key = SymmetricKey(data: secret.data(using: .utf8)!)
let plain = "Say hello to my little friend!"
let nonce = try! AES.GCM.Nonce(data: Data(base64Encoded: "fv1nixTVoYpSvpdA")!)
// Encrypt
let sealedBox = try! AES.GCM.seal(plain.data(using: .utf8)!, using: key, nonce: nonce)
let ciphertext = sealedBox.ciphertext.base64EncodedString()
print("ciphertext: \(ciphertext)") // bWtTZkPAu7oXpQ3QpHvoTvc4NQgDTIycXHFJWvjk
let sealedBoxToDecrypt = try! AES.GCM.SealedBox(nonce: nonce,
ciphertext: Data(base64Encoded: ciphertext)!,
tag: sealedBox.tag)
let decrypted = try! AES.GCM.open(sealedBoxToDecrypt, using: key)
print(String(decoding: decrypted, as: UTF8.self))
}
func testEncryptandDecryptFirstWay() {
let keyStr = "d5a423f64b607ea7c65b311d855dc48f36114b227bd0c7a3d403f6158a9e4412"
let key = SymmetricKey(data: Data(hex:keyStr))
let nonceData = Data(hex: "131348c0987c7eece60fc0bc")
let nonce: AES.GCM.Nonce = try! AES.GCM.Nonce(data: nonceData)
let plain = "This is first cypto graphy method"
var decyptedStr = ""
if let encyptedData = plain.asData.encrypt(nonce: nonce, key: key) {
decyptedStr = encyptedData.decrypt(nonce: nonce, key: key)
}
XCTAssertEqual(plain, decyptedStr)
}
}
extension Data {
func encrypt(nonce: AES.GCM.Nonce, key: SymmetricKey) ->Data?{
// Encrypt
do {
let sealedBox = try AES.GCM.seal(self, using: key, nonce: nonce)
let cipherText = sealedBox.ciphertext.base64EncodedString()
let tag = sealedBox.tag
let tagPlusCipherText = tag + cipherText.asData
return tagPlusCipherText
}
catch let exceptionInfo {
debugPrint("Encrypt exception Info: \(exceptionInfo)")
}
return nil
}
func decrypt(nonce: AES.GCM.Nonce, key: SymmetricKey) -> String{
let tag = self.subtract(0, 16)
let cipherTextData = self.subtract(tag.count, self.count - tag.count)
let cipherText = cipherTextData.asString
// Decrypt
var decodeStr: String = ""
do {
let sealedBoxToDecrypt = try AES.GCM.SealedBox(nonce: nonce,
ciphertext: Data(base64Encoded: cipherText)!,
tag: tag)
let decrypted = try AES.GCM.open(sealedBoxToDecrypt, using: key)
decodeStr = String(decoding: decrypted, as: UTF8.self)
} catch let exceptionInfo {
debugPrint("Decrypt exception info: \(exceptionInfo)")
}
return decodeStr
}
public func subtract(_ start: Int, _ length: Int) ->Data {
precondition(self.count >= start + length,
"Invalid data range range. trying to find out of bound data")
let allBytes = Array(Data(bytes: self.bytes, count: self.count))
let partBytes = Array(allBytes[start..<start + length])
let dataPart = Data(bytes: partBytes, count: partBytes.count)
return dataPart
}
var asString: String {
let str = String(decoding: self, as: UTF8.self)
return str
}
}
extension String {
var asData: Data {
return self.data(using: .utf8) ?? Data()
}
}

Swift String omit/convert polish accents

I have a following problem:
I am making an API request. With a city name f.e. 'Poznań" (containing some signs typical for some language), swift doesn't want to give me the result, but when I do the same request through Postman app it gives the result in a proper way. How can can I prevent swift from converting those 'strange' letters? 'city.name' is city name that I pass from the previous VC and googlePlaces API. Here is sample of a request and part of my code:
https://samples.openweathermap.org/data/2.5/weather?q=London&appid=b6907d289e10d714a6e88b30761fae22
private let kWeatherAPIURL = "https://api.openweathermap.org/data/2.5/weather?q=%#&appid=%#"
let urlString = String(format: kWeatherAPIURL, city.name, weatherAPIKey)
guard let url = URL(string: urlString) else {
print("address doesnt exist!")
return
}
I am force unwrapping here for brevity:
let kWeatherAPIURL = "https://api.openweathermap.org/data/2.5/weather?q=%#&appid=%#"
let weatherAPIKey = "YourWeatherAPIKey"
let cityName = "Poznań"
let cString = cityName.cString(using: .utf8)!
let utf8CityName = cityName.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
let urlString = String(format: kWeatherAPIURL, utf8CityName, weatherAPIKey)
let url = URL(string: urlString)!
//https://api.openweathermap.org/data/2.5/weather?q=Pozna%C5%84&appid=YourWeatherAPIKey
A safe approach would be to use URL components:
let weatherAPIKey = "YourWeatherAPIKey"
let cityName = "Poznań"
var components = URLComponents()
components.scheme = "https"
components.host = "api.openweathermap.org"
components.path = "/data/2.5/weather"
components.queryItems = [URLQueryItem(name: "q", value: cityName),
URLQueryItem(name: "appid", value: weatherAPIKey)
]
print(components.url!) //https://api.openweathermap.org/data/2.5/weather?q=Pozna%C5%84&appid=YourWeatherAPIKey
An example of using URLComponents.
Prepare a function like this:
func createWeatherAPIURL(cityName: String, apiKey: String) -> URL? {
let kWeatherAPIURL = "https://api.openweathermap.org/data/2.5/weather"
var urlCompo = URLComponents(string: kWeatherAPIURL)
urlCompo?.queryItems = [
URLQueryItem(name: "q", value: cityName),
URLQueryItem(name: "appid", value: apiKey)
]
return urlCompo?.url
}
And use it:
guard let url = createWeatherAPIURL(cityName: city.name, apiKey: weatherAPIKey) else {
print("address doesnt exist!")
return
}

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.