Updated defuse\php-encryption to version 2.4.0

This commit is contained in:
Netkas 2023-07-11 18:31:54 -04:00
parent 56a220f704
commit ffa48ca0aa
No known key found for this signature in database
GPG key ID: 5DAF58535614062B
12 changed files with 215 additions and 46 deletions

View file

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Refactored `\ncc\Objects > PackageLock`
- Updated `defuse\php-encryption` to version 2.4.0
## [1.0.2] - 2023-06-29

View file

@ -4,6 +4,7 @@ namespace ncc\Defuse\Crypto;
use ncc\Defuse\Crypto\Exception as Ex;
final class Core
{
const HEADER_VERSION_SIZE = 4;
@ -98,9 +99,14 @@ final class Core
*/
public static function secureRandom($octets)
{
if ($octets <= 0) {
throw new Ex\CryptoException(
'A zero or negative amount of random bytes was requested.'
);
}
self::ensureFunctionExists('random_bytes');
try {
return \random_bytes($octets);
return \random_bytes(max(1, $octets));
} catch (\Exception $ex) {
throw new Ex\EnvironmentIsBrokenException(
'Your system does not have a secure random number generator.'
@ -285,7 +291,7 @@ final class Core
{
static $exists = null;
if ($exists === null) {
$exists = \extension_loaded('mbstring') && \ini_get('mbstring.func_overload') !== false && (int)\ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING;
$exists = \extension_loaded('mbstring') && \function_exists('mb_strlen');
}
if ($exists) {
$length = \mb_strlen($str, '8bit');
@ -311,7 +317,7 @@ final class Core
{
static $exists = null;
if ($exists === null) {
$exists = \extension_loaded('mbstring') && \ini_get('mbstring.func_overload') !== false && (int)\ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING;
$exists = \extension_loaded('mbstring') && \function_exists('mb_substr');
}
// This is required to make mb_substr behavior identical to substr.
@ -381,7 +387,15 @@ final class Core
*
* @return string A $key_length-byte key derived from the password and salt.
*/
public static function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
public static function pbkdf2(
$algorithm,
#[\SensitiveParameter]
$password,
$salt,
$count,
$key_length,
$raw_output = false
)
{
// Type checks:
if (! \is_string($algorithm)) {

View file

@ -10,8 +10,11 @@ class Crypto
* Encrypts a string with a Key.
*
* @param string $plaintext
* @param Key $key
* @param bool $raw_binary
* @param Key $key
* @param bool $raw_binary
*
* @throws Ex\EnvironmentIsBrokenException
* @throws \TypeError
*
* @return string
*/
@ -45,11 +48,19 @@ class Crypto
*
* @param string $plaintext
* @param string $password
* @param bool $raw_binary
* @param bool $raw_binary
*
* @throws Ex\EnvironmentIsBrokenException
* @throws \TypeError
*
* @return string
*/
public static function encryptWithPassword($plaintext, $password, $raw_binary = false)
public static function encryptWithPassword(
$plaintext,
#[\SensitiveParameter]
$password,
$raw_binary = false
)
{
if (!\is_string($plaintext)) {
throw new \TypeError(
@ -124,7 +135,12 @@ class Crypto
*
* @return string
*/
public static function decryptWithPassword($ciphertext, $password, $raw_binary = false)
public static function decryptWithPassword(
$ciphertext,
#[\SensitiveParameter]
$password,
$raw_binary = false
)
{
if (!\is_string($ciphertext)) {
throw new \TypeError(
@ -160,7 +176,11 @@ class Crypto
*
* @return string
*/
public static function legacyDecrypt($ciphertext, $key)
public static function legacyDecrypt(
$ciphertext,
#[\SensitiveParameter]
$key
)
{
if (!\is_string($ciphertext)) {
throw new \TypeError(
@ -372,7 +392,13 @@ class Crypto
*
* @return string
*/
protected static function plainEncrypt($plaintext, $key, $iv)
protected static function plainEncrypt(
$plaintext,
#[\SensitiveParameter]
$key,
#[\SensitiveParameter]
$iv
)
{
Core::ensureConstantExists('OPENSSL_RAW_DATA');
Core::ensureFunctionExists('openssl_encrypt');
@ -402,7 +428,14 @@ class Crypto
*
* @return string
*/
protected static function plainDecrypt($ciphertext, $key, $iv, $cipherMethod)
protected static function plainDecrypt(
$ciphertext,
#[\SensitiveParameter]
$key,
#[\SensitiveParameter]
$iv,
$cipherMethod
)
{
Core::ensureConstantExists('OPENSSL_RAW_DATA');
Core::ensureFunctionExists('openssl_decrypt');
@ -431,7 +464,12 @@ class Crypto
*
* @return bool
*/
protected static function verifyHMAC($expected_hmac, $message, $key)
protected static function verifyHMAC(
$expected_hmac,
$message,
#[\SensitiveParameter]
$key
)
{
$message_hmac = \hash_hmac(Core::HASH_FUNCTION_NAME, $message, $key, true);
return Core::hashEquals($message_hmac, $expected_hmac);

View file

@ -4,7 +4,7 @@ namespace ncc\Defuse\Crypto;
/**
* Class DerivedKeys
* @package ncc\Defuse\Crypto
* @package Defuse\Crypto
*/
final class DerivedKeys
{

View file

@ -175,7 +175,11 @@ final class Encoding
*
* @return string
*/
public static function saveBytesToChecksummedAsciiSafeString($header, $bytes)
public static function saveBytesToChecksummedAsciiSafeString(
$header,
#[\SensitiveParameter]
$bytes
)
{
// Headers must be a constant length to prevent one type's header from
// being a prefix of another type's header, leading to ambiguity.
@ -207,7 +211,11 @@ final class Encoding
*
* @return string
*/
public static function loadBytesFromChecksummedAsciiSafeString($expected_header, $string)
public static function loadBytesFromChecksummedAsciiSafeString(
$expected_header,
#[\SensitiveParameter]
$string
)
{
// Headers must be a constant length to prevent one type's header from
// being a prefix of another type's header, leading to ambiguity.

View file

@ -38,7 +38,12 @@ final class File
* @throws Ex\EnvironmentIsBrokenException
* @throws Ex\IOException
*/
public static function encryptFileWithPassword($inputFilename, $outputFilename, $password)
public static function encryptFileWithPassword(
$inputFilename,
$outputFilename,
#[\SensitiveParameter]
$password
)
{
self::encryptFileInternal(
$inputFilename,
@ -81,7 +86,12 @@ final class File
* @throws Ex\IOException
* @throws Ex\WrongKeyOrModifiedCiphertextException
*/
public static function decryptFileWithPassword($inputFilename, $outputFilename, $password)
public static function decryptFileWithPassword(
$inputFilename,
$outputFilename,
#[\SensitiveParameter]
$password
)
{
self::decryptFileInternal(
$inputFilename,
@ -125,7 +135,12 @@ final class File
* @throws Ex\IOException
* @throws Ex\WrongKeyOrModifiedCiphertextException
*/
public static function encryptResourceWithPassword($inputHandle, $outputHandle, $password)
public static function encryptResourceWithPassword(
$inputHandle,
$outputHandle,
#[\SensitiveParameter]
$password
)
{
self::encryptResourceInternal(
$inputHandle,
@ -169,7 +184,12 @@ final class File
* @throws Ex\IOException
* @throws Ex\WrongKeyOrModifiedCiphertextException
*/
public static function decryptResourceWithPassword($inputHandle, $outputHandle, $password)
public static function decryptResourceWithPassword(
$inputHandle,
$outputHandle,
#[\SensitiveParameter]
$password
)
{
self::decryptResourceInternal(
$inputHandle,
@ -196,7 +216,9 @@ final class File
}
/* Open the input file. */
self::removePHPUnitErrorHandler();
$if = @\fopen($inputFilename, 'rb');
self::restorePHPUnitErrorHandler();
if ($if === false) {
throw new Ex\IOException(
'Cannot open input file for encrypting: ' .
@ -209,7 +231,9 @@ final class File
}
/* Open the output file. */
self::removePHPUnitErrorHandler();
$of = @\fopen($outputFilename, 'wb');
self::restorePHPUnitErrorHandler();
if ($of === false) {
\fclose($if);
throw new Ex\IOException(
@ -265,7 +289,9 @@ final class File
}
/* Open the input file. */
self::removePHPUnitErrorHandler();
$if = @\fopen($inputFilename, 'rb');
self::restorePHPUnitErrorHandler();
if ($if === false) {
throw new Ex\IOException(
'Cannot open input file for decrypting: ' .
@ -279,7 +305,9 @@ final class File
}
/* Open the output file. */
self::removePHPUnitErrorHandler();
$of = @\fopen($outputFilename, 'wb');
self::restorePHPUnitErrorHandler();
if ($of === false) {
\fclose($if);
throw new Ex\IOException(
@ -770,9 +798,38 @@ final class File
{
$error = error_get_last();
if ($error === null) {
return '[no PHP error]';
return '[no PHP error, or you have a custom error handler set]';
} else {
return $error['message'];
}
}
/**
* PHPUnit sets an error handler, which prevents getLastErrorMessage() from working,
* because error_get_last does not work when custom handlers are set.
*
* This is a workaround, which should be a no-op in production deployments, to make
* getLastErrorMessage() return the error messages that the PHPUnit tests expect.
*
* If, in a production deployment, a custom error handler is set, the exception
* handling will still work as usual, but the error messages will be confusing.
*
* @return void
*/
private static function removePHPUnitErrorHandler() {
if (defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__')) {
set_error_handler(null);
}
}
/**
* Undoes what removePHPUnitErrorHandler did.
*
* @return void
*/
private static function restorePHPUnitErrorHandler() {
if (defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__')) {
restore_error_handler();
}
}
}

View file

@ -41,7 +41,11 @@ final class Key
*
* @return Key
*/
public static function loadFromAsciiSafeString($saved_key_string, $do_not_trim = false)
public static function loadFromAsciiSafeString(
#[\SensitiveParameter]
$saved_key_string,
$do_not_trim = false
)
{
if (!$do_not_trim) {
$saved_key_string = Encoding::trimTrailingWhitespace($saved_key_string);
@ -82,7 +86,10 @@ final class Key
*
* @throws Ex\EnvironmentIsBrokenException
*/
private function __construct($bytes)
private function __construct(
#[\SensitiveParameter]
$bytes
)
{
Core::ensureTrue(
Core::ourStrlen($bytes) === self::KEY_BYTE_SIZE,

View file

@ -39,7 +39,10 @@ final class KeyOrPassword
*
* @return KeyOrPassword
*/
public static function createFromPassword($password)
public static function createFromPassword(
#[\SensitiveParameter]
$password
)
{
return new KeyOrPassword(self::SECRET_TYPE_PASSWORD, $password);
}
@ -133,7 +136,11 @@ final class KeyOrPassword
* @param int $secret_type
* @param mixed $secret (either a Key or a password string)
*/
private function __construct($secret_type, $secret)
private function __construct(
$secret_type,
#[\SensitiveParameter]
$secret
)
{
// The constructor is private, so these should never throw.
if ($secret_type === self::SECRET_TYPE_KEY) {

View file

@ -22,7 +22,10 @@ final class KeyProtectedByPassword
*
* @return KeyProtectedByPassword
*/
public static function createRandomPasswordProtectedKey($password)
public static function createRandomPasswordProtectedKey(
#[\SensitiveParameter]
$password
)
{
$inner_key = Key::createNewRandomKey();
/* The password is hashed as a form of poor-man's domain separation
@ -47,7 +50,10 @@ final class KeyProtectedByPassword
*
* @return KeyProtectedByPassword
*/
public static function loadFromAsciiSafeString($saved_key_string)
public static function loadFromAsciiSafeString(
#[\SensitiveParameter]
$saved_key_string
)
{
$encrypted_key = Encoding::loadBytesFromChecksummedAsciiSafeString(
self::PASSWORD_KEY_CURRENT_VERSION,
@ -82,7 +88,10 @@ final class KeyProtectedByPassword
* @param string $password
* @return Key
*/
public function unlockKey($password)
public function unlockKey(
#[\SensitiveParameter]
$password
)
{
try {
$inner_key_encoded = Crypto::decryptWithPassword(
@ -115,7 +124,12 @@ final class KeyProtectedByPassword
*
* @return KeyProtectedByPassword
*/
public function changePassword($current_password, $new_password)
public function changePassword(
#[\SensitiveParameter]
$current_password,
#[\SensitiveParameter]
$new_password
)
{
$inner_key = $this->unlockKey($current_password);
/* The password is hashed as a form of poor-man's domain separation

View file

@ -1,7 +1,7 @@
php-encryption
===============
[![Build Status](https://travis-ci.org/defuse/php-encryption.svg?branch=master)](https://travis-ci.org/defuse/php-encryption)
![Build Status](https://app.travis-ci.com/defuse/php-encryption.svg?branch=master)
[![codecov](https://codecov.io/gh/defuse/php-encryption/branch/master/graph/badge.svg)](https://codecov.io/gh/defuse/php-encryption)
[![Latest Stable Version](https://poser.pugx.org/defuse/php-encryption/v/stable)](https://packagist.org/packages/defuse/php-encryption)
[![License](https://poser.pugx.org/defuse/php-encryption/license)](https://packagist.org/packages/defuse/php-encryption)
@ -15,10 +15,10 @@ This is a library for encrypting data with a key or password in PHP. **It
requires PHP 5.6 or newer and OpenSSL 1.0.1 or newer.** We recommend using a
version of PHP that [still has security
support](https://www.php.net/supported-versions.php), which at the time of
writing means PHP 7.3 or later. Using this library with an unsupported
writing means PHP 8.0 or later. Using this library with an unsupported
version of PHP could lead to security vulnerabilities.
The current version of `php-encryption` is v2.3.1. This library is expected to
The current version of `php-encryption` is v2.4.0. This library is expected to
remain stable and supported by its authors with security and bugfixes until at
least January 1st, 2024.
@ -99,23 +99,26 @@ a formal audit, please [contact Taylor Hornby](https://defuse.ca/contact.htm).
Public Keys
------------
The GnuPG public key used to sign current and older releases is available in
[dist/signingkey.asc](https://github.com/defuse/php-encryption/raw/master/dist/signingkey.asc). Its fingerprint is:
```
2FA6 1D8D 99B9 2658 6BAC 3D53 385E E055 A129 1538
```
You can verify it against Taylor Hornby's [contact
page](https://defuse.ca/contact.htm) and
[twitter](https://twitter.com/DefuseSec/status/723741424253059074).
Due to the old key expiring, new releases will be signed with a new public key
available in [dist/signingkey-new.asc](https://github.com/defuse/php-encryption/raw/master/dist/signingkey-new.asc). Its fingerprint is:
The GnuPG public key used to sign the current and new releases is available in
[dist/signingkey-new.asc](https://github.com/defuse/php-encryption/raw/master/dist/signingkey-new.asc). Its fingerprint is:
```
6DD6 E677 0281 5846 FC85 25A3 DD2E 507F 7BDB 1669
```
You can verify it against Taylor Hornby's [contact
page](https://defuse.ca/contact.htm) and
[twitter](https://twitter.com/DefuseSec/status/1670840796743081984).
Older releases were signed with a (now-expired) available in
[dist/signingkey-old.asc](https://github.com/defuse/php-encryption/raw/master/dist/signingkey-old.asc). The old key's fingerprint is:
```
2FA6 1D8D 99B9 2658 6BAC 3D53 385E E055 A129 1538
```
The old key's fingerprint can be verified against Taylor Hornby's [contact page](https://defuse.ca/contact.htm) and
[twitter](https://twitter.com/DefuseSec/status/723741424253059074).
A signature of this new key by the old key is available in
[dist/signingkey-new.asc.sig](https://github.com/defuse/php-encryption/raw/master/dist/signingkey-new.asc.sig).

View file

@ -1,4 +1,24 @@
<?php
/*
* Copyright (c) Nosial 2022-2023, all rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace ncc\Defuse\Crypto;

View file

@ -1 +1 @@
2.3.1
2.4.0