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
}
}
Related
How can I merge files in Swift / iOS ? The FileManager can move and copy items but I've seen nothing about merging files. I'd like to have something like
FileManager.default.merge(files: [URL], to location: URL) throws
Files can potentially be big, so I'd rather avoid having to pass their data in memory.
=== here is my own in memory merge:
let data = NSMutableData()
files.forEach({ partLocation in
guard let partData = NSData(contentsOf: partLocation) else { return }
data.append(partData as Data)
do {
try FileManager.default.removeItem(at: partLocation)
} catch {
print("error \(error)")
}
})
data.write(to: destination, atomically: true)
Here is my own solution (thanks #Alexander for the guidance)
extension FileManager {
func merge(files: [URL], to destination: URL, chunkSize: Int = 1000000) throws {
try FileManager.default.createFile(atPath: destination.path, contents: nil, attributes: nil)
let writer = try FileHandle(forWritingTo: destination)
try files.forEach({ partLocation in
let reader = try FileHandle(forReadingFrom: partLocation)
var data = reader.readData(ofLength: chunkSize)
while data.count > 0 {
writer.write(data)
data = reader.readData(ofLength: chunkSize)
}
reader.closeFile()
})
writer.closeFile()
}
}
func merge(files: [URL], to destination: URL, chunkSize: Int = 100000000) {
for partLocation in files {
// create a stream that reads the data above
let stream: InputStream
stream = InputStream.init(url: partLocation)!
// begin reading
stream.open()
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: chunkSize)
// var writeData : Data = Data()
while stream.hasBytesAvailable {
let read = stream.read(buffer, maxLength: chunkSize)
var writeData:Data = Data()
writeData.append(buffer, count: read) enter code here
if let outputStream = OutputStream(url: destination, append: true) {
outputStream.open()
writeData.withUnsafeBytes { outputStream.write($0, maxLength: writeData.count) }
outputStream.close()
writeData.removeAll()
}
}
stream.close()
buffer.deallocate(capacity: chunkSize)
}
}
Hello i am currently going crazy with alamofire :).
What I'm trying to do is to disable evaluation because server has no valid SSL certificate but I have to connect by https and I have to send a x509 certificate made on IOS device by OpenSSL
I am currently using alamofire 4 and I was trying to do:
open class CertTrustPolicyManager: ServerTrustPolicyManager {
open override func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? {
let policy = ServerTrustPolicy.disableEvaluation;
// let policy = ServerTrustPolicy.pinCertificates(certificates: [certificateToPin], validateCertificateChain: true, validateHost: false);
// var policy = ServerTrustPolicy.pinCertificates(certificates: [certificateToPin], validateCertificateChain: false, validateHost: false);
return policy
}
let trustPolicies = CertTrustPolicyManager(policies: [:])
let alamofireManager:SessionManager = Alamofire.SessionManager(configuration: configuration, delegate: SessionDelegate(), serverTrustPolicyManager: trustPolicies)
also trying
var serverTrustPolicy:[String: ServerTrustPolicy] = [
Router.baseURLString : .pinCertificates(
certificates: [certificateToPin],
validateCertificateChain: false,
validateHost: false)
]
let alamofireManager:SessionManager = Alamofire.SessionManager(configuration: configuration, delegate: SessionDelegate(), serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicy))
First approach with
let policy = ServerTrustPolicy.disableEvaluation;
gave me successful connection but then I'm unable to pin certificate ( or I don't know how)
second approach produces and god knows whats next :)
2017-05-10 08:37:13.801894+0200 App[10117:1120893] [] nw_coretls_callback_handshake_message_block_invoke_3 tls_handshake_continue: [-9812]
2017-05-10 08:37:13.802 App[10117:1120907] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
I don't even know if I'm sending it correctly.
any tips?
EDIT this made my connection good but I'm not sending certificate
alamofireManager.delegate.sessionDidReceiveChallenge = { session, challenge in
var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling
var credential: URLCredential?
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
disposition = URLSession.AuthChallengeDisposition.useCredential
credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
} else {
if challenge.previousFailureCount > 0 {
disposition = .cancelAuthenticationChallenge
} else {
credential = alamofireManager.session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace)
if credential != nil {
disposition = .useCredential
}
}
}
return (disposition, credential)
}
Cheers
Problem self solved.
now the answer for SENDING CLIENT SIDE CERTIFICATE maybe someone will need it :)
We need PKCS12 to send certificate so
import Foundation
public class PKCS12 {
let label:String?
let keyID:NSData?
let trust:SecTrust?
let certChain:[SecTrust]?
let identity:SecIdentity?
public init(PKCS12Data:NSData,password:String)
{
let importPasswordOption:NSDictionary = [kSecImportExportPassphrase as NSString:password]
var items : CFArray?
let secError:OSStatus = SecPKCS12Import(PKCS12Data, importPasswordOption, &items)
guard secError == errSecSuccess else {
if secError == errSecAuthFailed {
NSLog("ERROR: SecPKCS12Import returned errSecAuthFailed. Incorrect password?")
}
fatalError("SecPKCS12Import returned an error trying to import PKCS12 data")
}
guard let theItemsCFArray = items else { fatalError() }
let theItemsNSArray:NSArray = theItemsCFArray as NSArray
guard let dictArray = theItemsNSArray as? [[String:AnyObject]] else { fatalError() }
func f<T>(key:CFString) -> T? {
for d in dictArray {
if let v = d[key as String] as? T {
return v
}
}
return nil
}
self.label = f(key: kSecImportItemLabel)
self.keyID = f(key: kSecImportItemKeyID)
self.trust = f(key: kSecImportItemTrust)
self.certChain = f(key: kSecImportItemCertChain)
self.identity = f(key: kSecImportItemIdentity)
}
}
extension URLCredential {
public convenience init?(PKCS12 thePKCS12:PKCS12) {
if let identity = thePKCS12.identity {
self.init(
identity: identity,
certificates: thePKCS12.certChain,
persistence: URLCredential.Persistence.forSession)
}
else { return nil }
}
}
we need x509 also to do PKCS12 I was in need of generating certificates dynamically so theres the code bridged from C
-(void) createX509{
OPENSSL_init();
NSString *docPath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/cert"];
NSString *docPathKey = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/key"];
NSString *docPathp12 = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/p12"];
NSString *dataFile = [NSString stringWithContentsOfFile:docPath
encoding:NSUTF8StringEncoding
error:NULL];
FILE *fp = fopen(docPath.UTF8String, "r");
if(fp == NULL){
fp = fopen(docPath.UTF8String, "w+");
FILE *fpKey = fopen(docPathKey.UTF8String, "w+");
EVP_PKEY * pkey;
pkey = EVP_PKEY_new();
RSA * rsa;
rsa = RSA_generate_key(
2048, /* number of bits for the key - 2048 is a sensible value */
RSA_F4, /* exponent - RSA_F4 is defined as 0x10001L */
NULL, /* callback - can be NULL if we aren't displaying progress */
NULL /* callback argument - not needed in this case */
);
EVP_PKEY_assign_RSA(pkey, rsa);
X509 * x509;
x509 = X509_new();
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
X509_gmtime_adj(X509_get_notBefore(x509), 0);
X509_gmtime_adj(X509_get_notAfter(x509), 31536000000L);
X509_set_pubkey(x509, pkey);
X509_NAME * name;
name = X509_get_subject_name(x509);
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
(unsigned char *)"CA", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
(unsigned char *)"company", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
(unsigned char *)"localhost", -1, -1, 0);
X509_set_issuer_name(x509, name);
X509_sign(x509, pkey, EVP_sha1());
[#"" writeToFile:docPath
atomically:YES
encoding:NSUTF8StringEncoding
error:NULL];
fp = fopen(docPath.UTF8String, "a+");
PEM_write_X509(
fp, /* write the certificate to the file we've opened */
x509 /* our certificate */);
PEM_write_PrivateKey(fpKey, pkey, NULL, NULL, 0, NULL, NULL);
fflush(fpKey);
fclose(fpKey);
fflush(fp);
fclose(fp);
dataFile = [NSString stringWithContentsOfFile:docPath
encoding:NSUTF8StringEncoding
error:NULL];
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
OpenSSL_add_all_digests();
PKCS12* p12;
p12 = PKCS12_create("password", "login", pkey, x509, NULL, 0,0,0,0,0);
if(!p12) {
fprintf(stderr, "Error creating PKCS#12 structure\n");
ERR_print_errors_fp(stderr);
exit(1);
}
fp = fopen(docPathp12.UTF8String, "w+");
if (!(fp = fopen(docPathp12.UTF8String, "wb"))) {
ERR_print_errors_fp(stderr);
exit(1);
}
i2d_PKCS12_fp(fp, p12);
PKCS12_free(p12);
fflush(fp);
fclose(fp);
}
The pkcs12 and x05 is now made so we continue in swift
public let alamofireManager: SessionManager = {
let obj = OpenSSL();
obj.createX509()
var path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first;
var certPEM:String!;
var keyPEM:String!;
var certificateToPin:SecCertificate!;
var pkcs12:PKCS12?;
do{
try certPEM = String(contentsOfFile: path! + "/cert").replacingOccurrences(of: "\n", with: "")
try keyPEM = String(contentsOfFile: path! + "/key").replacingOccurrences(of: "\n", with: "")
let p12 = NSData(contentsOfFile: path! + "/p12");
pkcs12 = PKCS12.init(PKCS12Data: p12!, password: "password")
let docsurl = try! FileManager.default.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let urlAp = docsurl.appendingPathComponent("cert");
var cert64 = certPEM.replacingOccurrences(of: "-----BEGIN CERTIFICATE-----", with: "")
cert64 = cert64.replacingOccurrences(of: "-----END CERTIFICATE-----", with: "")
let certificateData = NSData(base64Encoded: cert64, options: .ignoreUnknownCharacters)
certificateToPin = SecCertificateCreateWithData(kCFAllocatorMalloc, certificateData!)
var trust: SecTrust?
let policy = SecPolicyCreateBasicX509()
let status = SecTrustCreateWithCertificates(certificateToPin!, policy, &trust)
let publicKey:SecKey?;
if status == errSecSuccess {
publicKey = SecTrustCopyPublicKey(trust!)!;
}
let dictionary = SecPolicyCopyProperties(policy)
}catch{
print("err")
}
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForResource = Request.settings.timeout
let trustPolicies = CertTrustPolicyManager(policies: [:])
var serverTrustPolicy:[String: ServerTrustPolicy] = [
Router.baseURLString : .pinCertificates(
certificates: [certificateToPin],
validateCertificateChain: false,
validateHost: false)
]
var alamofireManager:SessionManager = Alamofire.SessionManager(configuration: configuration, delegate: SessionDelegate(), serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicy))
alamofireManager.delegate.sessionDidReceiveChallenge = { session, challenge in
var disposition: URLSession.AuthChallengeDisposition = .useCredential
var credential: URLCredential?
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
disposition = URLSession.AuthChallengeDisposition.useCredential
credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
} else {
if challenge.previousFailureCount > 0 {
disposition = .cancelAuthenticationChallenge
} else {
credential = alamofireManager.session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace)
if credential != nil {
disposition = .useCredential
}
}
}
let certs = [certificateToPin]
let persist = URLCredential.Persistence.forSession;
return (disposition, URLCredential.init(PKCS12: pkcs12!))
}
return alamofireManager
}()
There I was in need to get certificates, probably some of code is useless or badly wrote but its working ( I'm new to IOS :) ), I was also converting PEM certificates to DER there but after these operations I was finally able to do insecure connection with sending client side and created certificate with Alamofire.
The code above is gathered from everywhere!
Cheers
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
}
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}
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.