- Laman Utama
- Dokumentasi Penyulitan
Dokumentasi Penyulitan
Ketahui cara penyulitan AES-256-GCM kami berfungsi. Dokumentasi lengkap dengan contoh kod untuk melaksanakan penyulitan pihak pelanggan.
Bab
Bagaimana Ia Berfungsi
Penerbitan Kunci
Kata laluan anda digunakan untuk menerbitkan kunci AES 256-bit menggunakan PBKDF2 dengan SHA-256 dan 600,000 lelaran. Ini menjadikan serangan kekerasan mahal secara komputasi.
Nilai Rawak
Garam 128-bit rawak dan IV (Vektor Permulaan) 96-bit dijana menggunakan penjanaan nombor rawak yang selamat secara kriptografi untuk setiap penyulitan.
Penyulitan AES-256-GCM
Data disulitkan menggunakan AES-256-GCM (Galois/Counter Mode), yang menyediakan kerahsiaan dan pengesahan ketulenan.
Format Output
Output diformatkan sebagai v1:salt:iv:ciphertext di mana semua komponen dikodkan base64.
Fungsi Penyulitan
Terbitkan Kunci
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']
);
}
Pembantu
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;
}
Sulitkan
/**
* 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(':');
}
Nyahsulit
/**
* 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);
}
Contoh Lengkap
/**
* 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);
})();
Output Dijangka
Asal: Hello World Disulitkan: v1:aBcDeFgHiJkLmNoP...:qRsTuVwXyZ...:encrypted_data... Dinyahsulit: Hello World
Nota: Output disulitkan akan berbeza setiap kali disebabkan oleh penjanaan garam dan IV rawak, tetapi penyahsulitan akan sentiasa mengembalikan mesej asal.
Bersedia untuk mencuba?
Gunakan alat penyulitan interaktif kami untuk melihat penyulitan ini beraksi.
Cuba Alat Penyulitan