AES encryption: Node.js, Swift & Android

Since the existing information on AES encryption and decryption using Node.js, Swift and Android is …

Terminology

AES, CBC – 

Initialization Vector – 

Node.js

 

const crypto = require('crypto');

let algorithm = 'aes-256-cbc';
let initializationVector = crypto.randomBytes(16); // IV is always 16-bytes
let key = crypto.randomBytes(32); // Using a 256 bit key

function encrypt(data) {
	var cipher = crypto.createCipheriv(algorithm, key, initializationVector)
	var crypted = cipher.update(data,'utf8','base64')
	crypted += cipher.final('base64');
	return crypted;
}
function decrypt(text) {
	let data = new Buffer(text, "base64")
	let decipher = crypto.createDecipheriv(algorithm, key, initializationVector);
	let decrypted = decipher.update(data);
	decrypted = Buffer.concat([decrypted, decipher.final()]);
	return decrypted.toString('utf8');
}

iOS: Swift

Just like with Node.js, all needed functionality is readily available. All you need to do is add ‘Security.framework’ and a bridging header containing the following:

#import <CommonCrypto/CommonCrypto.h>

func decrypt(data:Data, keyData:Data, ivData:Data) -> Data? {
        let keyLength = keyData.count
        let dataLength = data.count
        
        let validKeyLengths = [kCCKeySizeAES128, kCCKeySizeAES192, kCCKeySizeAES256]
        if (validKeyLengths.contains(keyLength) == false) {
            print("Invalid key length")
            return nil;
        }
        
        let clearLength = size_t(data.count)
        var clearData = Data(count:clearLength)
        
        var numBytesDecrypted :size_t = 0
        let options   = CCOptions(kCCOptionPKCS7Padding)
        
        
        let cryptStatus = clearData.withUnsafeMutableBytes {cryptBytes in
            data.withUnsafeBytes {dataBytes in
                ivData.withUnsafeBytes {ivBytes in
                    keyData.withUnsafeBytes {keyBytes in
                        CCCrypt(CCOperation(kCCDecrypt),
                                CCAlgorithm(kCCAlgorithmAES128),
                                options,
                                
                                keyBytes, //key bytes
                                keyLength, //key length
                            
                                ivBytes, //iv bytes
                                dataBytes, //iv bytes
                            
                                dataLength,
                                
                                cryptBytes,
                                clearLength,
                                &numBytesDecrypted)
                    }
                }
            }
        }
        
        if UInt32(cryptStatus) == UInt32(kCCSuccess) {
            clearData.count = numBytesDecrypted
        }
        else {
            print("decrypt failed")
            return nil;
//            throw AESError.CryptorError(("Decryption failed", Int(cryptStatus)))
        }
        
        return clearData;
    }

Android: Java

 

Further reading

Stronger Encryption and Decryption in Node.js

http://lollyrock.com/articles/nodejs-encryption/

https://coolaj86.com/articles/symmetric-cryptography-aes-with-webcrypto-and-node-js/