Skip to main content

🔐 Tiêu chuẩn Mã hóa Nâng cao (AES)

AES (Advanced Encryption Standard) là một thuật toán mã hóa đáng tin cậy, được sử dụng để bảo vệ dữ liệu bằng cách chuyển đổi chúng sang định dạng không thể đọc được nếu không có khóa giải mã thích hợp. AES được phát triển bởi Viện Tiêu chuẩn và Công nghệ Quốc gia Hoa Kỳ (NIST) vào năm 2001.

Hiện nay, AES được sử dụng rộng rãi nhờ vào khả năng bảo mật mạnh mẽ hơn nhiều so với DES và Triple DES, mặc dù việc triển khai AES có phần phức tạp hơn. Thuật toán này hỗ trợ các độ dài khóa 128, 192 hoặc 256 bit, giúp nâng cao khả năng chống lại truy cập trái phép.

AES là một giải pháp bảo mật dữ liệu hiệu quả, được ứng dụng phổ biến trong các lĩnh vực như bảo mật giao tiếp qua Internet, bảo vệ dữ liệu nhạy cảm, và mã hóa tệp tin. Là một nền tảng trong mật mã học hiện đại, AES được công nhận toàn cầu vì khả năng bảo vệ thông tin trước các mối đe dọa mạng.

Đặc điểm kỹ thuật:

  • AES là thuật toán mã hóa khối (Block Cipher).

  • Kích thước khóa: 128, 192 hoặc 256 bit.

  • Mã hóa dữ liệu theo từng khối 128 bit.

🚀 Ứng dụng AES tại ZENGI

Tại ZENGI, thuật toán AES được triển khai theo các tiêu chí kỹ thuật sau:

  • Khóa mã hóa (Encryption Key): sử dụng chuỗi hexstring để tạo khóa 16 byte.

  • Chế độ mã hóa: áp dụng chuẩn CBC (Cipher Block Chaining) với độ dài block là 16 byte.

  • Padding: sử dụng PKCS#7 để đảm bảo dữ liệu có độ dài phù hợp với block size.

  • IV (Initialization Vector): sử dụng chuỗi hexstring ngẫu nhiên có độ dài 16 byte cho mỗi phiên mã hóa.

Chi tiết các thư viện hỗ trợ chuẩn AES/CBC/PKCS7Padding theo ngôn ngữ lập trình

🔐 AES/CBC/PKCS#7/IV – Language Support Matrix

FeatureGoJavaPythonNode.jsC (OpenSSL)
AES support✅ via crypto/aes✅ via javax.crypto.Cipher✅ via pycryptodome or cryptography✅ via crypto module✅ via OpenSSL EVP_* API
CBC mode support✅ via cipher.NewCBC...✅ via "AES/CBC/..."✅ via AES.MODE_CBC✅ via createCipheriv()✅ EVP_aes_256_cbc() etc.
PKCS#7 padding support⚠️ Manual (no built-in)✅ (called PKCS5Padding)*✅ via Crypto.Util.Padding✅ Default behavior✅ Automatic in EVP_Encrypt*
IV support✅ Manual✅ via IvParameterSpec✅ via parameter in AES.new()✅ via 3rd argument✅ Required in EVP init
Hex key/IV support✅ via encoding/hex✅ via custom hexToBytes()✅ via bytes.fromhex()✅ via Buffer.from(..., 'hex')✅ Manually via sscanf() or similar

*: Java's "PKCS5Padding" actually performs PKCS#7 logic for AES (since block size is 16).

Code AES mẫu cho các ngôn ngữ chính

Go

package main

import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/hex"
"fmt"
)

func pkcs7Pad(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
return append(data, bytes.Repeat([]byte{byte(padding)}, padding)...)
}

func pkcs7Unpad(data []byte) []byte {
length := len(data)
paddingLen := int(data[length-1])
return data[:length-paddingLen]
}

func main() {
keyHex := "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"
ivHex := "0102030405060708090a0b0c0d0e0f10"

key, _ := hex.DecodeString(keyHex)
iv, _ := hex.DecodeString(ivHex)
plaintext := []byte("Hello, AES-256 with hex key!")

// Encrypt
block, _ := aes.NewCipher(key)
padded := pkcs7Pad(plaintext, aes.BlockSize)
ciphertext := make([]byte, len(padded))
cipher.NewCBCEncrypter(block, iv).CryptBlocks(ciphertext, padded)
encoded := base64.StdEncoding.EncodeToString(ciphertext)
fmt.Println("Encrypted:", encoded)

// Decrypt
decoded, _ := base64.StdEncoding.DecodeString(encoded)
cipher.NewCBCDecrypter(block, iv).CryptBlocks(decoded, decoded)
unpadded := pkcs7Unpad(decoded)
fmt.Println("Decrypted:", string(unpadded))
}

Java

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class AESJava {

// Hex to byte function which use for convert hexstring keys to byte
public static byte[] hexToBytes(String hex) {
byte[] result = new byte[hex.length() / 2];
for (int i = 0; i < result.length; i++)
result[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
return result;
}

public static void main(String[] args) throws Exception {
String keyHex = "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff";
String ivHex = "0102030405060708090a0b0c0d0e0f10";

byte[] key = hexToBytes(keyHex);
byte[] iv = hexToBytes(ivHex);

IvParameterSpec ivSpec = new IvParameterSpec(iv);
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

// Encrypt
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
byte[] encrypted = cipher.doFinal("Hello, AES-256 with hex key!".getBytes("UTF-8"));
String encoded = Base64.getEncoder().encodeToString(encrypted);
System.out.println("Encrypted: " + encoded);

// Decrypt
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encoded));
System.out.println("Decrypted: " + new String(decrypted, "UTF-8"));
}
}

Python

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import base64

key = bytes.fromhex("00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff")
iv = bytes.fromhex("0102030405060708090a0b0c0d0e0f10")
plaintext = b"Hello, AES-256 with hex key!"

cipher = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(plaintext, AES.block_size))
encoded = base64.b64encode(ciphertext).decode()
print("Encrypted:", encoded)

# Decrypt
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted = unpad(cipher.decrypt(base64.b64decode(encoded)), AES.block_size)
print("Decrypted:", decrypted.decode())

Javascript

const crypto = require('crypto');

const key = Buffer.from('00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff', 'hex');
const iv = Buffer.from('0102030405060708090a0b0c0d0e0f10', 'hex');
const plaintext = 'Hello, AES-256 with hex key!';

// Encrypt
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let encrypted = cipher.update(plaintext, 'utf8', 'base64');
encrypted += cipher.final('base64');
console.log('Encrypted:', encrypted);

// Decrypt
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
let decrypted = decipher.update(encrypted, 'base64', 'utf8');
decrypted += decipher.final('utf8');
console.log('Decrypted:', decrypted);

C

#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

// Convert hex string to bytes
void hex_to_bytes(const char *hex, unsigned char *out, size_t out_len) {
for (size_t i = 0; i < out_len; ++i) {
sscanf(hex + 2*i, "%2hhx", &out[i]);
}
}

// Base64 encode
char* base64_encode(const unsigned char *input, int len) {
BIO *b64, *mem;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
mem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, mem);
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
BIO_write(b64, input, len);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
char *buff = (char *)malloc(bptr->length + 1);
memcpy(buff, bptr->data, bptr->length);
buff[bptr->length] = 0;
BIO_free_all(b64);
return buff;
}

// Base64 decode
int base64_decode(const char *input, unsigned char *output, int outlen) {
BIO *b64 = BIO_new(BIO_f_base64());
BIO *mem = BIO_new_mem_buf((void *)input, -1);
b64 = BIO_push(b64, mem);
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
int len = BIO_read(b64, output, outlen);
BIO_free_all(b64);
return len;
}

// Encrypt using AES-256-CBC with PKCS#7 padding
int encrypt(unsigned char *plaintext, int plaintext_len,
unsigned char *key, unsigned char *iv,
unsigned char *ciphertext) {

EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
int len = 0, ciphertext_len = 0;

EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len);
ciphertext_len = len;
EVP_EncryptFinal_ex(ctx, ciphertext + len, &len);
ciphertext_len += len;
EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}

// Decrypt AES-256-CBC with PKCS#7
int decrypt(unsigned char *ciphertext, int ciphertext_len,
unsigned char *key, unsigned char *iv,
unsigned char *plaintext) {

EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
int len = 0, plaintext_len = 0;

EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv);
EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len);
plaintext_len = len;
EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
plaintext_len += len;
EVP_CIPHER_CTX_free(ctx);
return plaintext_len;
}

int main() {
const char *key_hex = "00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff";
const char *iv_hex = "0102030405060708090a0b0c0d0e0f10";
const char *message = "Hello, AES-256 with hex key!";

unsigned char key[32], iv[16];
hex_to_bytes(key_hex, key, 32);
hex_to_bytes(iv_hex, iv, 16);

unsigned char ciphertext[128], decrypted[128];

int encrypted_len = encrypt((unsigned char *)message, strlen(message), key, iv, ciphertext);
char *encoded = base64_encode(ciphertext, encrypted_len);
printf("Encrypted (base64): %s\n", encoded);

// Decrypt
unsigned char decoded[128];
int decoded_len = base64_decode(encoded, decoded, sizeof(decoded));
int decrypted_len = decrypt(decoded, decoded_len, key, iv, decrypted);
decrypted[decrypted_len] = 0;
printf("Decrypted: %s\n", decrypted);

free(encoded);
return 0;
}