jsq / psr7-stream-encryption
用于加密和解密任意大小的数据流。
0.4.0
2020-02-29 21:40 UTC
Requires
- php: >=7.1
- ext-openssl: *
- guzzlehttp/psr7: ~1.0
- psr/http-message: ~1.0
Requires (Dev)
- phpunit/phpunit: ^6.0
This package is auto-updated.
Last update: 2024-08-29 03:36:47 UTC
README
PHP的内置OpenSSL绑定提供了加密和解密数据的便捷方式。然而,由ext-openssl
提供的接口仅对字符串进行操作,因此解密大型密文需要将整个密文加载到内存中,并接收包含全部解码明文的字符串。
本包旨在允许加密和解密任意大小的数据流。它支持使用AES-CBC、AES-CTR和AES-ECB进行流式加密和解密。
不推荐在新的系统中使用AES-ECB。它包括在内是为了与旧系统兼容。有关ECB的缺点,请参考维基百科上的讨论。
用法
使用加密装饰器装饰一个Psr\Http\Message\StreamInterface
实例,以便在调用装饰流上的read
时逐步加密装饰流的內容
$iv = random_bytes(openssl_cipher_iv_length('aes-256-cbc')); $cipherMethod = new Cbc($iv); $key = 'some-secret-password-here'; $inStream = new Stream(fopen('some-input-file', 'r')); // Any PSR-7 stream will be fine here $cipherTextStream = new AesEncryptingStream($inStream, $key, $cipherMethod); // Wrap the stream in an EncryptingStream $cipherTextFile = Psr7\stream_for(fopen('encrypted.file', 'w')); Psr7\copy_to_stream($cipherTextStream, $cipherTextFile); // When you read from the encrypting stream, the data will be encrypted. // You'll also need to store the IV somewhere, because we'll need it later to decrypt the data. // In this case, I'll base64 encode it and stick it in a file (but we could put it anywhere where we can retrieve it later, like a database column) file_put_contents('encrypted.iv', base64_encode($iv));
在调用加密流上的read
之前不会执行加密。
要计算密文的HMAC,将装饰流包装在一个HashingStream
实例中
$hash = null; $ciphertext = new Jsq\EncryptionStreams\AesEncryptingStream( $plaintext, $key, $cipherMethod ); $hashingDecorator = new Jsq\EncryptionStreams\HashingStream( $ciphertext, $key, function ($calculatedHash) use (&$hash) { $hash = $calculatedHash; } ); while (!$ciphertext->eof()) { $ciphertext->read(1024 * 1024); } assert('$hash === $hashingDecorator->getHash()');
在解密密文时,在将其作为参数传递给解密流之前,将密文包装在一个哈希装饰器中
$key = 'secret key'; $iv = random_bytes(openssl_cipher_iv_length('aes-256-cbc')); $plainText = 'Super secret text'; $cipherText = openssl_encrypt( $plainText, 'aes-256-cbc', $key, OPENSSL_RAW_DATA $iv ); $expectedHash = hash('sha256', $cipherText); $hashingDecorator = new Jsq\EncryptingStreams\HashingStream( GuzzleHttp\Psr7\stream_for($cipherText), $key, function ($hash) use ($expectedHash) { if ($hash !== $expectedHash) { throw new DomainException('Cipher text mac does not match expected value!'); } } ); $decrypted = new Jsq\EncryptionStreams\AesEncryptingStream( $cipherText, $key, $cipherMethod ); while (!$decrypted->eof()) { $decrypted->read(1024 * 1024); }
与加密装饰器一样,HashingStream
是延迟执行的,并且只有在读取底层流时才会对底层流进行哈希处理。在上面的示例中,只有在读取了整个密文(并且所有但最后一个块已解密)后才会抛出异常。
HashingStream
不可定位,因此您需要将其包装在一个GuzzleHttp\Psr7\CachingStream
中,以支持随机访问。