4, 'modify' => 8, 'copy' => 16, 'annot-forms' => 32 ];
$protection = 192;
foreach[$permissions as $permission]
{
if [!isset[$options[$permission]]]
$this->Error['Incorrect permission: '.$permission];
$protection += $options[$permission];
}
if [$owner_pass === null]
$owner_pass = uniqid[rand[]];
$this->encrypted = true;
$this->padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08".
"\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A";
$this->_generateencryptionkey[$user_pass, $owner_pass, $protection];
}
/****************************************************************************
* *
* Private methods *
* *
****************************************************************************/
function _putstream[$s]
{
if [$this->encrypted]
$s = RC4[$this->_objectkey[$this->n], $s];
parent::_putstream[$s];
}
function _textstring[$s]
{
if [!$this->_isascii[$s]]
$s = $this->_UTF8toUTF16[$s];
if [$this->encrypted]
$s = RC4[$this->_objectkey[$this->n], $s];
return '['.$this->_escape[$s].']';
}
/**
* Compute key depending on object number where the encrypted data is stored
*/
function _objectkey[$n]
{
return substr[$this->_md5_16[$this->encryption_key.pack['VXxx',$n]],0,10];
}
function _putresources[]
{
parent::_putresources[];
if [$this->encrypted] {
$this->_newobj[];
$this->enc_obj_id = $this->n;
$this->_put['>'];
$this->_put['endobj'];
}
}
function _putencryption[]
{
$this->_put['/Filter /Standard'];
$this->_put['/V 1'];
$this->_put['/R 2'];
$this->_put['/O ['.$this->_escape[$this->Ovalue].']'];
$this->_put['/U ['.$this->_escape[$this->Uvalue].']'];
$this->_put['/P '.$this->Pvalue];
}
function _puttrailer[]
{
parent::_puttrailer[];
if [$this->encrypted] {
$this->_put['/Encrypt '.$this->enc_obj_id.' 0 R'];
$this->_put['/ID [[][]]'];
}
}
/**
* Get MD5 as binary string
*/
function _md5_16[$string]
{
return md5[$string, true];
}
/**
* Compute O value
*/
function _Ovalue[$user_pass, $owner_pass]
{
$tmp = $this->_md5_16[$owner_pass];
$owner_RC4_key = substr[$tmp,0,5];
return RC4[$owner_RC4_key, $user_pass];
}
/**
* Compute U value
*/
function _Uvalue[]
{
return RC4[$this->encryption_key, $this->padding];
}
/**
* Compute encryption key
*/
function _generateencryptionkey[$user_pass, $owner_pass, $protection]
{
// Pad passwords
$user_pass = substr[$user_pass.$this->padding,0,32];
$owner_pass = substr[$owner_pass.$this->padding,0,32];
// Compute O value
$this->Ovalue = $this->_Ovalue[$user_pass,$owner_pass];
// Compute encyption key
$tmp = $this->_md5_16[$user_pass.$this->Ovalue.chr[$protection]."\xFF\xFF\xFF"];
$this->encryption_key = substr[$tmp,0,5];
// Compute U value
$this->Uvalue = $this->_Uvalue[];
// Compute P value
$this->Pvalue = -[[$protection^255]+1];
}
}
?>
Nếu doanh nghiệp của bạn sử dụng Định dạng Tài liệu Di động để gửi dữ liệu riêng tư và nhạy cảm như tài liệu ngân hàng, bạn có thể cần sử dụng bảo vệ bằng mật khẩu. Trong bài viết này, bạn sẽ thấy cách mã hóa tệp PDF bằng các công cụ có sẵn cho PHP
Các loại mã hóa
Để bảo vệ nội dung tài liệu, phải sử dụng thuật toán mã hóa. PDF hỗ trợ mật mã đối xứng sử dụng mật khẩu do người tạo tài liệu chỉ định để tạo khóa mã hóa. Người nhận tài liệu phải nhập mật khẩu đó để giải mã tài liệu
Chúng tôi có hai thuật toán để lựa chọn, với độ dài khóa khác nhau. Khóa mã hóa được sử dụng càng lâu thì càng khó bẻ mã
- RC4. Thuật toán đầu tiên được hỗ trợ bởi PDF. Thật không may, nó được coi là không an toàn vì nhiều lỗ hổng đã được phát hiện. Tuy nhiên, đó là thuật toán duy nhất được triển khai bởi hầu hết các trình tạo PDF miễn phí. Độ dài khóa có sẵn là 40 và 128 bit
- Chuẩn Mã hóa Cấp cao. Thuật toán này được chấp thuận ngay cả bởi U. S. chính phủ để bảo vệ thông tin được phân loại. Không có khả năng đoán trước được việc bẻ khóa mật mã AES trong một thời gian hợp lý; . Nếu bạn nhận được tài liệu ngân hàng được bảo vệ bằng mật khẩu, rất có thể chúng đã được mã hóa bằng AES. Độ dài khóa có sẵn là 128 và 256 bit
Quyền Người dùng
Khi mã hóa tài liệu PDF, bạn có thể chỉ định hai mật khẩu. Một trong số đó dành cho bạn với tư cách là chủ sở hữu tài liệu, vì vậy bạn có thể thực hiện bất kỳ tác vụ chỉnh sửa và in nào. Bạn cũng có thể đặt mật khẩu người dùng cấp quyền truy cập hạn chế vào tài liệu
Bạn quyết định những đặc quyền bạn trao cho người khác. Ví dụ: bạn có thể không cho phép in chất lượng đầy đủ để người dùng chỉ có bản xem trước. Bạn có thể vô hiệu hóa chỉnh sửa, tháo rời cấu trúc trang, điền biểu mẫu, v.v.
Tuy nhiên, tùy thuộc vào trình đọc PDF để thực thi các quy tắc này. Một hacker có thể triển khai trình đọc của riêng họ để không tuân theo các giới hạn. Sau khi tài liệu được giải mã bằng mật khẩu, người đọc có toàn quyền truy cập vào tài liệu đó và có thể thực hiện bất kỳ thao tác nào
Trong các ví dụ bên dưới, chúng tôi sẽ đặt mật khẩu người dùng và chủ sở hữu riêng biệt, nhưng mật khẩu sau luôn là tùy chọn
Mã hóa bằng TCPDF
Thư viện TCPDF là công cụ miễn phí duy nhất mà tôi biết hỗ trợ tất cả các mật mã, bao gồm cả AES 256-bit mạnh nhất. Trong nội bộ, TCPDF sử dụng phần mở rộng OpenSSL và Hash của PHP để thực hiện mã hóa
$pdf = new TCPDF['P', 'mm', 'LETTER'];
$pdf->SetProtection[
['print', 'modify', 'copy', 'annot-forms', 'fill-forms', 'extract', 'assemble', 'print-high'],
'test123', 'test456', 3
];
$pdf->AddPage[];
$pdf->writeHTML['Hello world
'];
file_put_contents['output.pdf', $pdf->Output['', 'S']];
Đối số cuối cùng của phương thức SetProtection[]
là một số chỉ định thuật toán và độ dài khóa. Các số bắt đầu bằng 0
cho RC4 40 bit và kết thúc bằng 3
đại diện cho AES 256 bit
Nếu bạn đặt một mảng trống làm đối số đầu tiên, sẽ không có quyền nào được cấp cho người dùng tài liệu ngoại trừ việc hiển thị nó trên màn hình
Mã hóa bằng mPDF
Thư viện mPDF hiển thị HTML tốt hơn TCPDF. Thật không may, nó không hỗ trợ nhiều loại thuật toán mã hóa như vậy. Bạn chỉ có thể chọn giữa mật mã RC4 40-bit và 128-bit. Độ dài khóa được chỉ định làm đối số thứ tư cho phương thức SetProtection[]
bên dưới
use Mpdf\Mpdf;
$pdf = new Mpdf[['format' => 'LETTER', 'orientation' => 'P']];
$pdf->SetProtection[
['print', 'modify', 'copy', 'annot-forms', 'fill-forms', 'extract', 'assemble', 'print-highres'],
'test123', 'test456', 128
];
$pdf->writeHTML['Hello world
'];
$pdf->Output['output.pdf', 'F'];
Mã hóa bằng Dompdf
Thư viện Dompdf khá tốt trong việc hiển thị mã HTML và CSS thành PDF. Khi nói đến mã hóa, nó chỉ hỗ trợ mật mã RC4 40 bit yếu
use Dompdf\Dompdf;
$pdf = new Dompdf[];
$pdf->getCanvas[]
->get_cpdf[]
->setEncryption['test123', 'test456', ['print', 'modify', 'copy', 'add']];
$pdf->loadHtml[$html];
$pdf->render[];
file_put_contents['output.pdf', $pdf->output[]];
Ngoài ra, Dompdf chỉ hỗ trợ bốn quyền cơ bản từ tiêu chuẩn PDF cũ hơn
Mã hóa với FPDF
Thư viện FPDF không có mã hóa tích hợp, nhưng có một đoạn mã riêng để triển khai RC4 40 bit
Setasign cung cấp một thư viện thương mại hỗ trợ mã hóa lên đến 256-bit AES
Mã hóa một tệp hiện có bằng các công cụ dòng lệnh
Nếu trình tạo PDF yêu thích của bạn không cung cấp mã hóa, bạn có thể sử dụng Máy chủ PDFtk để mã hóa tệp hiện có bằng RC4 128 bit. PDFtk không hỗ trợ AES
Với PDFtk, việc bảo vệ tệp đơn giản như chạy lệnh bên dưới trong thiết bị đầu cuối của bạn
pdftk input.pdf output encrypted.pdf owner_pw test123 user_pw test456
Để sử dụng AES, bạn cần chọn một công cụ thương mại chẳng hạn
Tóm lược
Mã hóa tài liệu là một cách tốt để bảo vệ nội dung tài liệu khỏi bị truy cập trái phép. Tài liệu ngân hàng thường được gửi qua email và chúng có thể bị đánh cắp từ tài khoản của một người. Với mã hóa mạnh, không thể đọc chúng