Mã hóa chuỗi và tập tin - thư viện mcrypt


tự học php nâng cao 10/08/2015 Cùng chuyên mục

Mã hóa là một phần quan trọng bảo mật ứng dụng web. Mật khẩu sẽ sử dụng các hàm băm một chiều như md5(), sha1() - các thông tin cần bảo mật như email khách hàng,...sẽ dụng các thuật toán mã hóa như 3des - RIJNDAEL-...

Mã hóa dữ liệu bằng hàm băm một chiều

Các hàm băm thường được sử dụng cho việc mã hóa "mật khẩu" - nghĩa là các thông tin mang tính duy nhất, nhờ vào tính chất: cho mã băm biết trước không thể tính toán được chuỗi bit do hàm băm tạo ra ( hàm băm một chiều) và tính chất: không thể tính toán để tìm ra 2 chuỗi bit có cùng giá trị băm (2 mã băm khác nhau có chuỗi bit khác nhau). Do mỗi người dùng là một cá thể duy nhất, có thể có cùng tên nhưng cần phải có một thông tin mang tính riêng tư - tách biệt với các đối tượng khác, được gọi là mật khẩu. Để ở dạng thô như '123...' nó là các thông tin thiếu an toàn - còn khi được mã hóa sẽ có dạng '0dsf476c...'.

Chương trình xử lý sẽ tiếp nhận mật khẩu từ người dùng nhập vào sau đó sử dùng hàm băm mã hóa nó. Bây giờ, cho dù người khác có thấy được chuỗi mã hóa này cũng "không thể nào" dịch ngược được để xem mật khẩu đã nhập vào là gì, ở đây hiểu "không thể nào" dựa trên độ phức tạp của thuật toán và tài nguyên sử dụng [số lượng máy chủ lớn - thời gian tính toán cả tỷ năm, các điều kiện thực tế không đáp ứng được]. Tuy nhiên, nếu người dùng đặt mật khẩu dễ đoán như 123, admin,... quá ngắn (dưới 8 ký tự) thì có thể nhanh chóng tìm được mật khẩu khớp với đoạn mã hóa. Bạn nên đặt mật khẩu khóa đoán, từ 8 - 12 ký tự.

Có 2 hàm mã hóa dạng này là md5()sha1()... hàm md5() nhận chuỗi đầu vào và cho ra một chuỗi có chiều dài khoảng 32 ký tự asscii (chuỗi mã hóa 128bit)- hàm sha1(), bảo mật hơn hàm md5() - cho ra chuỗi có chiều dài khoảng 40 ký tự ascii (chuỗi mã hóa 160bit).

Ví dụ 1: Mã hóa mật khẩu người dùng (encode user password) sử dụng hàm md5()sha1()

<?php
	$password ="ran123";
	$_enpass = md5($password);
	echo "Ma hoa md5".$_enpass." chieu dai: ",strlen($_enpass)."<br>";
	$password = "r123";
	$_enpass = md5($password);
	echo "Ma hoa md5".$_enpass." chieu dai: ",strlen($_enpass)."<br>";
	$password ="ran123";
	$_enpass = sha1($password);
	echo "Ma hoa sha1".$_enpass." chieu dai: ",strlen($_enpass)."<br>";
	$password ="r123";
	$_enpass = sha1($password);
	echo "Ma hoa sha1".$_enpass." chieu dai: ",strlen($_enpass)."<br>";
	/*---xác thực mật khẩu---*/
	$password = "ran123";
	$_enpass = md5($password);
	if(md5("rn123") == $_enpass))
	{
		echo 'Mật khẩu đúng';
	}
	else
	{
		echo 'Mật khẩu sai';
	}
?>

sha1()md5() là 2 hàm dùng để mã hóa mật khẩu truyền thống. PHP giới thiệu hàm mã hóa crypt() có khả năng bảo mật cao hơn và tốc độ cũng giảm đi hẳn ( hàng trăm lần ). 

Cú pháp:

string crypt(string $str, [string $salt])

Trong đó:

  • $str: là chuỗi cần mã hóa
  • $salt: là một tùy chọn, ( một số ký tự ngẫn nhiên)

Ví dụ 2: mã hóa chuỗi '123' bằng hàm crypt()

<?php
$pass = '123';
echo crypt($pass);
?>

 MÃ HÓA FILE:

Bạn có thể mã hóa nội dung file bằng hàm md5_file(), sha1_file()
string md5_file(string $filename, [bool $raw_output])
Trong đó:
- $filename: là đường dẫn tới file
- (tùy chọn) $raw_ouput: khi thiết lập là TRUE - sẽ xuất ra định dạng nhị phân thô, dài 16bit
- return value: hàm sẽ trả ra chuỗi mã hóa nội dung file nếu thành công, trả ra FALSE nếu thất bại
Hàm sha1_file() - tương tự 

Ví dụ 3: Mã hóa file 'hash.txt' có nội dung 'file hash' bằng hàm md5_file()sha1_file():

<?php
	$file = 'hash.txt';
	echo 'MD5 file hash of '.$file .': '.md5_file($file).'<br>';
	echo 'MD5 file hash, raw_output of '.$file .': '.md5_file($filem,TRUE).'<br>';
	echo 'SHA1 file hash of '.$file .': '.sha1_file($file).'<br>';
	echo 'SHA1 file hash, raw_output of '.$file .': '.sha1_file($filem,TRUE).'<br>';
?>

MÃ HÓA ĐỐI XỨNG VÀ PHI ĐỐI XỨNG

Để sử dụng các hàm mã hóa đối xứng và phi đối xứng, bạn cần cài đặt thư viện Mcrypt - thư viện này hỗ trợ nhiều hàm thực hiện các thuận toán (có tên tương ứng) như AES, DES, RIJNDAEL..., được gọi là ciphers. Dưới đây là danh sách các ciphers mà Mcrypt hỗ trợ:

MCRYPT_3DES
MCRYPT_ARCFOUR_IV (libmcrypt > 2.4.x only)
MCRYPT_ARCFOUR (libmcrypt > 2.4.x only)
MCRYPT_BLOWFISH
MCRYPT_CAST_128
MCRYPT_CAST_256
MCRYPT_CRYPT
MCRYPT_DES
MCRYPT_DES_COMPAT (libmcrypt 2.2.x only)
MCRYPT_ENIGMA (libmcrypt > 2.4.x only, alias for MCRYPT_CRYPT)
MCRYPT_GOST
MCRYPT_IDEA (non-free)
MCRYPT_LOKI97 (libmcrypt > 2.4.x only)
MCRYPT_MARS (libmcrypt > 2.4.x only, non-free)
MCRYPT_PANAMA (libmcrypt > 2.4.x only)
MCRYPT_RIJNDAEL_128 (libmcrypt > 2.4.x only)
MCRYPT_RIJNDAEL_192 (libmcrypt > 2.4.x only)
MCRYPT_RIJNDAEL_256 (libmcrypt > 2.4.x only)
MCRYPT_RC2
MCRYPT_RC4 (libmcrypt 2.2.x only)
MCRYPT_RC6 (libmcrypt > 2.4.x only)
MCRYPT_RC6_128 (libmcrypt 2.2.x only)
MCRYPT_RC6_192 (libmcrypt 2.2.x only)
MCRYPT_RC6_256 (libmcrypt 2.2.x only)
MCRYPT_SAFER64
MCRYPT_SAFER128
MCRYPT_SAFERPLUS (libmcrypt > 2.4.x only)
MCRYPT_SERPENT(libmcrypt > 2.4.x only)
MCRYPT_SERPENT_128 (libmcrypt 2.2.x only)
MCRYPT_SERPENT_192 (libmcrypt 2.2.x only)
MCRYPT_SERPENT_256 (libmcrypt 2.2.x only)
MCRYPT_SKIPJACK (libmcrypt > 2.4.x only)
MCRYPT_TEAN (libmcrypt 2.2.x only)
MCRYPT_THREEWAY
MCRYPT_TRIPLEDES (libmcrypt > 2.4.x only)
MCRYPT_TWOFISH (for older mcrypt 2.x versions, or mcrypt > 2.4.x )
MCRYPT_TWOFISH128 (TWOFISHxxx are available in newer 2.x versions, but not in the 2.4.x versions)
MCRYPT_TWOFISH192
MCRYPT_TWOFISH256
MCRYPT_WAKE (libmcrypt > 2.4.x only)
MCRYPT_XTEA (libmcrypt > 2.4.x only)

Bạn cần lưu ý đến version của thư viện mcrypt khi sử dụng.
Thuật ngữ sử dụng:
- Mã hóa: encrypt hay encode
- Giải mã: decypt hay decode

Cú pháp hàm mã hóa cơ bản:
string mcrypt_encrypt ( string $cipher , string $key, string $data )
Cú pháp hàm giải mã cơ bản:
string mcrypt_decrypt ( string $cipher , string $key, string $data )


Trong đó:
-$cipher là một trong các loại cipher tronh danh sách ở trên
-$key là chìa khóa để mã hóa
-$data là dữ liệu cần mã hóa

 MÃ HÓA ĐỐI XỨNG 3DES:

Ví dụ 4: Mã hóa đối xứng 3DES - sử dụng thư viện mcrypt trong PHP.

<?php
	$text = "ma hoa doi xung 3des";
	$key = "123";
	//mã hóa
	$encode = mcrypt_encrypt("MCRYPT_3DES",$key,$text);
	//giải mã
	$decode = mcrypt_decrypt("MCRYPT_3DES",$key,$encode);
	echo "Code mã hóa: ".$encode." chiều dài ".strlen($encode)."<br>";
	echo "Code giải mã: ".$decode;
?>

 MÃ HÓA PHI ĐỐI XỨNG AES

Ví dụ 5: Mã hóa đối xứng AES - sử dụng thư viện mcrypt trong PHP

<?php
$text = "ma hoa doi xung AES";
$key = "123";
//mã hóa
$encode = mcrypt_encrypt("MCRYPT_RIJNDAEL_128",$key,$text);
//giải mã
$decode =  mcrypt_decrypt("MCRYPT_RIJNDAEL_128",$key,$encode);
echo "Code mã hóa: ".$encode." chiều dài ".strlen($encode)."
";
echo "Code giải mã: ".$decode;
//chuỗi là email
$text ="khachhang@example.com";
$key = "64hxts";
//mã hóa
$encode = mcrypt_encrypt("MCRYPT_RIJNDAEL_128",$key,$text);
//giải mã
$decode =  mcrypt_decrypt("MCRYPT_RIJNDAEL_128",$key,$encode);
echo "Code mã hóa: ".$encode." chiều dài ".strlen($encode)."
?>

(*) - Trong phiên bản PHP 5.6 các hàm mã hóa, giải mã của thư viện mcrypt, bắt buộc nhận vào 4 đối số ( các phiên bản trước chỉ cần 3 đối số )

Ví dụ 6: Sử dụng thư viện mcrypt trong PHP 5.6 (tham khảo php.net)

<?php
	$key_len = uniqid(true);
	$key = pack("H*",substr(sha1($key_len).md5($key_len),0,64));
    # show key size use either 16, 24 or 32 byte keys for AES-128, 192
    # and 256 respectively
    $key_size =  strlen($key);
    echo "Key size: " . $key_size . "<br>";
    
    $plaintext = "Văn bản gốc - chưa mã hóa";
	
    # create a random IV to use with CBC encoding - tạo khóa IV tự động sử dụng thuật toán CBC
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    
    # creates a cipher text compatible with AES (Rijndael block size = 256)
    # to keep the text confidential 
    # only suitable for encoded input that never ends with value 00h
    # (because of default zero padding)
    $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key,
                                 $plaintext, MCRYPT_MODE_CBC, $iv);

    # prepend the IV for it to be available for decryption
    $ciphertext = $iv . $ciphertext;
    
    # encode the resulting cipher text so it can be represented by a string
    $ciphertext_base64 = base64_encode($ciphertext);

    echo  $ciphertext_base64 . "<br>";

    # === WARNING ===

    # Resulting cipher text has no integrity or authenticity added
    # and is not protected against padding oracle attacks.
    
    # --- DECRYPTION ---
    
    $ciphertext_dec = base64_decode($ciphertext_base64);
    
    # retrieves the IV, iv_size should be created using mcrypt_get_iv_size()
    $iv_dec = substr($ciphertext_dec, 0, $iv_size);
    
    # retrieves the cipher text (everything except the $iv_size in the front)
    $ciphertext_dec = substr($ciphertext_dec, $iv_size);

    # may remove 00h valued characters from end of plain text
    $plaintext_dec = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $ciphertext_dec, MCRYPT_MODE_CBC, $iv_dec);
    
    echo  $plaintext_dec . "<br>";
?>	

Lưu ý: Chiều dài khóa nhận các giá trị 16, 24, 32 tương ứng cho mã hóa AES- 128 bit, 192 bit, 256 bit

Trong đó MCRYPT_RIJNDAEL_128, chuỗi mã hóa độ dài 128 bit ( xuất ra chuỗi khoảng 32 ký tự ascii) - MCRYPT_RIJNDAEL_192, chuỗi mã hóa 192 bit (nên dùng) - chuỗi mã hóa khoảng 48 ký tự ascii.

Trong các ứng dụng thực tế, nên dùng MCRYPT_RIJNDAEL_192  để mã hóa các thông tin như email khách hàng, địa chỉ,...

Lưu ý: mã hóa và giải mã phải cùng 1 cipher - nếu không sẽ không khớp giá trị



Bài liên quan:



Bình luận:


php xử lý chuỗi