Search code examples
javascriptnode.jscryptojs

Encrypt text in Node.js and Decrypt from iOS app


I'm using the solution here current to encrypt text from Node.js and decrypt from an iOS app. https://stackoverflow.com/a/27893935/2977578

The encryption from Node.js works but CryptoJS is very slow. I'm trying to port this code to use the built-in crypto module in Node.js for speed but I'm not an expert in these functions. Is it possible to get this code to work just using the built-in crypto module?

var password = "...";
var salt = "...";
var iv64 = "...";
var hash = CryptoJS.SHA256(salt);
var key = CryptoJS.PBKDF2(password, hash, { keySize: 256/32, iterations: 1000 });
var iv  = CryptoJS.enc.Base64.parse(iv64);
var encrypted = CryptoJS.AES.encrypt(message, key, { iv: iv });
return encrypted.ciphertext.toString(CryptoJS.enc.Base64);

Solution

  • I've implemented this encryption logic using the built-in Node.js crypto module, I've encrypted the same plaintext using both the crypto-js function as well and decoded both to ensure the results are consistent:

    const CryptoJS = require('crypto-js');
    const crypto = require("crypto");
    
    function encrypt_cryptojs(message, password, iv64, salt) {
        var hash = CryptoJS.SHA256(salt);
        var key = CryptoJS.PBKDF2(password, hash, { keySize: 256/32, iterations: 1000 });
        var iv  = CryptoJS.enc.Base64.parse(iv64);
        var encrypted = CryptoJS.AES.encrypt(message, key, { iv: iv });
        return encrypted.ciphertext.toString(CryptoJS.enc.Base64);
    }
    
    // Use built-in crypto module.
    function encrypt(message, password, iv64, salt) {
        const iv = Buffer.from(iv64, 'base64');
        const hash = crypto.createHash('sha256').update(salt, 'utf8').digest()
        const key = crypto.pbkdf2Sync(password, hash, 1000, 32, null);
    
        const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
        let encrypted = cipher.update(message, 'utf8', 'base64')
        encrypted += cipher.final('base64');
        return encrypted;
    }
    
    function decrypt(messagebase64, password, iv64) {
    
        const iv = Buffer.from(iv64, 'base64');
        const hash = crypto.createHash('sha256').update(salt, 'utf8').digest()
        const key = crypto.pbkdf2Sync(password, hash, 1000, 32, null);
    
        const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
        let decrypted = decipher.update(messagebase64, 'base64');
        decrypted += decipher.final();
        return decrypted;
    }
    
    const plaintext = "If you prick us do we not bleed? If you tickle us do we not laugh";
    const salt = "some salt";
    const password = crypto.scryptSync("some password", salt, 16).toString("base64");
    const iv64 = "XxbSho8OZacvQwXC6S5RQw==";
    
    console.log("Ciphertext (crypto js):", encrypt_cryptojs(plaintext, password, iv64, salt));
    console.log("Ciphertext (built-in crypto module):", encrypt(plaintext, password, iv64, salt));
    console.log("Decrypted (crypto js):", decrypt(encrypt_cryptojs(plaintext, password, iv64, salt), password, iv64));
    console.log("Decrypted (built-in crypto module):", decrypt(encrypt(plaintext, password, iv64, salt), password, iv64));