Chương 4 Mã hóa đối xứng
VD: HCRYPTPROV hProvider;
HCRYPTPROV hProvider; if (!CryptAcquireContext(&hProvider, 0, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
• Sử dụng thư viện CryptoAPI để thực hiện mã hóa đối xứng thông điệp với thuật toán AES.
• Sử dụng Key thông qua một trong ba hàm. Kết quả trả về là đối tượng HCRYPTKEY
• CryptGenKey( ): Sinh khóa ngẫu nhiên.
• CryptDeriveKey( ): Sinh khóa từ mật khẩu.
• CryptImportKey( ) : Sinh khóa từ một đối tượng trong bộ nhớ.
VD1. Sinh khóa ngẫu nhiên
DWORD dwFlags; HCRYPTKEY hKey;
DWORD dwSize = 256;
dwFlags = ((dwSize << 16) & 0xFFFF0000) | CRYPT_EXPORTABLE;
if (!CryptGenKey(hProvider, CALG_AES_256, dwFlags, &hKey)) return 0;
• Sử dụng thư viện CryptoAPI để thực hiện mã hóa đối xứng thông điệp với thuật toán AES.
VD2. Sinh khóa từ mật khẩu: Cần phải băm mật khẩu và truyền vào hàm CryptDeriveKey
char * password = “nopass”;
BOOL bResult; DWORD cbData;
HCRYPTKEY hKey; // Lưu Key
HCRYPTHASH hHash; // Lưu giá trị băm của mật khẩu
if (!CryptCreateHash(hProvider, CALG_SHA1, 0, 0, &hHash)) // Khởi tạo hàm băm
return 0;
cbData = lstrlen(password) * sizeof(TCHAR);
if (!CryptHashData(hHash, (BYTE *)password, cbData, 0)) // Băm mật khẩu
{
CryptDestroyHash(hHash);
return 0; }
• Sử dụng thư viện CryptoAPI để thực hiện mã hóa đối xứng thông điệp với thuật toán AES.
• Thiết lập chế độ mã hóa CBC với hàm CryptSetKeyParam
DWORD dwMode = CRYPT_MODE_CBC;
CryptSetKeyParam(hKey, KP_MODE, (BYTE *)&dwMode, 0);
• Sinh ngẫu nhiên vector khởi tạo (IV)
BOOL bResult; // Lưu kết quả
BYTE *pbTemp; // Lưu vector khởi tạo
DWORD dwBlockLen, dwDataLen; dwDataLen = sizeof(dwBlockLen);
// Lấy kích thước block của thuật toán mã hóa
if (!CryptGetKeyParam(hKey, KP_BLOCKLEN, (BYTE *)&dwBlockLen, &dwDataLen, 0)) return 0;
dwBlockLen /= 8;
if (!(pbTemp = (BYTE *)LocalAlloc(LMEM_FIXED, dwBlockLen))) return FALSE;
// Sinh ngẫu nhiên IV
bResult = CryptGenRandom(hProvider, dwBlockLen, pbTemp);
// Thiết lập IV
bResult = CryptSetKeyParam(hKey, KP_IV, pbTemp, 0);
• Sử dụng thư viện CryptoAPI để thực hiện mã hóa đối xứng thông điệp với thuật toán AES.
• Mã hóa với CryptEncrypt
• Với các giải thuật mã hóa dòng thì kích thước dữ liệu ra = kích thước dữ liệu vào.
• Với các giải thuật mã hóa khối thì kích thước dữ liệu ra <= kích thước dữ liệu vào + kích thước khối.
• Hàm CryptEncrypt sẽ ghi đè dữ liệu mã hóa được vào bộ đệm chứa dữ liệu vào.
• Đoạn chương trình thực hiện mã hóa chung cho cả hai loại.
4.6 Microsoft Crypto API
ALG_ID Algid; // Giải thuật mã
char * pbData = "Hello CryptAPI"; // Xâu nguồn cần mã
char * pbResult = 0; // Xâu kết quả
DWORD dwDataLen = 0,dwBlockLen = 0;
cbData = strlen(pbData); // Chiều dài xâu nguồn
dwDataLen = sizeof(ALG_ID);
• Sử dụng thư viện CryptoAPI để thực hiện mã hóa đối xứng thông điệp với thuật toán AES.
• Mã hóa với CryptEncrypt
4.6 Microsoft Crypto API
if (GET_ALG_TYPE(Algid) != ALG_TYPE_STREAM) // Mã hóa khối
{
dwDataLen = sizeof(DWORD);
ret = CryptGetKeyParam(hKey, KP_BLOCKLEN, (BYTE*)&dwBlockLen, &dwDataLen, 0); // Lấy kích thước block theo bit
dwBlockLen = dwBlockLen/8; // Đổi kích thước block ra đơn vị byte
// Cấp phát bộ nhớ để chứa kết quả
pbResult = (char*)malloc(cbData+dwBlockLen); memcpy(pbResult,pbData,cbData);
// Thực hiện mã hóa, kết quả là dwDataLen byte lưu trong pbResult
dwDataLen = cbData;
CryptEncrypt(hKey, 0, TRUE, 0, (BYTE*)pbResult, &dwDataLen,
cbData+16)) ;
• Sử dụng thư viện CryptoAPI để thực hiện mã hóa đối xứng thông điệp với thuật toán AES.
• Mã hóa với CryptEncrypt (tiếp)
4.6 Microsoft Crypto API
else // Mã hóa dòng
{
// Cấp phát bộ nhớ lưu kết quả
pbResult = (char*)malloc(cbData); // Bảo toàn dữ liệu nguồn
memcpy(pbResult,pbData,cbData); // Thực hiện mã hóa
CryptEncrypt(hKey,0,TRUE,0,pbResult,&dwDataLen,cbData);
• Sử dụng thư viện CryptoAPI để thực hiện mã hóa đối xứng thông điệp với thuật toán AES.
• Giải mã với CryptDecrypt
• Kích thước dữ liệu đích <= kích thước dữ liệu nguồn
• Thực hiện đơn giản hơn so với CryptEncrypt
• Ví dụ
4.6 Microsoft Crypto API
char * pbData ; // Dữ liệu nguồn
DWORD cbData; // Kích thước nguồn
char * pbResult; // Dữ liệu đích
DWORD dwDataLen; // Kích thước đích
…
// Cấp phát bộ nhớ và sao chép dữ liệu nguồn vào đích
pbResult = (char*)malloc(cbData); memcpy(pbResult, pbData, cbData); dwDataLen = cbDataLen;
// Giải mã, kết quả là dwDataLen byte lưu trong pbResult
• Trao đổi khóa với OpenSSL
• CryptoAPI không cho phép nhập và xuất khóa dạng thô như OpenSSL.
• Để trao đổi khóa với thư viện khác, cần mã hóa khóa theo giải thuật AT_KEYEXCHANGE, và thực hiện nhập xuất dưới dạng cấu trúc BLOB.
• Hàm CryptImportKeyvà CryptExportKey dùng để thực hiện nhập xuất khóa.
• Xem thêm phần 5.26, 5.27 trong Secure Programming Cookbook.
Lương Ánh Hoàng
hoangla@soict.hut.edu.vn