Source: cripto.js

/**
 * 
 * @description Functions for AES256-GCM encryption/decryption and Argon2 hashing.<br>
 * This module provides functions to generate an AES key, encrypt and decrypt messages,
 * and hash and verify passwords using Argon2.<br>
 * It uses the PyCryptodome library for AES encryption and Argon2 for password hashing.<br>
 * It is important to note that the AES key should be kept secret and secure.<br>
 * The Argon2 hash should also be stored securely, as it is used to verify passwords.<br>
 * This module is intended for educational purposes and should not be used in 
 * production without proper security measures.<br>

 * @author RAFAEL PERAZZO B MOTA
 * @date Date: 2025-03-30
 * @version 1.0.3
 * 
 */
var crypto = require('crypto');
const argon2 = require('argon2');

/**
 * Converts a hex string to a Uint8Array.
 * @param {string} hexString - The hex string to convert.
 * @returns {Uint8Array} - The converted Uint8Array.
 */
function hexString2bytes(hexString) {
    const convertido = Uint8Array.from(Buffer.from(hexString, 'hex'));
    return convertido;
}

/**
 * Encrypts a message using AES256-GCM encryption.
 * @param {string} text - The message to encrypt.
 * @param {Uint8Array} key - The AES key to use for encryption.
 * @returns {string} - The encrypted message in hex format.
 */
function encrypt_gcm(text, key) {
    if (typeof key === 'string') {
        key = hexString2bytes(key);
    }
    var iv = crypto.randomBytes(16);
    var cipher = crypto.createCipheriv('aes-256-gcm', Buffer.from(key), iv);
    var encrypted = cipher.update(text, 'utf8', 'hex');
    encrypted += cipher.final('hex');
    var tag = cipher.getAuthTag();
    encrypted = iv.toString('hex') + ':' + tag.toString('hex') + ':' + encrypted;
    return encrypted;
}

/**
 * Decrypts a message using AES256-GCM encryption.
 * @param {string} text - The message to decrypt.
 * @param {Uint8Array} key - The AES key to use for decryption.
 * @returns {string} - The decrypted message.
 */
function decrypt_gcm(text, key) {
    if (typeof key === 'string') {
        key = hexString2bytes(key);
    }
    var iv = text.split(':')[0];
    var tag = text.split(':')[1];
    text = text.split(':')[2];
    var decipher = crypto.createDecipheriv('aes-256-gcm', Buffer.from(key), Buffer.from(iv, 'hex'));
    decipher.setAuthTag(Buffer.from(tag, 'hex'));
    var decrypted = decipher.update(text, 'hex', 'utf8');
    decrypted += decipher.final('utf8');
    return decrypted;
}

/**
 * Generates a HMAC using SHA3-512.
 * @param {Uint8Array} key - The key to use for HMAC generation.
 * @param {string} data - The data to hash.
 * @returns {string} - The HMAC in hex format.
 */
function hmac(key, data) {
    if (typeof key === 'string') {
        key = hexString2bytes(key);
    }
    var hmac = crypto.createHmac('sha3-512', key);
    hmac.update(data);
    return hmac.digest('hex');
}

/**
 * Hashes a password using Argon2.
 * @param {string} password - The password to hash.
 * @returns {string} - The hashed password.
 */
async function hashPassword(password) {
    return await argon2.hash(password);;
}

/**
 * Verifies a password against a hash using Argon2.
 * @param {string} password - The password to verify.
 * @param {string} hash - The hash to verify against.
 * @returns {boolean} - True if the password matches the hash, false otherwise.
 * @throws {Error} - If the password does not match the hash.
 */
async function verifyPassword(password, hash) {
    try {
        return await argon2.verify(hash, password);
    }
    catch (err) {
        return false;
    }
}

/**
 * Returns the author of the module.
 * @returns {string} - The author of the module.
 */
function author() {
    return 'RAFAEL PERAZZO B MOTA';
}

module.exports = {
    encrypt_gcm,
    decrypt_gcm,
    hmac,
    hashPassword,
    verifyPassword
};