使用 AES 256 CBC 解密 pdf 文件给出不可读的输出

Decryption of pdf file using AES 256 CBC gives non readable output

我有一些加密的 PDF 文件列表。单击每个 pdf 文件后,它应该使用 PDF.Js 使用 AES 256 CBC 进行解密和查看。我有以下代码(抱歉,它有点长,我在 JSFiddle 中尝试过,但遇到了保存和附加加密和解密文件的问题):

app.php

<?php

if($_POST['action'] == 'encrypt') {
    my_encrypt($_POST['filename']);
}

if($_POST['action'] == 'decrypt') {
    $result = my_decrypt($_POST['filename']);
    echo $result;
}

function my_encrypt($filename) {
    
    $filedata = file_get_contents($filename);
    // Remove the base64 encoding from our key
    $key = '8479768f48481eeb9c8304ce0a58481eeb9c8304ce0a5e3cb5e3cb58479768f4';
    $encryption_key = base64_decode($key);
    // Generate an initialization vector
    $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
    // Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
    $encrypted = openssl_encrypt($filedata, 'aes-256-cbc', $encryption_key, 0, $iv);
    // The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
    $result =  base64_encode($encrypted . '::' . $iv);
    $file = fopen('./files/Sampleencrypt.pdf', 'wb');
    fwrite($file, $result);
    fclose($file);
    echo $result;
    return $result;
}

function my_decrypt($filename) {
    $filedata = file_get_contents($filename);
    // Remove the base64 encoding from our key
    $key = '8479768f48481eeb9c8304ce0a58481eeb9c8304ce0a5e3cb5e3cb58479768f4';
    $encryption_key = base64_decode($key);
    // To decrypt, split the encrypted data from our IV - our unique separator used was "::"
    list($encrypted_data, $iv) = explode('::', base64_decode($filedata), 2);
    $result = openssl_decrypt($encrypted_data, 'aes-256-cbc', $encryption_key, 0, $iv);

    return $result;
}
?>

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title></title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="build/pdf.js"></script>
    <link rel="stylesheet" href="style.css">

    <script>
        function encrypt(filename){
           
            $.ajax({
                type: "POST",
                url: "app.php",
                data: { action:'encrypt', filename: filename }
            }).done(function( msg ) {
                alert( "Data returned: " + msg );
            });

            return false;
        }

        function decrypt(filename){
            
           $.ajax({
               type: "POST",
               url: "app.php",
               data: { action:'decrypt', filename: filename },
               success: function (response) {
                alert(response);
                showPdf(response);
                }
            })
           return false;
       }
    </script>
</head>
<body>
    
    <a href="./files/Sampleencrypt.pdf" onclick="return decrypt(this.href);">Decrypt Sample</a> </br>
    <a href="./files/A Sample PDF.pdf" onclick="return encrypt(this.href);">Encrypt Sample</a><br>
    <br>
    
    <h1>PDF.js Previous/Next example</h1>
    <div>
      <button id="prev">Previous</button>
      <button id="next">Next</button>
      &nbsp; &nbsp;
      <span>Page: <span id="page_num"></span> / <span id="page_count"></span></span>
    </div>
    <div>
        <canvas id="can"></canvas>
    </div>
    <script type="text/javascript" src="test.js"></script>
</body>
</html>

test.js

var canvas = document.getElementById('can');
var context = canvas.getContext('2d');

var pdfDoc = null,
  pageNum = 1,
  pageRendering = false,
  pageNumPending = null,
  scale = 1.5;

  function renderPage(num) {
    pageRendering = true;
    // Using promise to fetch the page
    pdfDoc.getPage(num).then(function(page) {
      var viewport = page.getViewport({scale: scale});
      canvas.height = viewport.height;
      canvas.width = viewport.width;
  
      // Render PDF page into canvas context
      var renderContext = {
        canvasContext: context,
        viewport: viewport
      };
      var renderTask = page.render(renderContext);
  
      // Wait for rendering to finish
      renderTask.promise.then(function() {
        pageRendering = false;
        if (pageNumPending !== null) {
          // New page rendering is pending
          renderPage(pageNumPending);
          pageNumPending = null;
        }
      });
    });
  
    // Update page counters
    document.getElementById('page_num').textContent = num;
  }

function queueRenderPage(num) {
    if (pageRendering) {
      pageNumPending = num;
    } else {
      renderPage(num);
    }
  }
  
  function onPrevPage() {
    if (pageNum <= 1) {
      return;
    }
    pageNum--;
    queueRenderPage(pageNum);
  }
  document.getElementById('prev').addEventListener('click', onPrevPage);
  
  function onNextPage() {
    if (pageNum >= pdfDoc.numPages) {
      return;
    }
    pageNum++;
    queueRenderPage(pageNum);
  }
  document.getElementById('next').addEventListener('click', onNextPage);


function showPdf(pdfData){
      // Loaded via <script> tag, create shortcut to access PDF.js exports.
      var pdfjsLib = window['pdfjs-dist/build/pdf'];
      
      // The workerSrc property shall be specified.
      pdfjsLib.GlobalWorkerOptions.workerSrc = './build/pdf.worker.js';
      
      // Using DocumentInitParameters object to load binary data.
      var loadingTask = pdfjsLib.getDocument({data: pdfData});
      loadingTask.promise.then(function(pdf) {
        console.log('PDF loaded');
        
        pdfDoc = pdf;
        //display total page number.
        document.getElementById('page_count').textContent = pdf.numPages;

        renderPage(pageNum);
      }, function (reason) {
        // PDF loading error
        console.error(reason);
      });

}

我正在使用 PDFJS(文档中的 base64 编码 PDF 示例)来显示 pdf 文件。 有些文件可以使用此功能(非常小的示例文件)。但是对于其他pdf文件,加密文件的解密给出了字符串输出,其中一些文本不可读(如S��*��AK������^����0)并且它们使用pdf.js加载但是没有得到显示。如果我将这个解密的输出保存在一个文件中并打开该文件,它是预期的。只有 PDFJS 无法显示它。我没有得到确切的问题。问题出在解密还是 PDFJS 代码中?请帮忙。

得到解决方案,将解密文件结果转换为base64,并在PDF.js中解码这个base-64编码的字符串。添加了以下代码:

app.php

    function my_decrypt($filename) {
    $filedata = file_get_contents($filename);
    // Remove the base64 encoding from our key
    $key = '8479768f48481eeb9c8304ce0a58481eeb9c8304ce0a5e3cb5e3cb58479768f4';
    $encryption_key = base64_decode($key);
    // To decrypt, split the encrypted data from our IV - our unique separator used was "::"
    list($encrypted_data, $iv) = explode('::', base64_decode($filedata), 2);
    $result = openssl_decrypt($encrypted_data, 'aes-256-cbc', $encryption_key, 0, $iv);
    $result =  base64_encode($result);
    return $result;
}

test.js

    function showPdf(pdfData){
    
      // Loaded via <script> tag, create shortcut to access PDF.js exports.
      var pdfjsLib = window['pdfjs-dist/build/pdf'];
      
      // The workerSrc property shall be specified.
      pdfjsLib.GlobalWorkerOptions.workerSrc = './build/pdf.worker.js';
      
      // Using DocumentInitParameters object to load binary data.
      var loadingTask = pdfjsLib.getDocument({data: atob(pdfData)});
      loadingTask.promise.then(function(pdf) {
        console.log('PDF loaded');
        
        pdfDoc = pdf;
        //display total page number.
        document.getElementById('page_count').textContent = pdf.numPages;

        renderPage(pageNum);
      }, function (reason) {
        // PDF loading error
        console.error(reason);
      });

}

谢谢!