Search code examples
javascriptnode.jsencryptionencodingscrypt

ScryptSync Key Cannot Be Used in createCipheriv, Nodejs, Crypto lib


I am new to topics related to encoding and I am having troubles with being able to convert my scryptsync key into something createCipheriv (Crypto library integrated into Nodejs) can use in the iv parameter.

const algorithm = 'aes-256-gcm';
var text = 'default'
var encrypted = secret;

class Auth
{

SignUp(pass)
{
    console.log(pass);

    var pair = ec.genKeyPair(); 

    text = pair.getPrivate.toString('hex');

    var key = crypto.scryptSync(pass, 'baethrowssalt', 32);

    console.log(`The key is:${key}`); //this is not a string

    key=key.toString('hex');

    var cipher = crypto.createCipheriv(algorithm, key);  

    var encrypted = cipher.update(text, 'hex', 'hex') + cipher.final('hex');

    fs.writeFileSync(file, encrypted);

    return alert(`Close and reopen your app to integrate your wallet securely`);
}

as you can see above, I tried converting the scryptSync return to string hex so that createCipheriv is willing to use it, but I get the following error:

pass is passrig
passrig
The key is:�→A�r;yR�����▲�h�8��f�����v�A�,
TypeError [ERR_INVALID_ARG_TYPE]: The "iv" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received undefined
    at Cipheriv.createCipherWithIV (internal/crypto/cipher.js:120:29)
    at new Cipheriv (internal/crypto/cipher.js:227:22)
    at Object.createCipheriv (crypto.js:117:10)

So my question contains two parts: how can I use scryptSync with the createCipheriv? To help me understand, what are the reasons behind your solutions?


Solution

  • I've created an example that encrypts some data using the algorithm aes-256-gcm and uses crypto.scryptSync to derive the key from a password.

    The steps are as follows:

    1. Derive our key from our password using crypto.scryptSync.
    2. Create an IV using crypto.randomBytes.
    3. Use our key and iv to encrypt the plaintext using our encrypt function.
    4. Test our encrypted data by decrypting using our decrypt function.

    This code is as follows:

    const crypto = require("crypto");
    const Algorithm = "aes-256-gcm";
    
    function encrypt(plainText, key, iv) {
        const cipher = crypto.createCipheriv(Algorithm, key, iv);
        return { encrypted: Buffer.concat([cipher.update(plainText), cipher.final()]), authTag: cipher.getAuthTag() }
    }
    
    function decrypt(encrypted, key, iv, authTag) {
        const decipher = crypto.createDecipheriv(Algorithm, key, iv).setAuthTag(authTag);
        return Buffer.concat([decipher.update(encrypted), decipher.final()]);
    }
    
    const password = "Speak Friend and Enter";
    const plainText = "There is nothing either good or bad but thinking makes it so.";
    
    const salt = crypto.randomBytes(32);
    
    // Create an encryption key from our password, ensuring it is 32 bytes long - AES-256 needs a 256 bit (32 byte) key 
    const KEY = crypto.scryptSync(password, salt, 32);
    const IV = crypto.randomBytes(16);
    
    console.log("Key (derived from password, hex):", KEY.toString("hex"));
    console.log("IV (hex):", IV.toString("hex"));
    console.log("Plaintext:", plainText);
    const { encrypted, authTag } = encrypt(plainText, KEY, IV);
    console.log("Encrypted (hex):", encrypted.toString("hex"));
    const decrypted = decrypt(encrypted, KEY, IV, authTag)
    console.log("Decrypted:", decrypted.toString("utf-8"));