Hãy xem. PKCS # 7 được mô tả trong RFC 5652 (Cú pháp thông báo mật mã).
Sơ đồ đệm được đưa ra trong phần 6.3. Content-encryption Process. Về cơ bản nó nói: nối thêm nhiều byte khi cần để điền vào kích thước khối đã cho (nhưng ít nhất một), và mỗi byte phải có độ dài đệm là giá trị.
Vì vậy, nhìn vào byte được giải mã cuối cùng, chúng tôi biết có bao nhiêu byte để loại bỏ. (Người ta cũng có thể kiểm tra xem tất cả họ có cùng giá trị không.)
Bây giờ tôi có thể cung cấp cho bạn một cặp chức năng PHP để thực hiện việc này, nhưng PHP của tôi hơi bị gỉ. Vì vậy, hoặc tự làm điều này (sau đó cảm thấy tự do để chỉnh sửa câu trả lời của tôi để thêm nó vào), hoặc có một cái nhìn tại user-contributed notes để tài liệu mcrypt - khá một số trong số đó là về đệm và cung cấp một thực hiện PKCS # 7 padding.
Vì vậy, chúng ta hãy nhìn vào first note there chi tiết:
<?php
function encrypt($str, $key)
{
$block = mcrypt_get_block_size('des', 'ecb');
này được kích thước khối của thuật toán được sử dụng. Trong trường hợp của bạn, bạn sẽ sử dụng aes
hoặc rijndael_128
thay vì des
, tôi giả sử (tôi đã không kiểm tra). (Thay vào đó, bạn chỉ có thể kéo dài 16
vào đây để AES, thay vì cách gọi hàm.)
$pad = $block - (strlen($str) % $block);
này tính toán kích thước đệm. strlen($str)
là độ dài dữ liệu của bạn (tính theo byte), % $block
cung cấp phần còn lại là modulo $block
, tức là số byte dữ liệu trong khối cuối cùng. $block - ...
do đó cung cấp số byte cần thiết để điền vào khối cuối cùng này (bây giờ là một số giữa 1
và $block
, bao gồm).
$str .= str_repeat(chr($pad), $pad);
str_repeat
tạo ra một chuỗi bao gồm một sự lặp lại của cùng một chuỗi, đây là một sự lặp lại của character given by$pad
, $pad
lần, tức là một chuỗi có độ dài $pad
, đầy $pad
. $str .= ...
gắn chuỗi đệm này vào dữ liệu gốc.
return mcrypt_encrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB);
Đây là bản thân mã hóa. Sử dụng MCRYPT_RIJNDAEL_128
thay vì MCRYPT_DES
.
}
Bây giờ theo một hướng khác:
function decrypt($str, $key)
{
$str = mcrypt_decrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB);
Các giải mã. (Tất nhiên, bạn sẽ thay đổi thuật toán, như trên). $ str bây giờ là chuỗi được giải mã, bao gồm cả phần đệm.
$block = mcrypt_get_block_size('des', 'ecb');
Đây lại là kích thước khối. (Xem bên trên.)
$pad = ord($str[($len = strlen($str)) - 1]);
Điều này có vẻ hơi lạ. Better viết nó trong nhiều bước:
$len = strlen($str);
$pad = ord($str[$len-1]);
$len
bây giờ là chiều dài của chuỗi đệm, và $str[$len - 1]
là ký tự cuối cùng của chuỗi này. ord
chuyển đổi số này thành một số. Do đó $pad
là số mà trước đây chúng tôi đã sử dụng làm giá trị điền cho phần đệm và đây là độ dài đệm.
return substr($str, 0, strlen($str) - $pad);
Vì vậy, bây giờ chúng tôi đã cắt $pad
byte cuối cùng khỏi chuỗi. (Thay vì strlen($str)
chúng tôi cũng có thể viết $len
tại đây: substr($str, 0, $len - $pad)
.).
}
?>
Lưu ý rằng thay vì sử dụng substr($str, $len - $pad)
, người ta cũng có thể viết substr($str, -$pad)
, như substr
hàm trong PHP có một đặc biệt xử lý cho toán hạng âm/lập luận, để đếm từ ngày kết thúc của chuỗi. (Tôi không biết nếu điều này là nhiều hơn hoặc ít hiệu quả hơn so với chiều dài đầu tiên và tính toán chỉ mục theo cách thủ công.)
Như đã nói ở trên và ghi chú trong nhận xét của rossum, thay vì chỉ đơn giản là loại bỏ phần đệm như đã làm ở đây, bạn nên kiểm tra xem nó có đúng không - tức là xem substr($str, $len - $pad)
và kiểm tra xem tất cả các byte của nó là chr($pad)
. Điều này phục vụ như một kiểm tra nhẹ chống lại tham nhũng (mặc dù kiểm tra này là hiệu quả hơn nếu bạn sử dụng một chế độ chuỗi thay vì ECB, và không phải là một thay thế cho một MAC thực).
(Và vẫn còn, hãy nói với khách hàng của bạn họ nên suy nghĩ về việc thay đổi sang một chế độ an toàn hơn ECB).
Chỉ cần một lưu ý: Nếu bạn có thể thay đổi, sử dụng [một chế độ hơn ECB (nó là không an toàn)] (http: //en.wikipedia. org/wiki/Block_cipher_modes_of_operation). –
@Paul Không, không thể thay đổi, hệ thống của khách hàng phụ thuộc vào những gì. Bất kỳ cơ hội bạn có thể hướng dẫn tôi với điều padding? –
Tôi có nghĩa là AES, đã sửa nó. –