crypto - Node.js

  • 作成日:
  • 最終更新日:2025/06/25

crypto とは?

Node.js の暗号化機能を提供するモジュール

暗号化とハッシュ化の違いは、暗号化は、元のデータを特定の鍵を用いて変換し、権限を持つ者のみがそのデータを復元できるようにする仕組みです。

これに対し、ハッシュ化は一度暗号化されたデータを元の状態に戻すことはできません。

シークレットキーの作成

crypto.scryptSync 関数は、パスワードベースのキー導出関数です。

パスワードベースのキー導出関数とは、元となるパスワードから安全な暗号キーを生成するための特殊なアルゴリズムを用いた関数です。

salt の値は、すくなくとも16バイトの長さにすることが推奨されています。

const crypto = require("crypto");

const secret = "secret";
const salt = "AkdioaA38GDAKkaeei";

const key = crypto.scryptSync(secret, salt, 32);
console.log(key.toString("hex"));

関数化

function generateKey(){
    const secret = "secret";
    const salt = "AkdioaA38GDAKkaeei"; 
    const key = crypto.scryptSync(secret, salt, 32);
    return key
}

ランダムなソルトを作成するには、以下のようにします。

const crypto = require('crypto');

// ランダムな16バイトのソルトを生成する
const salt = crypto.randomBytes(16).toString('hex');
console.log(salt);

暗号化と複合化

crypto がサポートする暗号化アルゴリズムを調べるには以下のようにします。

const crypto = require("crypto");
const cipers = crypto.getCiphers();

console.log(cipers);
const crypto = require("crypto");

function generateKey(){
    const secret = "secret";
    const salt = "AkdioaA38GDAKkaeei"; 
    const key = crypto.scryptSync(secret, salt, 32);
    return key
}

const password = "password";

const key = generateKey();

const iv = crypto.randomBytes(16);

const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let encryptedPassword = cipher.update(password, 'utf-8', 'hex');
encryptedPassword += cipher.final('hex');

console.log(encryptedPassword);


const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
let decrypted = decipher.update(encryptedPassword, "hex", "utf8");
decrypted += decipher.final("utf8");

console.log(decrypted);

関数化

const crypto = require("crypto");

// シークレットキーの作成
function generateKey(){
    const secret = "secret";
    const salt = "AkdioaA38GDAKkaeei"; 
    const key = crypto.scryptSync(secret, salt, 32);
    return key
}

// 暗号化
function encrypt(password, key){
    const iv = crypto.randomBytes(16);
    const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
    let encryptedPassword = cipher.update(password, 'utf-8', 'hex');
    encryptedPassword += cipher.final('hex');
    return { iv, encryptedPassword }
}

// 複合化
function decrypt(password, iv, key){
    const decipher = crypto.createDecipheriv("aes-256-cbc", key, iv);
    let decrypted = decipher.update(password, "hex", "utf8");
    decrypted += decipher.final("utf8");
    return decrypted;
}

const password = "password";
const key = generateKey();

const { iv, encryptedPassword } = encrypt(password, key)

console.log(encryptedPassword);
console.log(decrypt(encryptedPassword, iv, key));
  • cipher(サイファー):暗号

crypto.randomBytes 関数は、疑似ランダムデータを生成します。コールバック関数が指定されていない場合は同期的に生成され、バッファとして値が返されます。

const crypto = require("crypto");

const iv = crypto.randomBytes(16);
console.log(iv.toString("hex"));

ハッシュアルゴリズム

ハッシュアルゴリズムを調べるには以下のようにします。

const crypto = require("crypto");
const hashes = crypto.getHashes();
console.log(hashes);
const crypto = require("crypto");

const password ='password';

const ecdh = crypto.createECDH('secp256k1');
const salt = ecdh.generateKeys();
console.log(salt.toString("hex"));

const sha512 = crypto.createHash('sha512');
sha512.update(password + salt.toString("hex"));
const hash = sha512.digest('hex');

console.log(hash);

「 hash.update(data[, inputEncoding]) 」は、指定された data でハッシュの内容を更新します。

「 hash.digest([encoding]) 」は、ハッシュ化するために渡されたすべてのデータのダイジェストを計算します。 また、digest()メソッドが呼ばれた後は、ハッシュオブジェクトは使えません。

クラスの作成

const crypto = require('crypto');
const { promisify } = require('util');
const scryptAsync = promisify(crypto.scrypt);

class PassManager {
  createSaltHex(length = 16) {
    return crypto.randomBytes(length).toString('hex'); // 16進数文字列で返す
  }

  async createPassHash(password, saltHex){
    const saltBuffer = Buffer.from(saltHex, 'hex'); // hex文字列をバッファに変換
    const derivedKey = await scryptAsync(password, saltBuffer, 64);
    return `${saltHex}:${derivedKey.toString('hex')}`;
  }

  async equalPass(inputPassword, saltHex, storedHashHex) {
    const saltBuffer = Buffer.from(saltHex, 'hex');
    const derivedKey = await scryptAsync(inputPassword, saltBuffer, 64);
    return derivedKey.toString('hex') === storedHashHex;
  }
}

// 利用方法
(async () => {
  const passManager = new PassManager();

  const pass = "password123";
  const salt = passManager.createSaltHex(32);
  
  const savedHash = await passManager.createPassHash(pass, salt);
  console.log(savedHash)

  // 保存値から分離
  const [storedSalt, storedHash] = savedHash.split(':');

  // パスワード検証
  const isValid = await passManager.equalPass('password123', storedSalt, storedHash);
  console.log('一致しているか:', isValid);
})();
  • hex:(へクス):16進数

promisify()は、Node.js の util モジュールが提供する関数で、コールバック関数(特に Node.js のエラーファーストコールバック)を Promise ベースに変換するためのツールです。

Promise ベースに変換することで、async/awaitが使えるようになります。また、.then、.catch、.finallyも使えるようになります。

const scryptAsync = promisify(crypto.scrypt);は、crypto.scryptがコールバック関数ベースの非同期関数のため、async/await を使うために変換しています。

crypto.scrypt(password, salt, keylen[, options], callback)