1. Lương
Ánh
Hoàng
hoangla@soict.hut.edu.vn
LẬP
TRÌNH
AN
TOÀN
Secure
Programming
2. • Cung
cấp
các
kiến
thức,
kỹ
thuật
cơ
bản
để
xây
dựng
các
ứng
dụng
an
toàn.
Mục
đích
2
3. • Yêu
cầu
về
kiến
thức:
– An
ninh
mạng
– Ngôn
ngữ
lập
trình
C/C++.
• Lên
lớp
đầy
đủ
Yêu
cầu
3
4. • Thời
lượng:
45
tiết
– Lý
thuyết:
30
tiết
– Bài
tập:15
tiết
Thời
lượng
môn
học
4
5. • Secure
Program
Cookbook
for
C
and
C++,
Matt
Messier,
John
Viega,
O'Reilly
2003.
Tài
liệu
5
6. • Chương
1.
Kiểm
tra
đầu
vào
• Chương
2.
Kiểm
soát
truy
nhập
• Chương
3.
Kiểm
soát
xung
đột
• Chương
4.
Mã
hóa
đối
xứng
• Chương
5.
Hàm
băm
và
xác
thực
thông
điệp
• Chương
6.
Mã
hóa
công
khai
• Chương
7.
Anti-‐Tampering
• Chương
8.
Các
vấn
đề
khác
Nội
dung
6
9. Lương
Ánh
Hoàng
hoangla@soict.hut.edu.vn
Chương
1.
Kiểm
tra
đầu
vào
Input
Validation
10. 1.1
Nguyên
tắc
kiểm
tra.
1.2
Các
hàm
định
dạng
xâu
(string
formatting)
.
1.3
Tràn
bộ
đệm.
1.4
Tràn
số
học.
1.5
Kiểm
tra
tên
}ile
và
đường
dẫn.
1.6
Giải
mã
URL
1.7
Cross-‐Site
Scripting
1.8
SQL
Injection
Nội
dung
10
11. • Luôn
luôn
giả
định
dữ
liệu
đầu
vào
là
không
đáng
tin
cậy
– Dữ
liệu
từ
mạng
trong
mô
hình
client-‐server
– Dữ
liệu
từ
người
dùng
– Dữ
liệu
từ
tệp
tin
– …
• Ưu
tiên
loại
bỏ
dữ
liệu
hơn
là
cố
gắng
sửa
chữa
dữ
liệu.
• Thực
hiện
kiểm
tra
đầu
vào
tại
nhiều
cấp,
nhiều
điểm
– Kiểm
tra
đầu
vào
ở
các
hàm
– Kiểm
tra
đầu
vào
giữa
các
module.
– …
• Không
tiếp
nhận
lệnh
trực
tiếp
từ
người
dùng
nếu
chưa
qua
kiểm
tra.
• Kiểm
tra
các
ký
tự
đặc
biệt,
dấu
nháy.
• Tìm
hiểu
và
sử
dụng
cơ
chế
trích
dẫn
(quoting
mechanism)
nếu
cần.
• Càng
hiểu
về
dữ
liệu
bao
nhiêu
càng
lọc
được
tốt
bấy
nhiêu.
1.1
Các
nguyên
tắc
kiểm
tra
11
12. • Họ
các
hàm
printf()
,
syslog()
cho
phép
định
dạng
dữ
liệu
rất
mềm
dẻo
và
mạnh
mẽ
tuy
nhiên
cũng
cực
kỳ
nguy
hiểm.
• Thận
trọng
khi
sử
dụng
“%n”
– Tham
số
%n
cho
phép
ghi
ra
số
lượng
ký
tự
đã
kết
xuất
được
ra
một
địa
chỉ
bất
kỳ
chỉ
ra
trong
tham
số
tương
ứng.
Nếu
không
tồn
tại
tham
số
nào
thì
printf
sẽ
ghi
đè
lên
một
vùng
nào
đó
thuộc
stack
của
luồng
đang
thực
thi.
– VD.
int
counter
=
0;
printf(“Hello%n”,&counter);
//
OK,
counter
=
5
printf(“Hello%n”);
//
Nguy
hiểm
!!!
• Không
sử
dụng
trực
tiếp
xâu
định
dạng
từ
nguồn
bên
ngoài
– Xâu
định
dạng
có
nguồn
gốc
từ
ngoài
chương
trình
có
thể
có
một
vài
ký
tự
đặc
biệt
mà
chương
trình
chưa
lường
trước
được,
hoặc
không
có
tham
số
thay
thế
tương
ứng.
– VD.
char
str[1024];
gets(str);
printf(“Xin
chao:”);
printf(str);
//
Nguy
hiểm
!!!
printf(“%s”,str);
//
OK
1.2
Các
hàm
định
dạng
xâu
12
13. • Thận
trọng
khi
sử
dụng
sprintf,
vsprintf
với
“%s”
– Các
hàm
trên
đều
giả
định
kích
thước
bộ
đệm
cho
xâu
đích
là
vô
hạn.
– Nên
chỉ
rõ
số
lượng
ký
tự
tối
đa
sẽ
sử
dụng
khi
dùng
với
%s.
– Nên
sử
dụng
snprintf,
vsnprintf
nếu
có
thể.
– VD
char
str[1024];
char
dst[32];
gets(str);
sprintf(dst,”Xau
vua
nhap
vao
la
%s”,str);
//
Nguy
hiểm
sprintf(dst,”Xau
vua
nhap
vao
la
%.16s”,str);
//
OK
snprintf(dst,32,”Xau
vua
nhap
vao
la
%s”,str);//
OK
1.2
Các
hàm
định
dạng
xâu
13
14. • Tràn
bộ
đệm
(Buffer
Over}low):
copy
dữ
liệu
vượt
quá
biên
của
một
bộ
đệm
nào
đó
=>
đè
lên
vùng
nhớ
của
biến
(cấu
trúc)
khác.
• Phần
lớn
các
hàm
xử
lý
xâu
trong
C
đều
không
thực
hiện
kiểm
tra
biên
của
bộ
đệm:
gets,
strcpy,
…
• VD1:
Dữ
liệu
bị
hỏng
int
x
=
0;
char
buff[8];
strcpy(buff,”Hello
AAAAAAAAAAAAAAAAAAAAAAAAAAAAA”);
printf(“%d”,x);
• VD2:
Stack
bị
hỏng
char
name[8];
gets(name);
printf(name);
1.3
Tràn
bộ
đệm
14
15. • VD3:
Không
trở
về
được
từ
chương
trình
con
void
Hello()
{
char
name[8];
printf(“What
is
your
name
?”);
gets(name);
printf(“Hello
%s
!”,
name);
}
void
main()
{
Hello();
printf(“Bye”);
}
1.3
Tràn
bộ
đệm
15
16. • VD4:
Tấn
công
có
chủ
ý
trên
bộ
đệm
void
Bye()
{
printf(“Bye”);
}
void
Hello()
{
void
(*p)()
=
Bye;
char
name[8];
printf(“What
is
your
name
?”);
gets(name);
printf(“Hello
%s
!”,
name);
p();
}
void
main()
{
Hello();
}
1.3
Tràn
bộ
đệm
16
17. • Giải
pháp:
– Sử
dụng
các
hàm
strncpy,
memcpy…và
những
hàm
có
kiểm
soát
kích
thước
bộ
đệm
một
cách
tường
minh.
– Sử
dụng
Stack
Guard
trong
các
trình
biên
dịch
hỗ
trợ.
– Sử
dụng
DEP
(Data
Execution
Preventation)
trên
hệ
điều
hành
hỗ
trợ.
– Sử
dụng
ASLR
(Address
Space
Layout
Randomization)
trên
trình
biên
dịch
và
hệ
điều
hành
hỗ
trợ.
1.3
Tràn
bộ
đệm
17
18. • Dữ
liệu
nhận
về
có
thể
có
sai
sót
trong
trường
liên
quan
đến
kích
thước.
• Các
thao
tác
liên
quan
đến
số
nguyên
lớn
có
thể
bị
tràn,
lẫn
lộn
giữa
số
nguyên
không
dấu
và
có
dấu
• VD1:
Tràn
số
unsigned
int
x
=
0xFFFFFFFF;
//
MAX_INT
if
(
x+5
>
5
)
printf
(“X
>
0”
)
else
printf(“X
<
0”);
• VD2:
Dùng
sai
kiểu
có/không
dấu
if
(x
<
MAX_SIZE)
{
//
x,
số
byte
cần
cấp
phát
tùy
theo
giải
thuật
tính
được
if
(!(ptr
=
(unsigned
char
*)malloc(x)))
abort(
);
}
else
{
/*
Handle
the
error
condition
...
*/
}
1.4
Tràn
số
học
18
19. • Dữ
liệu
nhận
về
có
thể
là
tên
}ile,
ứng
dụng
cần
xác
định
đường
dẫn
tuyệt
đối
nếu
cần
thiết.
• Dùng
hàm
realpath()
trên
Unix/Linux
và
GetFullPathName
trên
Windows.
• Sử
dụng
realpath()
§ Nguyên
mẫu:
char
*realpath(const
char
*pathname,
char
resolved_path[MAXPATHLEN]);
§ Thận
trọng:
Có
thể
tràn
resolved_path
và
không
thread-‐safe.
§ Thư
viện:
stdlih.h
§ VD
char
resolved[1024];
char
*
result
=
realpath("printf.c",resolved);
printf("%s",result);
1.5
Kiểm
tra
tên
qile
và
đường
dẫn
19
20. • Sử
dụng
GetFullPathName()
§ Thư
viện:
windows.h
§ Nguyên
mẫu:
DWORD
GetFullPathName(LPCTSTR
lpFileName,
DWORD
nBufferLength,
LPTSTR
lpBuffer,
LPTSTR
*lpFilePath);
§ VD:
int
nBufferLen
=
0;
LPTSTR
lpBuffer;
nBufferLen
=
GetFullPathName(L"test.c",0,0,0);
if
(nBufferLen>0)
{
lpBuffer
=
new
TCHAR[nBufferLen+1];
GetFullPathName(L"test.c",nBufferLen,lpBuffer,0);
wprintf(L"%s",lpBuffer);
}
1.5
Kiểm
tra
tên
qile
và
đường
dẫn
20
21. • RFC
1738
quy
định
cách
mã
hóa
các
ký
tự
không
nhìn
thấy
được
trong
URL
dưới
dạng
“%<Mã
hexa>”.
• VD:
http://m%61il.google.com
http://m%25%36%31il.google.com
• Cách
giải
mã:
duyệt
từ
đầu
đến
cuối
,
tìm
các
ký
tự
%
và
thay
thế
bằng
mã
ASCII
tương
ứng.
• Không
sử
dụng
các
hàm
xử
lý
xâu
chuẩn
vì
có
thể
có
ký
tự
NULL
trong
URL.
1.6
Giải
mã
URL
21
22. • Cross-‐Site
Scripting
(XSS)
là
hình
thức
tấn
công
vào
trình
duyệt
người
dùng
bắt
nguồn
từ
việc
kiểm
tra
lỏng
lẻo
từ
server.
• Có
thể
dẫn
đến
thất
thoát
thông
tin
nhạy
cảm:
mật
khẩu,
session,
cookie…
• Thực
hiện
bằng
cách
chèn
mã
HTML/JAVASCRIPT
vào
dữ
liệu
sẽ
hiển
thị
ra
trình
duyệt
=>
đoạn
mã
sẽ
chạy
trên
trình
duyệt
của
nạn
nhân.
• VD.
Một
ứng
dụng
web
có
hai
trang
– Hello.php:
Hiển
thị
form
và
nhận
tên
của
người
dùng.
– Chao.php:
hiển
thị
tên
nhận
được
lại
cho
người
dùng.
1.7
Cross-‐Site
Scripting
22
23. • File
Hello.php
<HTML>
Xin
chào,
vui
lòng
nhập
tên
bạn
<FORM
action="chao.php"
method=“POST">
<input
type="text"
name="name"/><br/>
<input
type="submit"
value="Submit">
</FORM>
</HTML>
• File
Chao.php
<?PHP
echo
"Xin
chao
".$_POST['name'];
?>
• Demo
• Với
tên
là
:
Secure
• Với
tên
là:
Secure
<script>alert('XSS
was
found
!');</script>
• Với
tên
là:
Secure
<s%63ript>alert(‘Hacked’);</s%63ript>
• Giải
pháp:
Lọc
bỏ
các
thẻ
HTML
khỏi
dữ
liệu
từ
người
dùng.
Mỗi
ngôn
ngữ
lập
trình
có
một
cách
riêng.
1.7
Cross-‐Site
Scripting
23
24. • SQL
Injection:
Tấn
công
vào
CSDL
thông
qua
dữ
liệu
nhập
từ
trình
duyệt.
• Lợi
dụng
việc
kiểm
tra
lỏng
lẻo
từ
đầu
vào,
chèn
mã
lệnh
SQL
vào
các
truy
vấn
đến
CSDL
của
ứng
dụng
web.
• Thường
lợi
dụng
dấu
nháy
“
‘
“
để
kết
thúc
câu
truy
vấn
SQL
hoặc
thêm
các
câu
truy
vấn
khác.
• VD:
Lệnh
so
sánh
tên
và
mật
khẩu
trong
SQL
– select
*
from
users
where
username
=
‘$user’
and
password
=
‘$pass’
– Nếu
$user
hoặc
$pass
chứa
dấu
“’”
thì
SQL
sẽ
hiểu
nhầm
nội
dung
truy
vấn…
• Các
kỹ
thuật
khai
thác:
An
ninh
mạng
• VD:
Một
ứng
dụng
web
muốn
kiểm
tra
tên
và
mật
khẩu
gồm
hai
trang
– ask.php:
Hiện
form
đăng
nhập
và
thu
nhận
tên,
mật
khẩu
– login.php:
Kết
nối
đến
CSDL
và
kiểm
tra
1.8
SQL
Injection
24
25. • VD
(tiếp
– File
ask.php
<HTML>
Vui
long
nhap
ten
va
mat
khau
<FORM
action="login.php"
method="GET">
Ten:
<INPUT
type="text"
name="user"/><BR/>
Mat
khau:<INPUT
type="text"
name="pass"/><BR/>
<INPUT
type="submit"
name="Submit">
</FORM>
1.8
SQL
Injection
25
26. • VD
(tiếp)
– File
login.php
<?PHP
$db_server
=
"localhost";
$db_username=
"root";
$db_password=
"123456";
$db
=
"test";
$table
=
"users";
$conn
=
mysql_connect($server,$db_username,$db_password);
if
(!$conn)
{
echo
"Khong
ket
noi
dc
den
CSDL";
return;
}
$ret
=
mysql_select_db($db,$conn);
1.8
SQL
Injection
26
27. if
(!$ret)
{
echo
"Khong
ton
tai
CSLD
tuong
ung";
return;
}
$user
=
$_GET['name'];
$pass
=
$_GET['pass'];
$sql
=
"select
*
from
$table
where
username='$user'
and
password='$pass'";
echo
$sql;
$ret
=mysql_query($sql,$conn);
if
(mysql_num_rows($ret)>0)
echo
"Dang
nhap
thanh
cong";
else
echo
"Sai
ten
hoac
mat
khau";
?>
1.8
SQL
Injection
27
28. • Tấn
công
– username
=
a’
or
‘1’=‘1
– password
=
b’
or
‘1’=‘1
– …
• Phòng
chống
– Loại
bỏ
tất
cả
các
dấu
‘
và
các
ký
tự
đặc
biệt
nếu
cần.
– Sử
dụng
escaped
string
• Với
php/mysql:
mysql_real_escape_string,
hoặc
thêm
‘’.
• Với
SQL
server:
thêm
ký
tự
‘
trước
ký
tự
đặc
biệt.
• Với
Oracle
DB:
thêm
ký
tự
‘’
trước
ký
tự
đặc
biệt.
1.8
SQL
Injection
28
30. 2.1
Cơ
chế
kiểm
soát
truy
nhập
trên
Unix/Linux
2.2
Cơ
chế
kiểm
soát
truy
nhập
trên
Windows
2.3
Hạ
thấp
quyền
truy
nhập
của
tiến
trình
2.4
Xóa
}ile
an
toàn
2.5
Hạn
chế
quyền
truy
nhập
trên
}ile
2.6
Khóa
}ile
2.7
Tạo
}ile
tạm
2.8
Hạn
chế
truy
nhập
đến
hệ
thống
}ile
Nội
dung
30
31. • Trên
Unix/Linux
tất
cả
các
tài
nguyên
đều
được
coi
là
}ile:
tệp
tin,
ổ
đĩa,
bộ
nhớ,
thiết
bị….
• Mỗi
}ile
kiểm
soát
bởi
user
id
và
group
id.
• Mỗi
tiến
trình
có
ba
quyền:
effective
user
id,
real
user
id,
saved
user
id.
Effective
user
id
được
sử
dụng
trong
phần
lớn
các
kiểm
tra.
• Mỗi
tiến
trình
cũng
thuộc
về
ba
nhóm:
effective
group
id,
real
group
id,
saved
group
id.
• Có
ba
loại
quyền
• Đọc
(read)
• Ghi
(write)
• Thực
thi
(execute)
2.1
Cơ
chế
kiểm
soát
truy
nhập
trên
Unix/
Linux
31
32. • Mỗi
}ile
sẽ
có
ba
nhóm
quyền
tương
ứng
với:
user
id,
group
id,
và
other.
-‐rwxr-‐xr-‐x
1
Luong
Anh
Hoang
None
17964
Aug
28
23:45
test.exe
• Khi
tiến
trình
tạo
một
}ile
hoặc
tài
nguyên,
hệ
thống
sẽ
gán
user
id
và
group
id
cho
}ile
mới
đó
bằng
effective
user
id
và
effective
group
id
của
tiến
trình.
• Khi
tiến
trình
truy
nhập
một
}ile
hoặc
tài
nguyên,
hệ
thống
sẽ
lần
lượt
so
sánh
user
id,
group
id
của
tiến
trình
và
}ile
và
chọn
ra
tập
quyền
tương
ứng.
Nếu
không
khớp
thì
lớp
quyền
thứ
3
sẽ
được
sử
dụng.
2.1
Cơ
chế
kiểm
soát
truy
nhập
trên
Unix/
Linux
32
33. • Mỗi
}ile
cũng
có
thể
có
3
bit
đặc
biệt
• Sticky.
Nếu
bit
này
được
thiết
lập,
người
dùng
sẽ
không
thể
xóa
hay
đổi
tên
}ile
của
người
khác
nằm
trong
thưc
mục
mà
người
dùng
quản
lý.
Mặc
định
là
không
được
thiết
lập.
• Setuid:
Bit
này
liên
quan
đến
quá
trình
tạo
một
tiến
trình
mới.
Nếu
bit
này
được
thiết
lập,
tiến
trình
được
tạo
từ
}ile
này
sẽ
không
kế
thừa
quyền
từ
tiến
trình
cha,
mà
sẽ
có
quyền
từ
user
id
của
chính
}ile
đó.
• Setgid:
• Đối
với
}ile
thực
thi,
nếu
bit
này
được
thiết
lập
thì
một
tiến
trình
mới
được
tạo
sẽ
có
quyền
từ
groupd
id
của
}ile
đó
chứ
không
kế
thừa
từ
tiến
trình
cha
(tương
tự
Setuid).
• Đối
với
thưc
mục,
nếu
bit
này
được
thiết
lập
thì
các
}ile
tạo
trong
thư
mục
này
sẽ
có
groupd
id
của
thư
mục
cha,
chứ
không
kế
thừa
từ
tiến
trình
tạo
ra
}ile
đó.
2.1
Cơ
chế
kiểm
soát
truy
nhập
trên
Unix/
Linux
33
34. • Windows
sử
dụng
ACL:
Access
Control
List
để
phân
quyền
tài
nguyên.
• Các
tài
nguyên
của
Windows:
}ile,
registry,
mutex,
event,
IPC…
được
kiểm
soát
thông
qua
DACL
và
SACL.
• DACL
là
danh
sách
các
ACE,
mỗi
ACE
là
một
luật
quy
định
một
quyền
hạn
cụ
thể.
• DACL
rỗng
tương
đương
với
việc
tất
cả
mọi
người
có
toàn
quyền
truy
nhập
tới
đối
tượng.
• Mỗi
ACE
bao
gồm
3
thông
tin:
• SID:
Đại
diện
cho
một
user
hay
một
group
trong
hệ
thống
• Quyền
truy
nhập
• Giá
trị
boolean
tương
ứng
với
cho
phép
hay
không
cho
phép.
2.2
Cơ
chế
kiểm
soát
truy
nhập
trên
Windows
34
35. • Các
quyền
truy
nhập
2.2
Cơ
chế
kiểm
soát
truy
nhập
trên
Windows
35
TÊN
Diễn
giải
DELETE
The
ability
to
delete
the
object
READ_CONTROL
The
ability
to
read
the
object's
security
descriptor,
not
including
its
SACL
SYNCHRONIZE
The
ability
for
a
thread
to
wait
for
the
object
to
be
put
into
the
signaled
state;
not
all
objects
support
this
functionality
WRITE_DAC
The
ability
to
modify
the
object's
DACL
WRITE_OWNER
The
ability
to
set
the
object's
owner
GENERIC_READ
The
ability
to
read
from
or
query
the
object
GENERIC_WRITE
The
ability
to
write
to
or
modify
the
object
GENERIC_EXECUTE
The
ability
to
execute
the
object
(applies
primarily
to
}iles)
GENERIC_ALL
Full
control
36. • Ví
dụ
ACE
• DENY
GENERIC_ALL
Everyone:
Cấm
mọi
quyền
với
group
Everyone
• ALLOW
GENERIC_WRITE
Marketing:
Cho
phép
nhóm
group
Marketing
được
quyền
ghi
• Mỗi
đối
tượng
đều
có
một
Owner,
chính
là
người
tạo
ra
đối
tượng.
• Owner
có
toàn
quyền
với
đối
tượng
bất
kể
trong
DACL
có
cấm
hay
không.
• Owner
có
thể
bị
chiếm
bởi
user
khác.
2.2
Cơ
chế
kiểm
soát
truy
nhập
trên
Windows
36
37. • Nếu
một
tiến
trình
có
đặc
quyền
cao,
thực
hiện
các
thao
tác
nguy
hiểm
=>
cần
hạ
thấp
quyền
trước
khi
thực
hiện.
• Tiến
trình
có
thể
kiểm
tra
real
user
id,
real
group
id
bằng
lệnh
getuid
(),
getgid().
Đây
là
các
đặc
quyền
kế
thừa
từ
tiến
trình
cha.
• Tiến
trình
có
thể
kiểm
tra
effective
user
id
và
effective
group
id
bằng
lệnh
geteuid()
và
getegid().
Đây
thường
là
user
id
có
đặc
quyền
cao
hơn
(do
được
khởi
chạy
từ
super
user,
hoặc
các
bit
setuid
được
bật).
• Tiến
trình
từ
bỏ
đặc
quyền
bằng
việc
thiết
lập
group
mới
chính
là
real
user
id
qua
lệnh
• setgroups():
Thiết
lập
lại
nhóm
của
tiến
trình.
• setegid():
Thiết
lập
lại
effective
group
id
của
tiến
trình.
• seteuid():
Thiết
lập
lại
effective
user
id
của
tiến
trình.
2.3
Hạ
thấp
quyền
truy
nhập
của
tiến
trình
37
38. • Thông
thường,
một
}ile
sau
khi
xóa
sẽ
được
hệ
điều
hành
đánh
dấu
là
xóa,
nội
dung
chưa
hoàn
toàn
bị
loại
bỏ
trên
đĩa.
• Giải
pháp
• Ghi
đè
thông
tin
khác
nhiều
lần
lên
đĩa.
• Ghi
đè
dữ
liệu
ngâu
nhiên
nhiều
lần
lên
đĩa.
• Ghi
đè
sử
dụng
mẫu
định
sẵn
lên
đĩa.
• Sau
mỗi
chu
kỳ
ghi,
sử
dụng
fsync
để
đồng
bộ
với
đĩa,
vô
hiệu
hóa
cơ
chế
cache.
Hoặc
lệnh
f}lush()
nếu
sử
dụng
thư
viện
C.
• Một
vài
mẫu
được
sử
dụng
• static
unsigned
char
single_pats[16]
=
{
0x00,
0x11,
0x22,
0x33,
0x44,
0x55,
0x66,
0x77,
0x88,
0x99,
0xaa,
0xbb,
0xcc,
0xdd,
0xee,
0xff
};
• static
unsigned
char
triple_pats[6][3]
=
{
{
0x92,
0x49,
0x24
},
{
0x49,
0x24,
0x92
},
{
0x24,
0x92,
0x49
},
{
0x6d,
0xb6,
0xdb
},
{
0xb6,
0xdb,
0x6d
},
{
0xdb,
0x6d,
0xb6
}
};
2.4
Xóa
qile
an
toàn
38
39. • Unix/Linux
sử
dụng
umask
cho
mỗi
tiến
trình
để
vô
hiệu
hóa
một
vài
bit
khi
tiến
trình
tạo
}ile.
• Hàm
fopen,
open
luôn
luôn
tạo
}ile
với
quyền
666.
• Giả
sử
tiến
trình
muốn
tạo
}ile
với
quyền
666:
requested_permissions
=
0666;
actual_permissions
=
requested_permissions
&
~umask(
);
• Ứng
dụng
thay
đổi
umask
bằng
hàm
umask()
trước
khi
thực
hiện
lời
gọi
tạo
}ile.
#include
<sys/types.h>
#include
<sys/stat.h>
mode_t
umask(mode_t
mask);
2.5
Hạn
chế
quyền
truy
nhập
trên
qile
39
40. • Tiến
trình
muốn
kiểm
soát
truy
nhập
trên
một
phần
của
}ile
hay
toàn
bộ
}ile
để
tránh
xung
đột
khi
có
nhiều
tiến
trình
cùng
truy
nhập
trên
}ile.
• Unix/Linux
cung
cấp
cơ
chế
khóa
mềm:
Mọi
tiến
trình
đều
có
quyền
giành
được
khóa
và
thao
tác
trên
}ile,
tuy
nhiên
không
phải
tiến
trình
nào
cũng
tuân
thủ
theo
khóa
và
có
thể
phá
hỏng
dữ
liệu
của
tiến
trình
khác.
• Windows
thực
hiện
vấn
đề
này
tốt
hơn
bằng
khóa
cứng.
Có
hai
loại
khóa:
• Shared
Lock:
Cho
phép
các
tiến
trình
khác
(kể
cả
tiến
trình
giành
được
khóa)
đọc
nhưng
không
được
ghi
vào
một
phần
đã
khóa
của
}ile.
• Exclusive
Lock
:
Cấm
tất
cả
các
tiến
trình
khác
không
được
đọc
hay
ghi
vào
phần
đã
khóa
của
}ile.
Tiến
trình
giành
được
khóa
có
quyền
đọc
hoặc
ghi
vào
}ile.
2.6
Khóa
qile
40
41. • Các
hàm
khóa
}ile
trên
Windows
• LockFile,
UnlockFile:
Khóa
và
mở
khóa
đồng
bộ,
sẽ
không
trở
về
đến
khi
giành
được
khóa
hoặc
mở
được
khóa.
• LockFileEx,
UnlockFileEx:
Khóa
và
mở
khóa
đồng
bộ
hoặc
bất
đồng
bộ.
• Khóa
}ile
cũng
có
thể
xác
định
lúc
tạo
lập/truy
nhập
}ile
thông
qua
hàm
CreateFile.
• Đoạn
chương
trình
sau
sẽ
mở
một
}ile
để
đọc
với
chế
độ
Shared
Lock.
char
buff[1024];
DWORD
bytesRead
=
0;
HANDLE
fileHandle
=
NULL;
fileHandle
=
CreateFile(L"C:SecureProgrammingTest.txt",
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
0,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
2.6
Khóa
qile
41
42. • VD
(tiếp)
ReadFile(fileHandle,buff,128,&bytesRead,0);
buff[bytesRead]
=
0;
printf("File
content:%sn",buff);
LockFile(fileHandle,0,0,100,0);
//
Exclusive
Lock
printf("File
is
locked,
press
any
key
to
unlock...n");
getch();
UnlockFile(fileHandle,0,0,100,0);
printf("File
is
unlockedn");
getch();
CloseHandle(fileHandle);
2.6
Khóa
qile
42
43. • Ứng
dụng
tạo
}ile
tạm
để
lưu
trữ
thông
tin
tạm
thời
của
chương
trình.
• File
tạm
nên
được
tạo
lập
một
cách
an
toàn,
và
xóa
khi
kết
thúc
chương
trình.
• Trên
unix/linux:
• Hàm
mkstemp()
có
thể
sử
dụng
để
tạo
}ile
tạm
với
tên
ngẫu
nhiên.
• Ứng
dụng
cần
xóa
}ile
theo
tên,
ngay
sau
lời
gọi
mkstemp
để
đảm
bảo
không
tiến
trình
nào
truy
nhập
được.
• Sau
khi
tiến
trình
kết
thúc
một
cách
bình
thường/không
bình
thường,
}ile
tạm
sẽ
không
thể
truy
nhập
được
nữa.
• VD
char
szPath[]
=
“fileXXXXXX";
int
fd;
fd
=
mkstemp(szPath);
unlink(szPath);
printf("Temperary
file
created,
press
any
key
to
continue...");
write(fd,"Hello",5);
close(fd);
2.7
Tạo
qile
tạm
43
44. • Trên
Windows:
• Không
có
hàm
tương
đương
mkstemp()
• GetTempFileName()
sinh
tên
}ile
ngẫu
nhiên
nhưng
dễ
đoán.
• GetTempPath()
lấy
đường
dẫn
đến
thư
mục
tạm
của
người
dùng
hiện
tại.
• Tạo
}ile
bằng
hàm
CreateFile
với
hai
thuộc
tính
FILE_ATTRIBUTE_TEMPORARY
và
FILE_FLAG_DELETE_ON_CLOSE
• VD
HANDLE
}ileHandle
=
NULL;
}ileHandle
=
CreateFile(L"C:SecureProgrammingTmp.txt",
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
0,
OPEN_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY|
FILE_FLAG_DELETE_ON_CLOSE,
0);
2.7
Tạo
qile
tạm
44
45. • Trên
Unix/Linux,
ứng
dụng
có
thể
tự
giới
hạn
phạm
vi
truy
nhập
hệ
thống
tệp
tin
của
mình
bằng
lệnh
chroot()
• Sau
khi
gọi
chroot():
• Tiến
trình
không
thể
mở
rộng
phạm
vi
truy
nhập
bằng
lệnh
chroot
lần
nữa..
• Tiến
trình
chỉ
có
thể
thu
hẹp
hơn
nữa
phạm
vi
truy
nhập
của
mình.
• Tiến
trình
phải
chủ
động
gọi
thêm
chdir()
để
lệnh
chroot
có
hiệu
lực.
• VD:
#include
<unistd.h>
chroot("/new/root/directory");
chdir("/");
2.8
Hạn
chế
truy
nhập
đến
hệ
thống
qile
45
48. § Xung
đột
là
vấn
đề
phát
sinh
khi
nhiều
luồng
của
chương
trình
chạy
trên
bộ
vi
xử
lý
đa
nhân
cùng
truy
nhập
một
tài
nguyên
hệ
thống.
§ Ví
dụ
3.1
Khái
niệm
48
int
x
=
0;
DWORD
WINAPI
Thread(LPVOID
lpParam)
{
for
(int
i=0;i<2000000;i++)
x++;
return
0;
}
int
_tmain(int
argc,
_TCHAR*
argv[])
{
HANDLE
hThread1
=
CreateThread(NULL,NULL,Thread,NULL,NULL,NULL);
HANDLE
hThread2
=
CreateThread(NULL,NULL,Thread,NULL,NULL,NULL);
WaitForSingleObject(hThread1,INFINITE);
WaitForSingleObject(hThread2,INFINITE);
printf("X=%d",x);
getch();
return
0;
}
49. § Đoạn
găng
(Critical
Section)
là
đoạn
chương
trình
được
bảo
vệ
bởi
hệ
điều
hành
sao
cho
tại
mọi
thời
điểm
chỉ
có
một
luồng
được
phép
thực
thi.
§ Sử
dụng
§ Khai
báo:
CRITICAL_SECTION
cs
§ Khởi
tạo:
InitializeCriticalSection(&cs)
§ Sử
dụng
EnterCriticalSection(&cs)
//
Bắt
đầu
đoạn
găng
…
//
Kết
thúc
đoạn
găng
LeaveCriticalSection(&cs)
//
DeleteCriticalSection(&cs)
§ Ví
dụ
§ Đặc
điểm:
chỉ
có
tác
dụng
trong
cùng
một
tiến
trình
3.2
Đoạn
găng
49
50. § Đèn
hiệu
(Semaphore)
dùng
để
giới
hạn
số
lượng
luồng
tối
đa
được
phép
thực
thi
cùng
một
đoạn
chương
trình.
§ Sử
dụng
§ Khai
báo:
HANDLE
hSemaphore
§ Khởi
tạo:
hSemaphore
=
CreateSemaphore(NULL,5,5,NULL)
§ Sử
dụng
WaitForSingleObject(hSemaphore,
0L)
//
…
//
ReleaseSemaphore(hSemaphore,1,NULL)
//
CloseHandle(hSemaphore)
§ Ví
dụ
§ Đặc
điểm
§ Dùng
chung
được
giữa
các
tiến
trình
§ Tốc
độ
chậm
hơn
CRITICAL_SECTION
3.3
Đèn
hiệu
50
51. § Mutex
dùng
để
bảo
vệ
tài
nguyên
của
chương
trình,
tại
một
thời
điểm
chỉ
cho
phép
một
luồng
của
một
tiến
trình
truy
nhập.
§ Sử
dụng
§ Khai
báo:
HANDLE
hMutex;
§ Khởi
tạo:
hMutex
=
CreateMutex(NULL,
FALSE,
NULL)
§ Sử
dụng
WaitForSingleObject(hMutex,
INFINITE)
//
…
//
ReleaseMutex(hMutex)
§ Ví
dụ
§ Đặc
điểm
§ Chậm
hơn
CRITICAL_SECTION
§ Có
thể
đồng
bộ
giữa
các
tiến
trình
3.4
Mutex
51
52. § Event
dùng
đồng
bộ
hoạt
động
của
các
luồng
thông
qua
cơ
chế
báo
hiệu.
§ Sử
dụng
§ Khai
báo:
HANDLE
hEvent;
§ Khởi
tạo:
hMutex
=
CreateEvent(NULL,
TRUE,
FALSE,
“MyEvent”)
§ Sử
dụng
WaitForSingleObject(hEvent,
INFINITE)
//
…
SetEvent(hEvent)
//
Báo
hiệu
các
luồng
khác
ResetEvent(hEvent)
//
Chặn
các
luồng
khác
…
//
CloseHandle(hEvent)
§ Ví
dụ
3.5
Event
52
53. § SRW
Lock
(Slim
Reader
Writer
Lock
)dùng
đồng
bộ
hoạt
động
của
các
luồng
thông
tương
tự
như
đoạn
găng
§ Sử
dụng
§ Khai
báo:
SRWLOCK
lock;
§ Khởi
tạo:
InitializeSRWLock(&lock);
§ Sử
dụng
AcquireSRWLockShared(&lock)
AcquireSRWLockExclusive(&lock)
//
…
//
ReleaseSRWLockShared(&lock)
ReleaseSRWLockExclusive(&lock)
§ Ví
dụ
3.5
SRW
Lock
53
54. 1. Viết
chương
trình
chat
Client
và
Server
với
kênh
truyền
đã
mã
hóa
bằng
thuật
toán
AES-‐256,
sử
dụng
thư
viện
OpenSSL
và
CryptoAPI.
Mật
khẩu
mã
hóa
là
:
123456.
Việc
mã
hóa
và
việc
nhận
dữ
liệu
được
thực
hiện
đồng
thời
trên
2
luồng
riêng
biệt,
sử
dụng
cơ
chế
đồng
bộ
CRITICAL_SECTION
2. Viết
chương
trình
mã
hóa
và
giải
mã
tệp
tin
theo
thuật
toán
AES-‐256,
với
tên
nhập
từ
bàn
phím,
mật
khẩu
mã
hóa
là
:nopass.
Sử
dụng
thư
viện
OpenSSL
và
CryptoAPI
Bài
tập
54
55. Lương
Ánh
Hoàng
hoangla@soict.hut.edu.vn
Chương
4.
Mã
hóa
đối
xứng
Symmetric
Crytography
56. 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
57. • 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
58. • 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
59. • 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
60. • 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
61. • 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
/
62. • Đ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
63. • 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
64. • 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
http://www.ie7pro.com/
openssl.html
4.5
Mã
hóa
đối
xứng
với
OpenSSL
64
65. • 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
đề
<openssl/evp.h>.
• 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
66. • 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
67. • 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
68. • 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
69. • 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
70. • Thư
viện
CryptoAPI
4.6
Microsoft
Crypto
API
70
71. • 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ã
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.
• 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
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.
• 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
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.
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
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.
• 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
76. • 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;
77. • 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))
;
}
78. • 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);
}
79. • 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);
80. • 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
81. Lương
Ánh
Hoàng
hoangla@soict.hut.edu.vn
Chương
5.
Hàm
băm
và
xác
thực
thông
điệp
Hashes
and
Message
Authentication
82. 5.1
Các
loại
hàm
băm
và
MAC
thông
dụng
5.2
Băm
với
OpenSSL
5.3
Băm
dữ
liệu
với
CryptoAPI
5.4
Xác
thực
thông
điệp
với
HMAC
5.5
Salt
Nội
dung
82
83. • Hàm
băm
(hashes)
– Nhận
đầu
vào
là
một
xâu
và
đầu
ra
là
một
chuỗi
bit
có
chiều
dài
xác
định.
– Tỉ
lệ
đụng
độ
rất
nhỏ.
– Dùng
để
kiểm
tra
tính
toàn
vẹn
của
dữ
liệu
nhưng
không
đảm
bảo
tính
xác
thực
của
dữ
liệu.
– Thường
kết
hợp
với
mô
hình
mã
hóa
công
khai
chứ
không
sử
dụng
một
mình.
– Các
giải
thuật
băm
thông
dụng:
MD5,
SHA1
5.1
Các
hàm
băm
và
MAC
thông
dụng
83
84. • Hàm
băm
(hashes)
5.1
Các
hàm
băm
và
MAC
thông
dụng
84
Algorithm
Digest
size
Security
conqidence
Small
message
speed
(64
bytes),
in
cycles
per
byte[2]
Large
message
speed
(8K),
in
cycles
per
byte
Uses
block
cipher
Davies-‐Meyer-‐
AES-‐128
128
bits
(same
length
as
cipher
block
size)
Good
46.7
cpb
57.8
cpb
Yes
MD2
128
bits
Good
to
low
392
cpb
184
cpb
No
MD4
128
bits
Insecure
32
cpb
5.8
cpb
No
MD5
128
bits
Very
low,
may
be
insecure
40.9
cpb
7.7
cpb
No
MDC-‐2-‐AES-‐128
256
bits
Very
high
93
cpb
116
cpb
Yes
MDC-‐2-‐DES
128
bits
Good
444
cpb
444
cpb
Yes
RIPEMD-‐160
160
bits
High
62.2
cpb
20.6
cpb
No
SHA1
160
bits
High
53
cpb
15.9
cpb
No
SHA-‐256
256
bits
Very
high
119
cpb
116
cpb
No
SHA-‐384
384
bits
Very
high
171
cpb
166
cpb
No
SHA-‐512
512
bits
Very
high
171
cpb
166
cpb
No
85. • Xác
thực
thông
điệp
(Message
Authentication
Code)
– Nhận
đầu
vào
là
một
xâu
và
một
khóa
bí
mật,
đầu
ra
là
một
mã
có
chiều
dài
xác
định.
– Dùng
để
kiểm
tra
tính
toàn
vẹn
và
xác
thực
của
dữ
liệu.
– Các
giải
thuật
thông
dụng:
OMAC,
CMAC,
HMAC
5.1
Các
hàm
băm
và
MAC
thông
dụng
85
86. • Xác
thực
thông
điệp
(Message
Authentication
Code)
5.1
Các
hàm
băm
và
MAC
thông
dụng
86
MAC
Built
upon
Small
message
speed
(64
bytes)[4]
Large
message
speed
(8K)
Appropriate
for
hardware
Patent
restric-‐
tions
Parallel-‐izable
CMAC
A
universal
hash
and
AES
~18
cpb
~18
cpb
Yes
No
Yes
HMAC-‐SHA1
Message
digest
function
90
cpb
20
cpb
Yes
No
No
MAC127
hash127
+
AES
~6
cpb
~6
cpb
Yes
No
Yes
OMAC1
AES
29.5
cpb
37
cpb
Yes
No
No
OMAC2
AES
29.5
cpb
37
cpb
Yes
No
No
PMAC-‐AES
Block
cipher
72
cpb
70
cpb
Yes
Yes
Yes
RMAC
Block
cipher
89
cpb
80
cpb
Yes
No
No
UMAC32
UHASH
and
AES
19
cpb
cpb
No
No
Yes
XMACC-‐SHA1
Any
cipher
or
MD
function
162
cpb
29
cpb
Yes
Yes
Yes
87. • OpenSSL
cung
cấp
hai
loại
giao
diện
với
các
hàm
băm
– Giao
diện
riêng
rẽ
với
mỗi
giải
thuật
băm
cụ
thể.
• Mỗi
giải
thuật
băm
có
tệp
tiêu
đề
riêng
• Tên
gọi
các
hàm
là
khác
nhau
cho
các
giải
thuật
băm.
– Giao
diện
chung
EVP
cho
mọi
loại
hàm
băm.
• Tệp
tiêu
đề
chung:
<openssl/evp.h>
• Trình
tự
sử
dụng
như
nhau:
– Khởi
tạo
ngữ
cảnh:
EVP_DigestInit
– Cập
nhật
dữ
liệu
băm:
EVP_DigestUpdate
– Lấy
kết
quả:
EVP_DigestFinal.
5.2
Băm
dữ
liệu
với
OpenSSL
87
88. • VD:
Băm
với
SHA1
5.2
Băm
dữ
liệu
với
OpenSSL
88
#include
<openssl/sha.h>
int
i;
SHA_CTX
ctx;
unsigned
char
result[SHA_DIGEST_LENGTH];
/*
SHA1
has
a
20-‐byte
digest.
*/
unsigned
char
*s1
=
(unsigned
char*)"Testing";
unsigned
char
*s2
=
(unsigned
char*)"...1...2...3...";
SHA1_Init(&ctx);
SHA1_Update(&ctx,
s1,
strlen((char*)s1));
SHA1_Update(&ctx,
s2,
strlen((char*)s2));
/*
Yes,
the
context
object
is
last.
*/
SHA1_Final(result,
&ctx);
printf("SHA1("%s%s")
=
",
s1,
s2);
for
(i
=
0;
i
<
SHA_DIGEST_LENGTH;
i++)
printf("%02x",
result[i]);
printf("n");
89. • VD:
Băm
với
giao
diện
EVP
5.2
Băm
dữ
liệu
với
OpenSSL
89
#include
<openssl/evp.h>
#include
<stdio.h>
#include
<string.h>
int
i
,
ol;
EVP_MD_CTX
ctx;
unsigned
char
*result;
unsigned
char
*s1
=
(unsigned
char*)"Testing";
unsigned
char
*s2
=
(unsigned
char*)"...1...2...3...";
EVP_DigestInit(&ctx,
EVP_sha1());
EVP_DigestUpdate(&ctx,
s1,
strlen((char*)s1));
EVP_DigestUpdate(&ctx,
s2,
strlen((char*)s2));
if
(!(result
=
(unsigned
char
*)malloc(EVP_MD_CTX_block_size(&ctx))))abort();
EVP_DigestFinal(&ctx,
result,
&ol);
printf("SHA1("%s%s")
=
",
s1,
s2);
for
(i
=
0;
i
<
ol;
i++)
printf("%02x",
result[i]);
printf("n");
free(result);
90. • Trình
tự
băm
với
CryptoAPI
– Tệp
tiêu
đề:
Wincrypt.h
– Khởi
tạo
ngữ
cảnh
Provider:
CryptAcquireContext
– Tạo
đối
tượng
hash:
CryptCreateHash
– Băm
liên
tiếp
với:
CryptHashData
– Lấy
kết
quả:
CryptGetHashParam
– Giải
phóng
đói
tượng
hash:
CryptDestroyHash
5.3
Băm
dữ
liệu
với
CryptoAPI
90
91. • Ví
dụ:
Băm
dữ
liệu
với
thuật
toán
SHA-‐256
5.3
Băm
dữ
liệu
với
CryptoAPI
91
BYTE
*pbData;
DWORD
cbData
=
sizeof(DWORD),
cbHashSize,
i;
HCRYPTHASH
hSHA256;
HCRYPTPROV
hProvider;
unsigned
char
*s1
=
(unsigned
char*)"Testing";
unsigned
char
*s2
=
(unsigned
char*)"...1...2...3...";
//
Khởi
tạo
ngữ
cảnh
Provider
CryptAcquireContext(&hProvider,
0,
MS_ENH_RSA_AES_PROV,
PROV_RSA_AES,
0);
//
Tạo
đối
tượng
hàm
băm
CryptCreateHash(hProvider,
CALG_SHA_256,
0,
0,
&hSHA256);
//
Thực
hiện
băm
CryptHashData(hSHA256,
s1,
strlen((char*)s1),
0);
CryptHashData(hSHA256,
s2,
strlen((char*)s2),
0);
//
Thực
hiện
băm…
92. • Ví
dụ:
Băm
dữ
liệu
với
thuật
toán
SHA-‐256
(tiếp)
5.3
Băm
dữ
liệu
với
CryptoAPI
92
//
Lấy
kích
thước
dữ
liệu
băm
được
CryptGetHashParam(hSHA256,
HP_HASHSIZE,
(BYTE
*)&cbHashSize,
&cbData,
0);
pbData
=
(BYTE
*)LocalAlloc(LMEM_FIXED,
cbHashSize);
//
Lấy
dữ
liệu
băm
được
CryptGetHashParam(hSHA256,
HP_HASHVAL,
pbData,
&cbHashSize,
0);
//
Giải
phóng
đối
tượng
băm
và
ngữ
cảnh
Provider
CryptDestroyHash(hSHA256);
CryptReleaseContext(hProvider,
0);
printf("SHA256("%s%s")
=
",
s1,
s2);
for
(i
=
0;
i
<
cbHashSize;
i++)
printf("%02x",
pbData[i]);
printf("n");
LocalFree(pbData);
93. • Với
OpenSSL
– Tệp
tiêu
đều
<openssl/hmac.h>
– Gọi
hàm
HMAC_Init
để
khởi
tạo
ngữ
cảnh
và
key
sẽ
sử
dụng
– Liên
tục
gọi
hàm
HMAC_Update
để
cập
nhật
dữ
liệu.
– Gọi
hàm
HMAC_Final
để
kết
thúc
quá
trình
băm
– Gọi
hàm
HMAC_cleanup
để
xóa
key
khỏi
bộ
nhớ.
– Có
thể
gọi
hàm
All-‐in-‐one
HMAC
– Bên
nhận
kiểm
tra
lại
bằng
cách
thực
hiện
băm
với
với
cùng
một
key
và
giải
thuật
và
so
sánh
kết
quả
5.4
Xác
thực
thông
điệp
với
HMAC
93
94. • Với
OpenSSL
5.4
Xác
thực
thông
điệp
với
HMAC
94
int
i;
HMAC_CTX
ctx;
unsigned
int
len;
unsigned
char
out[20];
unsigned
char
*
key
=
(unsigned
char*)"secret";
int
keylen
=
strlen((char*)key);
//
Khởi
tạo
HMAC
với
key
là
secret
HMAC_Init(&ctx,
key,
keylen,
EVP_sha1(
));
//
Thực
hiện
băm
xâu
"fr
HMAC_Update(&ctx,
(unsigned
char*)"hash
me
pls",
11);
//
Lấy
kết
quả
HMAC_Final(&ctx,
out,
&len);
for
(i
=
0;
i
<
len;
i++)
printf("%02x",
out[i]);
printf("n");
95. • Với
CryptAPI
– Tạo
đối
tượng
Hash
với
hàm
CryptCreateHash,
trong
đó
tham
số
hKey
là
một
key
đã
được
tạo
trước.
– Thiết
lập
thông
tin
về
giải
thuật
băm
với
hàm
CryptSetHashParam.
– Thực
hiện
băm
với
hàm
CryptHashData
– Lấy
kích
thước,
nội
của
dữ
liệu
băm
được
với
hàm
CryptGetHashParam.
– Giải
phóng
đói
tượng
Hash
và
Key
5.4
Xác
thực
thông
điệp
với
HMAC
95
96. • Với
CryptAPI
5.4
Xác
thực
thông
điệp
với
HMAC
96
BYTE
out[20];
DWORD
cbData
=
sizeof(out),
i;
HCRYPTKEY
hKey;
HMAC_INFO
HMACInfo;
HCRYPTHASH
hHash;
HCRYPTPROV
hProvider;
//
Lấy
ngữ
cảnh
provider
CryptAcquireContext(&hProvider,
0,MS_ENH_RSA_AES_PROV,PROV_RSA_AES,CRYPT_VERIFYCONTEXT);
//
Sinh
key
từ
mật
khẩu
hKey
=
CreateKeyFromPassword(hProvider,"secret");
//
Tạo
đối
tượng
băm
CryptCreateHash(hProvider,
CALG_HMAC,
hKey,
0,
&hHash);
97. • Với
CryptAPI
5.4
Xác
thực
thông
điệp
với
HMAC
97
//
Thiết
lập
giải
thuật
băm
HMACInfo.HashAlgid
=
CALG_SHA1;
HMACInfo.pbInnerString
=
HMACInfo.pbOuterString
=
0;
HMACInfo.cbInnerString
=
HMACInfo.cbOuterString
=
0;
CryptSetHashParam(hHash,
HP_HMAC_INFO,
(BYTE
*)&HMACInfo,
0);
//
Thực
hiện
băm
CryptHashData(hHash,
(BYTE
*)"Hash
me
plz",
11,
0);
//
Lấy
kết
quả
CryptGetHashParam(hHash,
HP_HASHVAL,
out,
&cbData,
0);
for
(i
=
0;
i
<
cbData;
i++)
printf("%02x",
out[i]);
printf("n");
CryptDestroyHash(hHash);
CryptDestroyKey(hKey);
CryptReleaseContext(hProvider,
0);
98. • Salt
– Chuỗi
dữ
liệu
thêm
vào
để
tăng
không
gian
khóa
và
chống
lại
hình
thức
replay-‐attack.
– Hai
bên
có
thể
thỏa
thuận
chung
một
salt
nào
đó
thay
đổi
theo
thời
gian.
– Salt
thường
được
thêm
vào
đầu
thông
điệp
gốc,
sau
đó
thực
hiện
băm
cả
salt
cả
thông
điệp.
5.5
Sử
dụng
Salt
98
99. 1.
Viết
chương
trình
mã
hóa
và
giải
mã
tệp
tin
bằng
giải
thuật
AES-‐256
bit.
Mật
khẩu
nhập
từ
bàn
phím.
Kiểm
tra
tính
đúng
đắn
của
kết
quả
bằng
giải
thuật
SHA-‐256.
Sử
dụng
thư
viện
OpenSSL.
Khuôn
dạng
dữ
liệu
của
tệp
tin
sau
khi
mã
hóa
có
thể
như
sau:
<Kích
thước><Nội
dung
tệp
tin
đã
mã><Giá
trị
băm
SHA-‐256>
2.
Viết
chương
trình
chat
client-‐server
đơn
giản
trong
đó
kênh
truyền
được
mã
hóa
theo
giải
thuật
AES-‐256.
Key
được
sinh
ra
từ
mật
khẩu
thỏa
thuận
trước
và
không
truyền
qua
mạng,
Vector
khởi
tạo
là
mã
BCD
được
thiết
lập
từ
ngày
và
giờ
hiện
tại
của
hệ
thống
(Hàm
API
GetSystemTime).
Ví
dụ:
Nếu
hiện
tại
là
07h
ngày
10/10/2011
thì
giá
trị
dưới
dạng
hexa
của
vector
khởi
tạo
là
2011101007000….00
Bài
tập
99
100. 3.
Viết
chương
trình
băm
nội
dung
một
}ile
bằng
giải
thuật
HMAC-‐AES256,
sử
dụng
thư
viện
OpenSSL.
Mật
khẩu
để
băm
nhập
từ
bàn
phím.Kết
quả
băm
được
lưu
vào
cuối
}ile.
4.
Viết
chương
trình
kiểm
tra
tính
toàn
vẹn
của
một
}ile
bằng
giải
thuật
HMAC-‐AES256.
Mật
khẩu
để
kiểm
tra
nhập
từ
bàn
phím.
Bài
tập
100
101. Lương
Ánh
Hoàng
hoangla@soict.hut.edu.vn
Chương
6.
Mã
hóa
công
khai
Public
Key
Cryptography
102. 6.1
Mã
hóa
với
OpenSSL
RSA
6.2
Chữ
ký
số
6.3
Biểu
diễn
khóa
6.4
Kết
nối
SSL
6.5
Hạ
tầng
khóa
công
khai
Nội
dung
102
103. • Mã
hóa
bất
đối
xứng
• Là
các
giải
thuật
sử
dụng
một
cặp
khóa
cho
việc
mã
hóa
và
giải
mã
• Dữ
liệu
được
mã
hóa
bằng
khóa
công
khai
sẽ
được
giải
mã
bằng
khóa
bí
mật
và
ngược
lại.
• Các
giải
thuật
thông
dụng:
RSA,
DSA,
Dif}ie-‐Hellman.
• Không
sử
dụng
trực
tiếp
để
mã
hóa
dữ
liệu
vì
tốc
độ
rất
chậm.
• Thường
được
sử
dụng
để
• Trao
đổi
khóa
đối
xứng
trong
phiên
truyền
mật
• Chữ
ký
số
• Xác
nhận
danh
tính
• …
6.1
Mã
hóa
với
OpenSSL
RSA
103
104. • OpenSSL
RSA
• Thường
được
sử
dụng
trao
đổi
khóa
• Lưu
trữ
tất
cả
thông
tin
về
một
khóa
dưới
cấu
trúc
RSA.
• Tệp
tiêu
đề
rsa.h
• Sinh
cặp
khóa
đối
xứng
bằng
hàm
RSA
*RSA_generate_key(int
bits,
//
Kích
thước
khóa:
1024,2048…
unsigned
long
exp,//
Số
mũ:
3,
17,
65537
void
(*cb)(int,
int,
void),
//
Callback
void
*cb_arg);
6.1
Mã
hóa
với
OpenSSL
RSA
104
105. • Mã
hóa
với
khóa
công
khai
• Sử
dụng
hàm
RSA_public_encrypt:
int
RSA_public_encrypt(int
l,
//
Chiều
dài
dữ
liệu
unsigned
char
*pt,
//
Xâu/số
cần
mã
unsigned
char
*ct,
//
Kết
quả
RSA
*r,
//
Cấu
trúc
RSA
int
p);
//
Kiểu
padding
Kết
quả
trả
về:
chiều
dài
xâu
mã
được.
6.1
Mã
hóa
với
OpenSSL
RSA
105
106. • Giải
mã
với
khóa
bí
mật
• Sử
dụng
hàm
RSA_private_decrypt:
int
RSA_private_decrypt(int
l,
unsigned
char
*ct,
unsigned
char
*pt,
RSA
*r,
int
p);
Kết
quả
trả
về:
chiều
dài
xâu
giải
mã
được
6.1
Mã
hóa
với
OpenSSL
RSA
106
107. • Bài
tập
– Viết
chương
trình
chat
console
client-‐server
sử
dụng
giải
thuật
RSA.
Chỉ
chia
sẻ
public
key
trên
đường
truyền.
6.1
Mã
hóa
với
OpenSSL
RSA
107
108. • Chữ
ký
số
dữ
liệu
nhằm
xác
thực
danh
tính
của
người
gửi,
tương
tự
như
HMAC
nhưng
sử
dụng
giải
thuật
RSA
• Quá
trình
ký
số
dữ
liệu
nhận
đầu
vào
là
giá
trị
băm
của
thông
điệp,
khóa
bí
mật
của
người
gửi,
đầu
ra
là
giá
trị
hàm
băm
đã
được
mã
hóa.
• Bên
nhận
thực
hiện
quá
trình
ngược
lại:
tính
giá
trị
băm
của
thông
điệp,
giải
mã
giá
trị
băm
đã
mã
hóa
của
bên
gửi
bằng
khóa
công
khai
và
so
sánh
hai
giá
trị
băm
này.
• Hacker
không
thể
giả
mạo
giá
trị
băm
vì
không
có
khóa
bí
mật
của
bên
gửi.
6.2
Chữ
ký
số
108
109. • Sơ
đồ
ký
6.2
Chữ
ký
số
109
Dữ
liệu
Giá
trị
băm
(MD)
Hash
(SHA1)
Chữ
ký
Khóa
bí
mật
Mã
hóa
Dữ
liệu
+
Chữ
ký