javascriptswiftreact-nativeaescommoncrypto

How to decrypt in swift using CommonCrypto


I am building an IOS app and it communicates with the JS. So the communication between the two ends must be encrypted. So my main intention is to encrypt from Javascript side and send it to the IOS app mobile end, and the mobile app should decrypt the data. This is how I have done on Javascript side and it works fine as expected,

 const key = CryptoJS.enc.Utf8.parse("MY SECRET KEY 123");
 const iv = CryptoJS.enc.Utf8.parse("ui09ji884uh88984");
 var encrypted = CryptoJS.AES.encrypt("Hello world",key, {
                           mode: CryptoJS.mode.CBC,
                           padding: CryptoJS.pad.Pkcs7,
                           iv: iv
                    });
 console.log("Encrypted data ="+encrypted);

The issue is how I can decrypt this encrypted data in swift using CommonCrypto. Since this is plain base64 text how can we feed it to decryption? The code I have done so far in swift is posted below,

func testCrypt(data data:[UInt8], keyData:[UInt8], ivData:[UInt8], operation:Int) -> [UInt8]? {
    let cryptLength  = size_t(data.count+kCCBlockSizeAES128)
    var cryptData    = [UInt8](repeating: 0, count:cryptLength)

    let keyLength             = size_t(kCCKeySizeAES128)
    let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
    let options:  CCOptions   = UInt32(kCCOptionPKCS7Padding)

    var numBytesEncrypted :size_t = 0

    let cryptStatus = CCCrypt(CCOperation(operation),
                              algoritm,
                              options,
                              keyData,
                              keyLength,
                              ivData,
                              data,
                              data.count,
                              &cryptData,
                              cryptLength,
                              &numBytesEncrypted)

    if UInt32(cryptStatus) == UInt32(kCCSuccess) {
//      cryptData.remove
        cryptData.removeSubrange(numBytesEncrypted..<cryptData.count)

    } else {
        print("Error: \(cryptStatus)")
    }

    return cryptData;
}

This is the way I have called the above method,

let message       = "Hello world"
let messageData   = Array(message.utf8)
let keyData       = Array("MY SECRET KEY 123".utf8)
let ivData        = Array("ui09ji884uh88984".utf8)
                  
let str = ".."//THIS IS THE ENCRYPTED TEXT FROM JS
let buf = Array(str.utf8)
print("BUFF: ", buf)
                  
let encryptedData = testCrypt(data:messageData,   keyData:keyData, ivData:ivData, operation:kCCEncrypt)!
let decryptedData = testCrypt(data:encryptedData, keyData:keyData, ivData:ivData, operation:kCCDecrypt)!
var decrypted     = String(bytes:decryptedData, encoding:String.Encoding.utf8)!

This works fine if we do both the encryption and decryption and passing the encrypted byte array for decryption. But when I try to convert the encrypted text in to a byte array and passing it to it, an exception occurs. And also the one which I convert (eg: buf) and which the testCrypt returns after encrypting (eg: encryptedData) isn't similar. Please can anyone elaborate this and provide a solution will be greatly appreciated.


Solution

  • Ok I found the issue. Before converting it to a UInt8 Array you need to convert it to a data object and then convert it to UInt8 array for feeding. So the code in swift should look like this,

    let str = "SJeOvypKWad9GzUD2GHRig=="
    let data = Data(base64Encoded: str);
    let buf: [UInt8] = Array(data!)