Bài giảng Lập trình an toàn - Chương 4: Mã hóa đối xứng - Lương Ánh Hoàng
4.1 Biểu diễn khóa
4.2 Chuyển đổi chuỗi hexa và khóa nhị phân.
4.3 Mã hóa và giải mã Base64
4.4 Các phương pháp mã hóa đối xứng
4.5 Mã hóa đối xứng với OpenSSL
4.6 Mã hóa đối xứng với Microsoft Crypto API
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Lập trình an toàn - Chương 4: Mã hóa đối xứng - Lương Ánh Hoàng", để tải tài liệu gốc về máy hãy click vào nút Download ở trên
Tóm tắt nội dung tài liệu: Bài giảng Lập trình an toàn - Chương 4: Mã hóa đối xứng - Lương Ánh Hoàng
Lương Ánh Hoàng hoangla@soict.hut.edu.vn Chương 4. Mã hóa đối xứng Symmetric Crytography 4.1 Biểu diễn khóa 4.2 Chuyển đổi chuỗi hexa và khóa nhị phân. 4.3 Mã hóa và giải mã Base64 4.4 Các phương pháp mã hóa đối xứng 4.5 Mã hóa đối xứng với OpenSSL 4.6 Mã hóa đối xứng với Microsoft Crypto API Nội dung 56 • Khóa đối xứng: Một số rất lớn sử dụng để mã hóa và giải mã thông điệp. • Biểu diễn khóa: • Phân tách thành các byte và lưu dưới dạng một mảng. unsigned char key[KEYLEN_BYTES] • Biểu diễn dưới dạng số nguyên lớn nếu khóa có chiều dài 64-‐bit long long key • Biểu diễn dưới dạng chuỗi chữ số hexa char key[]=“AF12B5C7E0” • Biểu diễn dưới dạng xâu ASCII (mật khẩu). char key[]=“secret!!!” • Lưu ý về tính “endian” của máy thực hiện mã hóa. 4.1 Biểu diễn khóa 57 • Chuyển đổi khóa nhị phân sang dạng chuỗi chữ số hexa #define MAX_KEY_LEN 32 unsigned char key[MAX_KEY_LEN]; char result[MAX_KEY_LEN*2+1]; for (int i=0;i<MAX_KEY_LEN;i++) sprintf(result+i*2,"%2X",key[i]); printf("Key:%s",result); 4.2 Chuyển đổi chuỗi hexa và khóa nhị phân 58 • Chuyển đổi chuỗi hexa sang khóa nhị phân char Hex2Dec(char c) { if (('a'<=c)&&(c<='z')) return c -‐ 'a'+10; if (('A'<=c)&&(c<='Z')) return c -‐ 'A'+10; if (('0'<=c)&&(c<='9')) return c -‐ '0'; return -‐1; } #define MAX_KEY_LENGTH 32 char hexa[]="AF125C4D8E"; unsigned char key[MAX_KEY_LENGTH]; int keylen = strlen(hexa); char c1,c2; if ((keylen%2!=0)||(keylen/2 > MAX_KEY_LENGTH)) printf("Invalid key length"); keylen = keylen/2; for (int i=0;i<keylen;i++) { c1 = Hex2Dec(hexa[i*2]); c2 = Hex2Dec(hexa[i*2+1]); if ((c1==-‐1)||(c2==-‐1)) { printf("Invalid character !!!"); break; }; key[i] = (c1<<4)|c2; }; 4.2 Chuyển đổi chuỗi hexa và khóa nhị phân 59 • Mã hóa Base64 • Sử dụng 6-‐bit để mã hóa dữ liệu và biểu diễn dưới dạng các chữ cái ASCII. • Cứ 3 byte dữ liệu vào sẽ được biểu diễn thành 4 byte dữ liệu ra. • Các ký tự ra nằm trong khoảng: • ‘A’ – ‘Z’ tương đương các giá trị của từ mã từ 0-‐25. • ‘a’ – ‘z’ tương đương các giá trị của từ mã từ 26-‐51. • ‘0’-‐ ‘9’ tương đương các giá trị từ mã từ 52-‐61. • ‘+’ , ‘-‐’ tương ứng với các giá trị mã 62,63. • Nếu dữ liệu vào có kích thước không chia hết cho 3 sẽ thì được thêm vào bằng ký tự ‘=‘. • VD Dữ liệu gốc: ‘A’ – 0100.0001 Dữ liệu mã hóa dạng Base64: 010000.010000.000000.000000 ~ QQ== Dữ liệu gốc: ‘AA’ – 0100.0001.0100.0001 Dữ liệu mã hóa dạng Base64: 010000.010100.000100.000000 ~ QUE= Dữ liệu gốc: ‘AAA’ – 0100.0001.0100.0001.0100.0001 Dữ liệu dạng mã hóa Base64: 010000.010100.000101.000001 ~ QUFB 4.3 Mã hóa và giải mã Base64 60 • Mã hóa Base64 4.3 Mã hóa và giải mã Base64 61 Value Char Value Char Value Char Value Char 0 A 16 Q 32 g 48 w 1 B 17 R 33 h 49 x 2 C 18 S 34 i 50 y 3 D 19 T 35 j 51 z 4 E 20 U 36 k 52 0 5 F 21 V 37 l 53 1 6 G 22 W 38 m 54 2 7 H 23 X 39 n 55 3 8 I 24 Y 40 o 56 4 9 J 25 Z 41 p 57 5 10 K 26 a 42 q 58 6 11 L 27 b 43 r 59 7 12 M 28 c 44 s 60 8 13 N 29 d 45 t 61 9 14 O 30 e 46 u 62 + 15 P 31 f 47 v 63 / • Đoạn chương trình mã hóa Base64: P4.5 – Secure C Programming Cookbook • Đoạn chương trình giải mã Base64: P4.6 – Secure C Programming Cookbook 4.3 Mã hóa và giải mã Base64 62 • Mã hóa đối xứng: Sử dụng chung một khóa cho mã hóa và giải mã • Có hai loại: Mã khối và mã dòng • Có nhiều chế độ mã hóa: ECB, CBC, CFB, OFB, CTR, CWC • Có nhiều giải thuật: 4.4 Các phương pháp mã hóa đối xứng 63 Cipher Key size Speed[4] Implementation Notes AES 128 bits[5] 14.1 cpb in asm, 22.6 cpb in C Brian Gladman's[6] The assembly version currently works only on Windows. AES 128 bits 41.3 cpb OpenSSL Triple DES 192 bits[7] 108.2 cpb OpenSSL SNOW 2.0 128 or 256 bits 6.4 cpb Fast reference implementation[8] This implementation is written in C. RC4 Up to 256 bits (usually 128 bits) 10.7 cpb OpenSSL Serpent 128, 192, or 256 bits 35.6 cpb Fast reference implementation It gets a lot faster on 64-‐bit platforms and is at least as fast as AES in hardware. Blowfish Up to 256 bits (usually 128 bits) 23.2 cpb OpenSSL • Thư viện OpenSSL: Thư viện mã nguồn mở, mạnh mẽ và dễ sử dụng. • OpenSSL hỗ trợ: • Nhiều thuật toán mã hóa: AES, DES , 3DES, Blow}ish, CAST, Idea, RC2, RC5. • Nhiều chế độ mã hóa: ECB, CBC, CFB, OFB, CTR • Mã hóa dòng: RC4. • Các giải thuật băm: MD2, MD4, MD5,SHA-‐1,SHA-‐224,SHA-‐256 • MAC: HMAC. MDC2 • Các giải thuật mã hóa công khai: DH, DSA, RSA, ECC • Sử dụng thư viện: • Trên Unix/Linux: Tải source về và biên dịch. Kết quả là }ile libcrypto.[so/a], libssl.[so/a] và các }ile .h để include vào chương trình. • Trên Windows: Tải bản binary đã biên dịch sẵn: libeay32.dll, ssleay32.dll, tệp tiêu đề (.h) và tệp thư viện (.lib). Link openssl.html 4.5 Mã hóa đối xứng với OpenSSL 64 • Giao diện OpenSSL EVP • Là API mức cao của OpenSSL, cho phép truy nhập đến các thuật toán ở mức thấp một cách tập trung, dễ dàng. • Tệp tiêu đề . • Tệp thư viện: libeay32.lib, ssleay32.lib • Mã hóa AES với OpenSSL EVP. • Khởi tạo khóa, vector khởi tạo, salt với EVP_BytesToKey hoặc tự chọn một bộ Key, IV nào đó. • Khởi tạo ngữ cảnh mã hóa với hàm EVP_EncryptInit_ex. • Khởi tạo ngữ cảnh giải mã với hàm EVP_DecryptInit_ex. • Mã hóa dữ liệu bằng việc liên tục gọi hàm EVP_EncryptUpdate, kết thúc quá trình mã hóa bằng hàm EVP_EncryptFinal_ex. • Giải mã dữ liệu bằng việc liên tục gọi hàm EVP_DecryptUpdate, kết thúc quá trình giải mã bằng hàm EVP_DecryptFinal_ex. 4.5 Mã hóa đối xứng với OpenSSL 65 • VD • Sinh key và iv bằng hàm EVP_BytesToKey char key[32]; char iv[32]; char * key_data = “nopass”; unsigned int salt[] = {12345, 54321}; EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key_data, 6, 1, key, iv); • Khởi tạo ngữ cảnh mã hóa với key và iv đã chọn EVP_CIPHER_CTX e_ctx; EVP_CIPHER_CTX_init(&e_ctx); EVP_EncryptInit_ex(&e_ctx, EVP_aes_256_cbc(),NULL, key, iv); • Khởi tạo ngữ cảnh giải mã với key và iv đã chọn EVP_CIPHER_CTX d_ctx; EVP_CIPHER_CTX_init(&d_ctx); EVP_DecryptInit_ex(&d_ctx, EVP_aes_256_cbc(),NULL, key, iv); 4.5 Mã hóa đối xứng với OpenSSL 66 • VD (tiếp) • Mã hóa với ngữ cảnh đã được khởi tạo char * plaintext=“Hello”; int len = strlen(plaintext); char ciphertext[1024]; int c_len = 0, f_len = 0; /* Gọi lại hàm này để cho phép OpenSSL sử dụng lại ngữ cảnh phiên mã hóa trước */ EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL); // Mỗi chu kỳ Update, c_len sẽ chứa số byte của xâu mã được EVP_EncryptUpdate(e, ciphertext, &c_len, plaintext, len); // Cuối chu kỳ Update, f_len sẽ chưa số byte còn lại của xâu mã EVP_EncryptFinal_ex(e, ciphertext+c_len, &f_len); 4.5 Mã hóa đối xứng với OpenSSL 67 • VD (tiếp) • Giải mã với ngữ cảnh đã được khởi tạo char plaintext[1024]; int p_len = 0; /* Gọi lại hàm này để cho phép OpenSSL sử dụng lại ngữ cảnh phiên giãi mã hóa trước */ EVP_DecryptInit_ex(e, NULL, NULL, NULL, NULL); // Giải mã với ciphertext và len được cung cấp trước EVP_DecryptUpdate(e, plaintext, &p_len, ciphertext, *len); // Kết thúc quá trình giải mã, cập nhật dữ liệu còn lại vào plaintext. EVP_DecryptFinal_ex(e, plaintext+p_len, &f_len); 4.5 Mã hóa đối xứng với OpenSSL 68 • Thư viện CryptoAPI • Cung cấp các hàm mật mã học cơ bản thông qua các Cryptographic Service Providers (CSP). • Microsoft Base Cryptographic Service Provider: RC2, RC4, DES • Microsoft Enhanced Cryptographic Service Provider: Triple-‐DES • Microsoft AES Cryptographic Service Provider: AES • • Cung cấp các hàm mã hóa và giải mã chứng thư số, và đồng thời bổ sung các hàm băm. • Cung cấp các hàm quản lý và lưu trữ chứng thư số. • Các hàm mã thông điệp hóa mức cao (Simpli}ied Message Functions). • Các hàm mã hóa thông điệp mức thấp (Low-‐Level Message Functions). 4.6 Microsoft Crypto API 69 • Thư viện CryptoAPI 4.6 Microsoft Crypto API 70 • 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. • Tệp tiêu đề wincript.h • Thư viện Crypt32.lib • Trình tự sử dụng 4.6 Microsoft Crypto API 71 Khởi tạo Provider Tạo khóa • Ngẫu nhiên • Từ mật khẩu • Từ bên ngoài Đặt chế độ mã • CBC • ECB • Thiết lập vector khởi tạo Thực hiện Mã hóa/Giải mã • 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. • Khởi tạo ngữ cảnh Provider thông qua hàm CryptAcquireContext BOOL WINAPI CryptAcquireContext(__out HCRYPTPROV* phProv, __in LPCTSTR pszContainer, __in LPCTSTR pszProvider, __in DWORD dwProvType, __in DWORD dwFlags ); VD: HCRYPTPROV hProvider; if (!CryptAcquireContext(&hProvider, 0, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) return 0; 4.6 Microsoft Crypto API 72 • 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; 4.6 Microsoft Crypto API 73 • 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; } // Tạo key từ giá trị băm của mật khẩu bResult = CryptDeriveKey(hProvider, CALG_AES_256, hHash, CRYPT_EXPORTABLE, &hKey); CryptDestroyHash(hHash); 4.6 Microsoft Crypto API 74 • 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); LocalFree(pbTemp); 4.6 Microsoft Crypto API 75 • 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 76 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); // Lấy thông tin về giải thuật mã hóa với key cho trước if (!CryptGetKeyParam(hKey, KP_ALGID, (BYTE *)&Algid, &dwDataLen, 0)) 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. • Mã hóa với CryptEncrypt 4.6 Microsoft Crypto API 77 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 78 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 79 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 CryptDecrypt(hKey,0,TRUE,0,pbResult,&dwDataLen); • 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. 4.6 Microsoft Crypto API 80
File đính kèm:
- bai_giang_lap_trinhantoan_chuong_4_ma_hoa_doi_xung_luong_anh.pdf