JavaScript Encryption and Decryption with Password

Keeping your data safe is super important right now. One good way to make sure your information is protected is by using encryption. This guide will show you how to encrypt and decrypt data using JavaScript and a password.

What is Encryption?

Encryption is when you change plain text into a secret code so people can't read it without permission. Decryption is the opposite, converting the secret code back into normal text. With a password, you can make sure only the right people can see the decoded information.

Demo

Online Text Encryption and Decryption Tool

This online tool can encrypt and decrypt various data types including any text, array and object with password. It uses a secret password key for maximum security to protect your text.

Paste your text here for encryption

Paste your encrypted text here for decryption

JavaScript Encryption Description Crypto Function

Here is an example of how you can use JavaScript to encrypt and decrypt data with a password. For this, we'll utilize the Web Cryptography API available through window.crypto.

The Web Cryptography API is a set of standardized interfaces that allow web applications to perform cryptographic operations, such as hashing, encryption, and decryption.

JavaScript
/**
 * Creates a crypto module with encryption and decryption capabilities.
 * This module uses AES-GCM encryption with PBKDF2 key derivation.
 * @returns {Object} An object with encrypt and decrypt methods.
 */
const createCrypto = () => {
    // Helper functions
    // created https://www.html-code-generator.com/javascript/data-encryption-decryption-with-password
    /**
     * Converts an ArrayBuffer to a hexadecimal string.
     * @param {ArrayBuffer} buffer - The buffer to convert.
     * @returns {string} The hexadecimal representation of the buffer.
     */
    const arrayBufferToHex = (buffer) =>
        Array.from(new Uint8Array(buffer))
        .map(b => b.toString(16).padStart(2, "0"))
        .join("");

    /**
     * Converts a hexadecimal string to a Uint8Array.
     * @param {string} hexString - The hexadecimal string to convert.
     * @returns {Uint8Array} The resulting Uint8Array.
     */
    const hexToUint8Array = (hexString) =>
        new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));

    /**
     * Derives a cryptographic key from a password using PBKDF2.
     * @param {string} password - The password to derive the key from.
     * @param {Uint8Array} salt - The salt for key derivation.
     * @param {string[]} keyUsage - The intended usage of the key (e.g., ["encrypt"] or ["decrypt"]).
     * @returns {Promise<CryptoKey>} A promise that resolves to the derived key.
     */
    const deriveKey = async (password, salt, keyUsage) => {
        const enc = new TextEncoder();
        const keyMaterial = await window.crypto.subtle.importKey(
            "raw",
            enc.encode(password), {
                name: "PBKDF2"
            },
            false,
            ["deriveBits", "deriveKey"]
        );
        return window.crypto.subtle.deriveKey({
                name: "PBKDF2",
                salt,
                iterations: 100000,
                hash: "SHA-256"
            },
            keyMaterial, {
                name: "AES-GCM",
                length: 256
            },
            false,
            keyUsage
        );
    };

    // Validation functions
    /**
     * Validates the input data type.
     * @param {any} data - The data to validate.
     * @throws {Error} If the data type is invalid.
     */
    const validateData = (data) => {
        const validTypes = ["string", "number", "boolean", "object"];
        const type = typeof data;
        if (!validTypes.includes(type) || (type === "object" && data === null)) {
            throw new Error(`Invalid data type. Expected one of ${validTypes.join(", ")}, but got ${type === "object" && data === null ? "null" : type}`);
        }
    };

    /**
     * Validates the password.
     * @param {string|number} password - The password to validate.
     * @throws {Error} If the password is invalid.
     */
    const validatePassword = (password) => {
        if (typeof password !== "string" && typeof password !== "number") {
            throw new Error("Password must be a string or a number");
        }
        if (password.toString().length < 2) {
            throw new Error("Password must be at least 2 characters");
        }
    };

    /**
     * Encrypts the given data using AES-GCM encryption.
     * @param {any} data - The data to encrypt. Can be a string, number, boolean, or object.
     * @param {string|number} password - The password to use for encryption.
     * @returns {Promise<string>} A promise that resolves to the encrypted data as a hexadecimal string.
     * @throws {Error} If the input data or password is invalid.
     */
    const encrypt = async (data, password) => {
        validateData(data);
        validatePassword(password);
        const enc = new TextEncoder();
        const salt = window.crypto.getRandomValues(new Uint8Array(16));
        const iv = window.crypto.getRandomValues(new Uint8Array(12));
        const dataString = typeof data === "string" ? data : JSON.stringify(data);
        const dataBytes = enc.encode(dataString);
        const key = await deriveKey(password.toString(), salt, ["encrypt"]);
        const encryptedData = await window.crypto.subtle.encrypt({
                name: "AES-GCM",
                iv
            },
            key,
            dataBytes
        );
        // Combine salt, iv, and encrypted data into a single Uint8Array
        const result = new Uint8Array(salt.length + iv.length + encryptedData.byteLength);
        result.set(salt, 0);
        result.set(iv, salt.length);
        result.set(new Uint8Array(encryptedData), salt.length + iv.length);
        return arrayBufferToHex(result.buffer);
    };

    /**
     * Decrypts the given encrypted data using AES-GCM decryption.
     * @param {string} encryptedText - The encrypted data as a hexadecimal string.
     * @param {string|number} password - The password to use for decryption.
     * @returns {Promise<any>} A promise that resolves to the decrypted data. If the original data was JSON, it will be parsed.
     * @throws {Error} If the encrypted text or password is invalid.
     */
    const decrypt = async (encryptedText, password) => {
        if (typeof encryptedText !== "string") {
            throw new Error("encryptedText must be a string");
        }
        validatePassword(password);
        const data = hexToUint8Array(encryptedText);
        const salt = data.slice(0, 16);
        const iv = data.slice(16, 28);
        const encryptedContent = data.slice(28);
        const key = await deriveKey(password.toString(), salt, ["decrypt"]);
        const decryptedData = await window.crypto.subtle.decrypt({
                name: "AES-GCM",
                iv
            },
            key,
            encryptedContent
        );
        const dec = new TextDecoder();
        const decryptedString = dec.decode(decryptedData);
        // Attempt to parse the decrypted data as JSON, return as string if parsing fails
        try {
            return JSON.parse(decryptedString);
        } catch (e) {
            return decryptedString;
        }
    };
    return {
        encrypt,
        decrypt
    };
};

Download this JavaScript function

Download JS

Example Usage

This script demonstrates how to encrypt a string ("Hello, World!") and then decrypt it back using a password. You can modify the data and password variables to use your own values.

JavaScript
// Create an instance of the crypto module
const cryptoModule = createCrypto();

// String encrypt
const data = "Hello, world!";
const password = "12345678";

// Encrypt the data
cryptoModule.encrypt(data, password)
    .then(encryptedData => {
        console.log("Encrypted Data:", encryptedData);
    }).catch(error => {
        console.error("Error:", error);
    });

// Decrypt the data
const encryptedString = "1196e2ccf04cfef79a2c407f090bfaf66f08b557a4c8a5d8ac40582ce1338b5b3cf452ef2a755d4d7e6960c3f1b74a9ca1c406e4cb26a5484d";
const oldPassword = "12345678";

cryptoModule.decrypt(encryptedString, oldPassword)
    .then(decryptedData => {
        console.log("Decrypted Data:", decryptedData);
    }).catch(error => {
        console.error("Error:", error);
    });

Advanced Examples

Examples With Different Data Types.

JavaScript
// different data types. array, object, number, boolean, object
const testCases = [
    "Hello, 世界! Здравствуй, мир! 你好,世界!", // string
    42, // number
    true, // boolean
    { name: "John", age: 30, languages: ["English", "日本語", "Русский"] }, // object
    [1, "two", { three: 3 }] // array
];

// Create an instance of the crypto module
const cryptoModule = createCrypto();

const password = "MySecretPassword123";

testCases.forEach(item => {
    cryptoModule.encrypt(item, password)
        .then(encrypted => {
            console.log("Encrypted:", encrypted);
            return cryptoModule.decrypt(encrypted, password);
        })
        .then(decrypted => {
            console.log("Decrypted:", decrypted);
        })
        .catch(error => {
            console.error("Error:", error.message);
        });
});

Encrypting and Decrypting JSON Data

When you give a data object or array to the Decrypt function, it returns the original object. There is no need to parse the data.

These advanced examples demonstrate how to handle file and JSON data encryption and decryption.

JavaScript
// example JSON object
const dataObject = {
        "name": "John",
        "age": 30,
        "city": "India"
    };
const password = "MySecretPassword123";

// Create an instance of the crypto module
const cryptoModule = createCrypto();


cryptoModule.encrypt(dataObject, password)
    .then(encrypted => {
        console.log("Encrypted object:", encrypted);
    })
    .catch(error => {
        console.error("Error:", error.message);
    });

Decrypting JSON Data

JavaScript
// Encrypted JSON object
const encryptedObject = "06e09f08535cf85f78decb4c47f974934590126cdfc5f66db49b668e0626dd35f3b3f90d948dc682ec28826df38e05caff2d964b75407500954623bb62cb348f44615bd1e68da61ce7fb16fdf625eef407418d92625ef3619dd68d5ed02d70b5a76fae6f0534";
const password = "MySecretPassword123";

// Create an instance of the crypto module
const cryptoModule = createCrypto();

cryptoModule.decrypt(encryptedObject, password)
    .then(encrypted => {
        console.log("Encrypted object:", encrypted);
        // return parsed object {}
    })
    .catch(error => {
        console.error("Error:", error.message);
    });

With async Functions

Here is how you can create async functions to encrypt and decrypt data.

Encrypt Function

JavaScript
// Usage example
const encryptText = async () => {
    const cryptoModule = createCrypto();
    const data = "Hello, World!";
    const password = "12345678";
    try {
        const encryptedString = await cryptoModule.encrypt(data, password);
        console.log("Encrypted Data:", encryptedString);
    } catch (error) {
        console.error("Error during encryption:", error);
    }
};

encryptText();

Decrypt Function

JavaScript
// Usage example
const decryptText = async () => {
    const cryptoModule = createCrypto();
    const encryptedText = "1196e2ccf04cfef79a2c407f090bfaf66f08b557a4c8a5d8ac40582ce1338b5b3cf452ef2a755d4d7e6960c3f1b74a9ca1c406e4cb26a5484d";
    const password = "12345678";
    try {
        const decryptedString = await cryptoModule.decrypt(encryptedText, password);
        console.log("Decrypted Data:", decryptedString);
    } catch (error) {
        console.error("Error during encryption:", error);
    }
};

decryptText();

Browser Compatibility

The Web Cryptography API is widely supported across modern browsers

  • Google Chrome: Version 37 and later
  • Mozilla Firefox: Version 34 and later
  • Microsoft Edge: All versions
  • Safari: Version 7.1 and later