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.
26 trang |
Chia sẻ: huongthu9 | Lượt xem: 542 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Giáo trình Lập trình An toàn - Chương 4: Mã hóa đối xứng - Lương Ánh Hoàng, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
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
Các file đính kèm theo tài liệu này:
- giao_trinh_lap_trinh_an_toan_chuong_4_ma_hoa_doi_xung_luong.pdf