CryptoSwift + CryptoJS Swift - ios
I really need some help here with decrypting server response encrypted with CryptoJS.
I use CryptoSwift to decrypt response.
Here is a sample of server response data I get.
{\"ct\":\"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\",\"iv\":\"d6d6bd8ee407bc25a7b23d8d36b7bce9\",\"s\":\"b8e72892c801c87c\"}"}
Simple string parsing clears the encrypted string and gives me the following data:
let iv = "d6d6bd8ee407bc25a7b23d8d36b7bce9"
let salt = "b8e72892c801c87c"
and a key formend with other data
let key = "8aa1ec1e6948b481d1ee450c94ffb2edc774877325df4d05aca2e5827497ed33"
Here is the peace of code I use to decrypt response:
// transforming key to [UInt8]
let keyChars = Array(key.characters)
let keyBytes = 0.stride(to: keyChars.count, by: 2).map {
UInt8(String(keyChars[$0 ..< $0+2]), radix: 16) ?? 0
}
// transforming iv to [UInt8]
let ivChars = Array(iv.characters)
let ivBytes = 0.stride(to: ivChars.count, by: 2).map {
UInt8(String(ivChars[$0 ..< $0+2]), radix: 16) ?? 0
}
// transforming encryptedData to [UInt8]
let messageData = encrypted.dataFromHexadecimalString()
let byteArray = messageData!.arrayOfBytes()
do {
let decryptedBytes: [UInt8] = try AES(key: keyBytes, iv: ivBytes, blockMode: .CFB).decrypt(byteArray)
let data = NSData.withBytes(decryptedBytes)
let decrypted = data.base64EncodedStringWithOptions([])
let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions())
print("decrypted = \(json)")
} catch {
print("error = \(error)")
}
What ever I do I get either error = Decrypt or base64 string that does not decode to a JSON as it suppose to.
P.S.: I did try CryptoJS.swift but the result was "undefined"
UPD
Sample project
This is how data encrypted on back end:
CryptoJS.AES.encrypt(JSON.stringify(options.params), key, { format: JsonFormatter }).toString()
This is how data decrypted on back end:
JSON.parse(CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(raw, key, { format: JsonFormatter })))
I tried to to something similar in my sample project but for some reason it did not work for me.
UPD2
Update from back end
// Nodejs import
var node_cryptojs = require('node-cryptojs-aes');
var CryptoJS = node_cryptojs.CryptoJS;
var JsonFormatter = node_cryptojs.JsonFormatter;
// Data to encrypt and encryption key
var data = {'hello':'world'};
var key = '8aa1ec1e6948b481d1ee450c94ffb2edc774877325df4d05aca2e5827497ed33';
// Encryption of the data
var encrypted = CryptoJS.AES.encry
var decrypted = JSON.parse(CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(encrypted, key, { format: JsonFormatter })))
UPD3
No, the name is similar but the API is different. We used npmjs.com/package/node-cryptojs-aes on the server-side (encryption+ decryption) and code.google.com/archive/p/crypto-js client-side on our site (also encryption+decryption)
Sample of encrypted data
{"_id":"5687ad129b65920a00b56a9b","type":"user","created":"2016-01-02T10:57:22.851Z","uuid":"d9df3412cee97ec1d0a8c547f73e4bb6","secret":"307a14f6ffc667c7941e6263edca4149","profile":{"lastname":"Mmm","gender":"Male","firstname":"Mmm","email":"mmm#mmm.mmm","dob":"1993-10-31T00:00:00.000+0200"},"avatar":{"large":"https://graph.facebook.com/v2.4/1122734811071660/picture?width=120&height=120"},"location":{"country":{"filename":"greece","code":"GR","continent":"Europe","name":"Greece"},"state":{"id":"Aitolia
kai Akarnania","country":"GR","name":"Aitolia kai
Akarnania"}},"auth":{"facebook":{"userID":"1122734811071660"}},"notifications":{"new_window":{"sms":false,"email":true,"push":false},"new_live":{"sms":false,"email":true,"push":false},"new_premium":{"sms":true,"email":true,"push":false},"reminder":{"sms":true,"email":true,"push":false},"new_arcade":{"sms":true,"email":true,"push":false},"ranking":{"sms":false,"email":true,"push":false}},"metas":{},"stats":{"game":{"time":{"total":1084452,"maze":{"mean":180436,"stdev":423,"min":180013,"max":180859,"sum":360872},"wordsearch":{"mean":111639.5,"stdev":68379.5,"min":43260,"max":180019,"sum":223279},"trivia":{"mean":22410,"stdev":0,"min":22410,"max":22410,"sum":22410},"brokenword":{"mean":40399,"stdev":0,"min":40399,"max":40399,"sum":40399},"imagelabel":{"mean":38349.5,"stdev":22808.5,"min":15541,"max":61158,"sum":76699},"scramble":{"mean":180174,"stdev":0,"min":180174,"max":180174,"sum":180174},"sort":{"mean":180619,"stdev":0,"min":180619,"max":180619,"sum":180619}},"score":{"total":4500,"maze":{"mean":null,"stdev":null,"min":null,"max":null,"sum":0},"wordsearch":{"mean":1000,"stdev":0,"min":1000,"max":1000,"sum":1000},"trivia":{"mean":800,"stdev":0,"min":800,"max":800,"sum":800},"brokenword":{"mean":800,"stdev":0,"min":800,"max":800,"sum":800},"imagelabel":{"mean":950,"stdev":50,"min":900,"max":1000,"sum":1900},"scramble":{"mean":null,"stdev":null,"min":null,"max":null,"sum":0},"sort":{"mean":null,"stdev":null,"min":null,"max":null,"sum":0}}},"positions":{"position":{"avg":0}},"played":{"window":1,"total":232,"live":120,"arcade":101,"live-duplicate":10}},"credits":487,"utm":"false","perms":{"root":true},"undefined":null,"value":{"credits":520,"usd":52,"bought":3},"premium":true}
Related
Decrypting AES/CBC/PKCS5Padding in iOS
I have a file that has been encrypted on Android using this code: import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.CipherOutputStream; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; public class AESUtils { private static final String IV_STRING = "123456789876543"; private String key = "mysecretkey12345"; public static byte[] encryptData(String key, byte[] byteContent) { byte[] encryptedBytes = null; try { byte[] enCodeFormat = key.getBytes(); SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES"); byte[] initParam = IV_STRING.getBytes(); IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); encryptedBytes = cipher.doFinal(byteContent); } catch (Exception e) { e.printStackTrace(); } return encryptedBytes; } public static byte[] decryptData(String key, byte[] encryptedBytes) { byte[] result = null ; try { byte[] sEnCodeFormat = key.getBytes(); SecretKeySpec secretKey = new SecretKeySpec(sEnCodeFormat, "AES"); byte[] initParam = IV_STRING.getBytes(); IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec); result = cipher.doFinal(encryptedBytes); } catch (Exception e) { e.printStackTrace(); } return result; } } I tried to reverse engineer the decryption in Swift using CommonCrypto like this: import CommonCrypto let keyStr:String = "mysecretkey12345" let ivStr:String = "123456789876543" func aesDecrypt(data:NSData) -> Data? { let k:NSData = keyStr.data(using: .utf8)! as NSData let dbytes = data.bytes let kbytes=k.bytes if let keyData = keyStr.data(using: .utf8), 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(kCCOptionPKCS7Padding) var numBytesEncrypted :size_t = 0 let cryptStatus = CCCrypt(operation, algoritm, options, kbytes, keyLength, ivStr, dbytes, data.length, cryptData.mutableBytes, cryptData.length, &numBytesEncrypted) if UInt32(cryptStatus) == UInt32(kCCSuccess) { cryptData.length = Int(numBytesEncrypted) return (cryptData.copy() as! Data) } else { return nil } } return nil } I am quite new to encryption, but from my research I found that CC uses CBC by default and PKCS7Padding is basically identical to PKCS5Padding. However, the decryption does not deliver the results that I expect! The swift code was frankensteined together from various sources, including many solutions suggested here on stackoverflow. Main problem is that most examples use key and iv as Data, whereas I have strings - not sure my conversion causes problems. Secondly, many simply convert string messages, whereas I convert data (from files) directly - should not affect it too much, actually makes the code simpler avoiding data->string conversion. But since it doesn't work, what did I miss?
Okay, I think I figured the problem. Obviously, there is a problem with NSData.bytes and one should work withUnsafeBytes. Furthermore, my issue may was that the IV was not part of the data, as many examples assumed, so I missed 16 bytes when decrypting. The following code works for me, hope it will help someone! func decrypt(data: Data) -> Data { let key: Data = keyStr.data(using: .utf8) ?? Data() let iv: Data = ivStr.data(using: .utf8) ?? Data() if(keyStr.count == kCCKeySizeAES128){print("Key OKAY")} else {print("Key NOT okay")} if(ivStr.count == kCCBlockSizeAES128){print("IV OKAY")} else {print("IV NOT okay")} var buffer = Data(count: data.count) var numberBytesDecrypted: Int = 0 let cryptStatus: CCCryptorStatus = key.withUnsafeBytes {keyBytes in data.withUnsafeBytes {dataBytes in buffer.withUnsafeMutableBytes {bufferBytes in iv.withUnsafeBytes {ivBytes in CCCrypt( // Stateless, one-shot encrypt operation CCOperation(kCCDecrypt), // op: CCOperation CCAlgorithm(kCCAlgorithmAES128), // alg: CCAlgorithm CCOptions(kCCOptionPKCS7Padding), // options: CCOptions keyBytes.baseAddress, // key: the "password" key.count, // keyLength: the "password" size ivBytes.baseAddress, // iv: Initialization Vector dataBytes.baseAddress!, // dataIn: Data to decrypt bytes data.count, // dataInLength: Data to decrypt size bufferBytes.baseAddress, // dataOut: decrypted Data buffer data.count, // dataOutAvailable: decrypted Data buffer size &numberBytesDecrypted // dataOutMoved: the number of bytes written )} } } } if(cryptStatus == CCCryptorStatus(kCCSuccess)){ return buffer[..<numberBytesDecrypted] } else { print("Decryption failed") return data } }
Okay, turned out one of my test files was corrupted and my decryption worked all along. Here is a simpler version without withUnsafeBytes: func decrypt(data: Data) -> Data { let key:Data = keyStr.data(using: .utf8)! let iv:Data = ivStr.data(using: .utf8)! var buffer = [UInt8](repeating: 0, count: data.count + kCCBlockSizeAES128) var bufferLen: Int = 0 let status = CCCrypt( CCOperation(kCCDecrypt), CCAlgorithm(kCCAlgorithmAES128), CCOptions(kCCOptionPKCS7Padding), [UInt8](key), kCCBlockSizeAES128, [UInt8](iv), [UInt8](data), data.count, &buffer, buffer.count, &bufferLen ) if(status == kCCSuccess) { return Data(bytes: buffer, count: bufferLen)} else { print("Decryption failed") return data } }
How to extract certificate and private key PEM strings from PKCS#12 file using swift
I have a use case where the user gives a PKCS#12 file and its password as input, and I need both the certificate's and the private key's PEM strings. I have managed to create a SecIdentity using the p12, and its documentation says: A SecIdentity object contains a SecKey object and an associated SecCertificate object. So, I believe I am in the right path, but I couldn't find a way of extracting the SecKey and the SecCertificate from this SecIdentity. I have also not found a way to get a PEM string from a SecKey or SecCertificate, but that would only be the last step. This is the code I've used to create the identity: let key: NSString = kSecImportExportPassphrase as NSString let options: NSDictionary = [key : p12Password] var rawItems: CFArray? let p12Data = try! Data(contentsOf: p12FileUrl) let data = p12Data! as NSData let cfdata = CFDataCreate(kCFAllocatorDefault, data.bytes.assumingMemoryBound(to: UInt8.self), data.length)! let result: OSStatus = SecPKCS12Import(cfdata, options, &rawItems) if result == errSecSuccess { let items = rawItems! as! [[String: Any]] let firstItem = items[0] let identity = firstItem[kSecImportItemIdentity as String] as! SecIdentity } -- UPDATE -- I made some more progress, and managed to extract the certificate in a DER format (which I haven't tried to convert to PEM so far - I believe it should be easy), but I still have no idea how to get the private key. if result == errSecSuccess { let items = rawItems! as! [[String: Any]] let firstItem = items[0] let identity = firstItem[kSecImportItemIdentity as String] as! SecIdentity var cert: SecCertificate? SecIdentityCopyCertificate(identity, &cert) var certDer = SecCertificateCopyData(cert!) //DER format var key: SecKey? SecIdentityCopyPrivateKey(identity, &key) let keyDict = SecKeyCopyAttributes(key!) //Not sure what we can find here }
Amazon AWS server side encryption in ios swift
In my app, I'm uploading the images attached by the user to S3 bucket in which server side encryption is used. We have used the following code in Android to achieve this and it WORKED. try { SSECustomerKey sseCustomerKey = new SSECustomerKey(BuildConfig.S3_AES_ENCRYPT_KEY); CognitoCachingCredentialsProvider sCredProvider = new CognitoCachingCredentialsProvider(mContext, AWSCognitoPoolId, Regions.fromName(Regions.US_EAST_1.getName())); AmazonS3Client sS3Client = new AmazonS3Client(sCredProvider); PutObjectRequest putRequest = new PutObjectRequest(BuildConfig.S3_BUCKET_NAME, file.getName(), file).withSSECustomerKey(sseCustomerKey); sS3Client.putObject(putRequest); sS3Client.setRegion(Region.getRegion(Regions.fromName(Regions.US_EAST_1.getName()))); } But in iOS, it is not working. Please find the following iOS code. let transferManager = AWSS3TransferManager.default() let uploadRequest = AWSS3TransferManagerUploadRequest() uploadRequest?.bucket = bucketName uploadRequest?.body = fileURL uploadRequest?.key = imageName[i] uploadRequest?.serverSideEncryption = .AES256 uploadRequest?.sseCustomerKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" uploadRequest?.contentType = "image/jpeg" transferManager.upload(uploadRequest!).continueWith(block: { (task) -> AnyObject? in if let error = task.error as NSError? { if error.domain == AWSS3TransferManagerErrorDomain as String { if let errorCode = AWSS3TransferManagerErrorType(rawValue: error.code) { switch (errorCode) { case .cancelled, .paused: DispatchQueue.main.async { } break; default: print("upload() failed: [\(error)]") break; } } else { print("upload() failed: [\(error)]") } } else { print("upload() failed: [\(error)]") } } return nil }) I get the following error in iOS upload() failed: [Error Domain=com.amazonaws.AWSS3ErrorDomain Code=0 "(null)" UserInfo={RequestId=C7302D0F4DD27397, HostId=Dm3itGpwZNcpPq28qfFkKDlB2VFbOzIYn01T270QzzVXJ9lmZWU2bX7oPXyXrG5A86OpfTrXSHw=, Message=Server Side Encryption with Customer provided key is incompatible with the encryption method specified, ArgumentValue=AES256, Code=InvalidArgument, ArgumentName=x-amz-server-side-encryption}] Please show me some light on this
I would recommend that you use TransferUtility instead of TransferManager. The TransferManager is on a deprecation path and doesn't have all the features that the TransferUtility has. Here is a code snippet showing how you can upload a file with server side encryption. let transferUtility = AWSS3TransferUtility.default() let uploadExpression = AWSS3TransferUtilityUploadExpression() uploadExpression.setValue("AES256", forRequestHeader: "x-amz-server-side-encryption") uploadExpression.progressBlock = {(task, progress) in print("Upload progress: ", progress.fractionCompleted) } let uploadCompletionHandler = { (task: AWSS3TransferUtilityUploadTask, error: Error?) -> Void in if let error = error { //Error completing transfer. Handle Error } else { //Successfully uploaded. ...... return nil } } transferUtility.uploadData( data, bucket: "bucket", key: "key", contentType: "contenttype", expression: uploadExpression, completionHandler: uploadCompletionHandler ).continueWith (block: { (task) -> Any? in if let error = task.error { //Error initiating transfer. Handle error } return nil }) } Here is a link to more information on how to use TransferUtility - https://docs.aws.amazon.com/aws-mobile/latest/developerguide/how-to-transfer-files-with-transfer-utility.html
Now it's been years but still this answer would help someone and save hours of searching which i have gone through, TransferManager is deprecated so now we are using transferUtility s3 to upload files, But if we want to encrypt the files we have to send 3 keys in the header expression.setValue("AES256", forRequestHeader: "x-amz-server-side-encryption-customer-algorithm") expression.setValue(base64String, forRequestHeader: "x-amz-server-side-encryption-customer-key") expression.setValue(md5String, forRequestHeader: "x-amz-server-side-encryption-customer-key-MD5") These 3 keys are necessary otherwise the transfer utility won't upload the file and give u an error, x-amz-server-side-encryption-customer-algorithm this key is use to tell which encryption algorithm u want to use, For the other 2 keys we have to generate them, Sample code is this to generate base64String and md5, There are many ways to generate the key you can look at the CryptoSwift docs, I have used Salt which makes it more secure then brute force attacks let input: Array<UInt8> = [0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9] let password: [UInt8] = Array("s33krit".utf8) let salt: [UInt8] = Array("nacllcan".utf8) let iv: Array<UInt8> = AES.randomIV(AES.blockSize) DispatchQueue.global().async { do { let key = try PKCS5.PBKDF2(password: password, salt: salt, iterations: 4096, keyLength: 32, variant: .sha2(.sha224)).calculate() let encrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(input) let base64String: String = encrypted.toBase64() let md5Data = encrypted.md5() let md5DataBase64 = md5Data.toBase64() print("Encrypted:\(encrypted),\n Base64String:\(base64String)") print("md5:\(md5Data),\n md5String:\(md5DataBase64)") completion(base64String,md5DataBase64) } catch { print(error) } } You have to use CryptoSwift to generate these md5 and base64String keys to send in the headers, This will upload the encrypted file to the AWS and to open it or decrypt it you have to use the same base64 key Hope this will help someone and save hours of time
How can I get a string from NSData and vice versa to send through QR code?
I need to send encrypted data through my QR code so I have encrypted some text. I wish to send string of this encrypted data through QR code to another device which can decrypt it. I am having trouble even getting the string from the encrypted data. I assume maybe encrypted data cannot be string (nil) so how can I transfer the data through QR code? Here is me trying to get string of the encrypted data: let data = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData! if let encryptedData = testCrypt(data, keyData:keyData, ivData:ivData, operation:UInt32(kCCEncrypt)) { let stringFromData = NSString(data: encryptedData, encoding: NSUTF8StringEncoding) print("stringFromData = \(stringFromData)") // nil } Here is function: func testCrypt(data:NSData, keyData:NSData, ivData:NSData, operation:CCOperation) -> NSData? { let keyBytes = UnsafePointer<UInt8>(keyData.bytes) let ivBytes = UnsafePointer<UInt8>(ivData.bytes) let dataLength = Int(data.length) let dataBytes = UnsafePointer<UInt8>(data.bytes) let cryptData: NSMutableData! = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128) let cryptPointer = UnsafeMutablePointer<UInt8>(cryptData.mutableBytes) let cryptLength = size_t(cryptData.length) let keyLength = size_t(kCCKeySizeAES128) let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128) let options: CCOptions = UInt32(kCCOptionPKCS7Padding) var numBytesEncrypted :size_t = 0 let cryptStatus = CCCrypt(operation, algoritm, options, keyBytes, keyLength, ivBytes, dataBytes, dataLength, cryptPointer, cryptLength, &numBytesEncrypted) if UInt32(cryptStatus) == UInt32(kCCSuccess) { cryptData.length = Int(numBytesEncrypted) } else { print("Error: \(cryptStatus)") } return cryptData; } Another solution I tried was to interpolate the NSData into string. This worked however I am stuck trying to get the string back to the NSData on the receiving end of WR code. I have the code to encrypt/decrypt I just need to figure out how to send the encrypted data over the QR code somehow. Here is my interpolation: let data = (message as NSString).dataUsingEncoding(NSUTF8StringEncoding) as NSData! if let encryptedData = testCrypt(data, keyData:keyData, ivData:ivData, operation:UInt32(kCCEncrypt)) { let stringFromData = "\(encryptedData)" print("\(stringFromData)") // correct }
Swift AES encryption using CommonCrypto
I am working on an iOS app on XCode 7.1 with Swift 2.1 and I am trying to do simple encryption with AES 128 bit and PKCS7 padding using CommonCrypto library. The code works but every time I try to cast the NSData object to NSString then to String I get a nil and the app crashes. I debugged the app and the NSData object is not nil. The error occurs when I try to unwrap the String optional. How to resolve this issue? and convert the NSData object to a String correctly? Here is my code static func AESEncryption(phrase: String,key: String,ivKey: String,encryptOrDecrypt: Bool) -> String { let phraseData = phrase.dataUsingEncoding(NSUTF8StringEncoding) let ivData = ivKey.dataUsingEncoding(NSUTF8StringEncoding) let keyData: NSData! = key.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! let keyBytes = UnsafePointer<Void>(keyData.bytes) let keyLength = size_t(kCCKeySizeAES128) let dataLength = Int(phraseData!.length) let dataBytes = UnsafePointer<Void>(phraseData!.bytes) let bufferData = NSMutableData(length: Int(dataLength) + kCCBlockSizeAES128)! let bufferPointer = UnsafeMutablePointer<Void>(bufferData.mutableBytes) let bufferLength = size_t(bufferData.length) let ivBuffer = UnsafePointer<Void>(ivData!.bytes) var bytesDecrypted = Int(0) let operation = encryptOrDecrypt ? UInt32(kCCEncrypt) : UInt32(kCCDecrypt) let algorithm: CCAlgorithm = UInt32(kCCAlgorithmAES128) let options: CCOptions = UInt32(kCCOptionPKCS7Padding) let cryptStatus = CCCrypt( operation, algorithm, options, keyBytes, keyLength, ivBuffer, dataBytes, dataLength, bufferPointer, bufferLength, &bytesDecrypted) if Int32(cryptStatus) == Int32(kCCSuccess) { bufferData.length = bytesDecrypted let data = bufferData as NSData let stringData = String(data: data,encoding: NSUTF8StringEncoding) print("After Operation: \(stringData)") return stringData! } else { print("Encryption Error: \(cryptStatus)") } return ""; }
The encrypted data will not be a valid UTF-8 string as it should be indistinguishable from random bits. If you need it in a string form you need to do something like base64 encode it or write out the hex values of the bytes. NSData has a base64EncodedDataWithOptions method which should produce a String.