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

Biểu diễn khóa

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.3 Mã hóa và giải mã Base64

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

 

docx 28 trang kimcuc 3840
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

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
Chương 4. Mã hóa đối xứng
Symmetric Crytography Lương Ánh Hoàng hoangla@soict.hut.edu.vn
Nội dung
Biểu diễn khóa
Chuyển đổi chuỗi hexa và khóa nhị phân.
Mã hóa và giải mã Base64
Các phương pháp mã hóa đối xứng
Mã hóa đối xứng với OpenSSL
Mã hóa đối xứng với Microsoft Crypto API
4.1 Biểu diễn khóa
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.
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+i]; for (int ì=0;ì<MaX_KEY_LEN;ì++) sprintf(result+i*2,”%2X”,key[i]);
printf(”Key:%s”,result);
• Chuyển đổi chuỗi hexa sang khóa nhị phân
char Hex2Dec(char c)
{	
if (('a'<=c)&&(c<='z')) return c - 'a'+1o; if (('A'<=c)&&(c<='Z')) return c - 'A'+1o;
if (('0'<=c)&&(c<='9')) return c - 'o'; return -1;
}
#define MAX_KEY_LENGTH 32 char hexa[]=”AF125C4D8E”;
unsigned char key[wAx_KEY_LENGTH]; int keylen = strlen(hexa);
char ci,c2;
if ((keylen%2!=o)||(keylen/2 >
MAX_KEY_LENGTH)) printf(”Invalid key length”); keylen = keylen/2;
for (int i=o;i<keylen;i++)
ci = Hex2Dec(hexa[i*2]);
c2 = Hex2Dec(hexa[i*2+i]);
if ((C1==-1)||(C2==-1))
{	
printf(”Invalid character !!!”); break;
};	
key[i] = (c1<<4)|c2;
Mã hóa và giải mã Base64
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
Mã hóa và giải mã Base64
Mã hóa Base64
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
ỉ
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
/
Mã hóa và giải mã Base64
Đ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
Các phương pháp mã hóa đối xứng
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:
Cipher
Key size
Speed B
Implementation
Notes
AES
128 bitsl51
14.1 cpb in asm, 22.6 cpb in C
Brian Gladman'sl6!
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, Blowfish, 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à file libcrypto.[so/ a], libssl.[so/a] và các file .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
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.
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_CIPHE R_CTX_i n it(&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_CIPHE R_CTX_i n it(&d_ctx);
EVP_DecryptInit_ex(&d_ctx, EVP_aes_256_cbc(),NULL, key, iv);
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[i024];
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);
VD (tiếp)
• Giải mã với ngữ cảnh đã được khởi tạo
char	plaintext[i024];
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);
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 (Simplified Message Functions).
Các hàm mã hóa thông điệp mức thấp (Low-Level Message Functions).
Thư viện CryptoAPI
CryptoAPI
Architecture
I
Certificate Functions	I	Message Functions
Tạo khóa
Ngẫu nhiên
Từ mật khẩu
Từ bên ngoài
Đặt chế độ mã
CBC
ECB
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
Khởi tạo
Provider
V	>
Thực hiện Mã
hóa/Giải mã
V	/

Thiết lập vector
khởi tạo
l/
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;
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) & oxFFFFoooo) | 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;
_ }	 , A
// 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);
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; BYTE *pbTemp;
// Lưu kết quả
// 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);	75
LocalFree(pbTemp);
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.
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
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)
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ụ
char * pbData ;
DWORD cbData; char * pbResult;
DWORD dwDataLen;
// Dữ liệu nguồn
// Kích thước nguồn
// Dữ liệu đích
// 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.

File đính kèm:

  • docxbai_giang_lap_trinh_an_toan_chuong_4_ma_hoa_doi_xung_luong_a.docx
  • pdfsecureprogramming_4_5235_505050.pdf