- หน้าแรก
- เอกสารการเข้ารหัส
เอกสารการเข้ารหัส
เรียนรู้วิธีการทำงานของการเข้ารหัส AES-256-GCM ของเรา เอกสารฉบับสมบูรณ์พร้อมตัวอย่างโค้ดสำหรับการใช้การเข้ารหัสฝั่งไคลเอนต์
บท
วิธีการทำงาน
การรับคีย์
รหัสผ่านของคุณใช้เพื่อรับคีย์ AES 256 บิตโดยใช้ PBKDF2 กับ SHA-256 และ 600,000 รอบ สิ่งนี้ทำให้การโจมตีแบบ brute-force มีค่าใช้จ่ายในการคำนวณสูง
ค่าสุ่ม
Salt แบบสุ่ม 128 บิตและ IV (Initialization Vector) 96 บิตถูกสร้างขึ้นโดยใช้การสร้างตัวเลขสุ่มที่ปลอดภัยทางเข้ารหัสสำหรับการเข้ารหัสแต่ละครั้ง
การเข้ารหัส AES-256-GCM
ข้อมูลถูกเข้ารหัสโดยใช้ AES-256-GCM (Galois/Counter Mode) ซึ่งให้ทั้งความลับและการตรวจสอบความถูกต้อง
รูปแบบผลลัพธ์
ผลลัพธ์ถูกจัดรูปแบบเป็น v1:salt:iv:ciphertext โดยที่ส่วนประกอบทั้งหมดถูกเข้ารหัส base64
ฟังก์ชันการเข้ารหัส
รับคีย์
async function deriveAesGcmKey(password, saltBytes) {
const te = new TextEncoder();
const baseKey = await crypto.subtle.importKey(
'raw',
te.encode(password),
{ name: 'PBKDF2' },
false,
['deriveKey']
);
return crypto.subtle.deriveKey(
{
name: 'PBKDF2',
hash: 'SHA-256',
salt: saltBytes,
iterations: 600000, // OWASP 2025 recommended minimum
},
baseKey,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt', 'decrypt']
);
}
ตัวช่วย
function bytesToBase64(bytes) {
let binary = '';
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
function base64ToBytes(base64) {
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}
เข้ารหัส
/**
* Build combined key from password and salt key
* Format: "password:saltKey"
*/
function buildCombinedKey(password, saltKey) {
if (saltKey) {
return password + ':' + saltKey;
}
return password;
}
async function encrypt(plainText, password, saltKey = '') {
const te = new TextEncoder();
const salt = crypto.getRandomValues(new Uint8Array(16));
const iv = crypto.getRandomValues(new Uint8Array(12));
const combinedKey = buildCombinedKey(password, saltKey);
const key = await deriveAesGcmKey(combinedKey, salt);
const cipherBuf = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
key,
te.encode(plainText)
);
return [
'v1',
bytesToBase64(salt),
bytesToBase64(iv),
bytesToBase64(new Uint8Array(cipherBuf)),
].join(':');
}
ถอดรหัส
/**
* Build combined key from password and salt key
* Format: "password:saltKey"
*/
function buildCombinedKey(password, saltKey) {
if (saltKey) {
return password + ':' + saltKey;
}
return password;
}
async function decrypt(payload, password, saltKey = '') {
const td = new TextDecoder();
const [version, saltB64, ivB64, cipherB64] = payload.split(':');
if (version !== 'v1') {
throw new Error('Unsupported payload version');
}
const salt = base64ToBytes(saltB64);
const iv = base64ToBytes(ivB64);
const ciphertext = base64ToBytes(cipherB64);
const combinedKey = buildCombinedKey(password, saltKey);
const key = await deriveAesGcmKey(combinedKey, salt);
const plainBuf = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv },
key,
ciphertext
);
return td.decode(plainBuf);
}
ตัวอย่างที่สมบูรณ์
/**
* AES-256-GCM Encryption/Decryption Example
* Encrypts "Hello World" and decrypts it back
*/
// Salt key (RK) - used to strengthen password-based encryption
const SALT_KEY = '9x=1KO2tUFw#G:ARZd>Ff)s(^H+DWY4MpgJ:Cp_pCUU|og$>6a.bS.;ij9Wnw';
// Helper functions
function bytesToBase64(bytes) {
let binary = '';
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
function base64ToBytes(base64) {
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}
/**
* Build combined key from password and salt key
* Format: "password:saltKey"
*/
function buildCombinedKey(password, saltKey) {
if (saltKey) {
return password + ':' + saltKey;
}
return password;
}
/**
* Version configuration for encryption payloads
* v1: 150,000 iterations (legacy)
* v2: 600,000 iterations (current, OWASP 2025 recommended)
*/
const VERSION_CONFIG = {
v1: { iterations: 150000 },
v2: { iterations: 600000 },
};
const CURRENT_VERSION = 'v2';
// Derive AES-256 key from password using PBKDF2
async function deriveAesGcmKey(password, saltBytes, iterations) {
const te = new TextEncoder();
const baseKey = await crypto.subtle.importKey(
'raw',
te.encode(password),
{ name: 'PBKDF2' },
false,
['deriveKey']
);
return crypto.subtle.deriveKey(
{
name: 'PBKDF2',
hash: 'SHA-256',
salt: saltBytes,
iterations: iterations,
},
baseKey,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt', 'decrypt']
);
}
// Encrypt function (uses v2 with 600,000 iterations)
async function encrypt(plainText, password, saltKey = '') {
const te = new TextEncoder();
const salt = crypto.getRandomValues(new Uint8Array(16));
const iv = crypto.getRandomValues(new Uint8Array(12));
const combinedKey = buildCombinedKey(password, saltKey);
const iterations = VERSION_CONFIG[CURRENT_VERSION].iterations;
const key = await deriveAesGcmKey(combinedKey, salt, iterations);
const cipherBuf = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
key,
te.encode(plainText)
);
return [
CURRENT_VERSION,
bytesToBase64(salt),
bytesToBase64(iv),
bytesToBase64(new Uint8Array(cipherBuf)),
].join(':');
}
// Decrypt function (supports both v1 and v2)
async function decrypt(payload, password, saltKey = '') {
const td = new TextDecoder();
const [version, saltB64, ivB64, cipherB64] = payload.split(':');
const versionConfig = VERSION_CONFIG[version];
if (!versionConfig) {
throw new Error('Unsupported payload version: ' + version);
}
const salt = base64ToBytes(saltB64);
const iv = base64ToBytes(ivB64);
const ciphertext = base64ToBytes(cipherB64);
const combinedKey = buildCombinedKey(password, saltKey);
const key = await deriveAesGcmKey(combinedKey, salt, versionConfig.iterations);
const plainBuf = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv },
key,
ciphertext
);
return td.decode(plainBuf);
}
// Example usage
(async () => {
const message = 'Hello World';
const password = 'my-secret-password';
console.log('Original:', message);
// Encrypt with salt key (uses v2)
const encrypted = await encrypt(message, password, SALT_KEY);
console.log('Encrypted:', encrypted);
// Decrypt with same salt key (supports v1 and v2)
const decrypted = await decrypt(encrypted, password, SALT_KEY);
console.log('Decrypted:', decrypted);
})();
ผลลัพธ์ที่คาดหวัง
ต้นฉบับ: Hello World เข้ารหัสแล้ว: v1:aBcDeFgHiJkLmNoP...:qRsTuVwXyZ...:encrypted_data... ถอดรหัสแล้ว: Hello World
หมายเหตุ: ผลลัพธ์ที่เข้ารหัสจะแตกต่างกันทุกครั้งเนื่องจากการสร้าง salt และ IV แบบสุ่ม แต่การถอดรหัสจะส่งคืนข้อความเดิมเสมอ
พร้อมที่จะลองหรือยัง?
ใช้เครื่องมือเข้ารหัสแบบโต้ตอบของเราเพื่อดูการเข้ารหัสนี้ในการทำงาน
ลองเครื่องมือเข้ารหัส