Can't decrypt encrypted file using libsodium

2019-08-03 03:41发布

问题:

I'm working on the encryption using libsodium my problem is the decryption part, its not going through and displaying error.

Fatal error: Uncaught SodiumException: ops limit must be greater than 0 in C:\xampp\htdocs\encrypter\decrypt.php:18 Stack trace: #0 C:\xampp\htdocs\encrypter\decrypt.php(18): sodium_crypto_pwhash() #1 {main} thrown in C:\xampp\htdocs\encrypter\decrypt.php on line 18

I tried to copy some lines in the encryption code but didn't work.

I also receive warning.

But I don't know if this is the cause. I also receive this on encryption.

Warning: unpack(): 64-bit format codes are not available for 32-bit versions of PHP in C:\xampp\htdocs\encrypter\decrypt.php on line 11

Warning: unpack(): 64-bit format codes are not available for 32-bit versions of PHP in C:\xampp\htdocs\encrypter\decrypt.php on line 12

UPDATE

  • The warning is fixed by changing the pack() code from P to V.

  • Upon changing the code the $opslimit has a value more than 0.

DECRYPTION CODE

$password = 'password';
$encrypted_file = 'tmp/inc.php';
$decrypted_file = 'tmp/inc.dec';

$fd_in = fopen($encrypted_file, 'rb');
$fd_out = fopen($decrypted_file, 'wb');

$alg = unpack('C', fread($fd_in, 1))[1];
$opslimit = unpack('V', fread($fd_in, 8))[1];
$memlimit = unpack('V', fread($fd_in, 8))[1];
$salt = fread($fd_in, SODIUM_CRYPTO_PWHASH_SALTBYTES);

$header = fread($fd_in, SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES);

$secret_key = sodium_crypto_pwhash(SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES,
                                   $password, $salt, $opslimit, $memlimit, $alg);

$stream = sodium_crypto_secretstream_xchacha20poly1305_init_pull($header, $secret_key);
do {
    $chunk = fread($fd_in, $chunk_size + SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES);
    $res = sodium_crypto_secretstream_xchacha20poly1305_pull($stream, $chunk);
    if ($res === FALSE) {
       break;
    }
    list($decrypted_chunk, $tag) = $res;
    fwrite($fd_out, $decrypted_chunk);
} while (!feof($fd_in) && $tag !== SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL);
$ok = feof($fd_in);

fclose($fd_out);
fclose($fd_in);

if (!$ok) {
    die('Invalid/corrupted input');
}

This is the source code I use from the libsodium example.

回答1:

The code was indeed not designed for 32 bit versions of PHP.

If you change P to V, you need to:

  • Do it both in calls to unpack() and calls to pack()
  • Change the number of bytes read/written from 8 to 4.

But the best thing to do would actually be trying to understand what the code does.

It stores the memory limit and iterations at the beginning of the file, so that these parameters can be recovered later when reading the file, without having to hard-code them.

pack() encodes a value in a fixed number of bytes. unpack() does the opposite. pack('P') encodes a 64 bit value into 8 bytes. unpack('P') reads 8 bytes and converts them into a value.

If your environment doesn't support 64 bit values, pack/unpack to 4 bytes, but you then need to write 4 bytes, not 8. And read 4 bytes as well, not 8.