diff options
Diffstat (limited to 'vendor/aws/aws-sdk-php/src/Crypto/Polyfill/AesGcm.php')
-rw-r--r-- | vendor/aws/aws-sdk-php/src/Crypto/Polyfill/AesGcm.php | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/vendor/aws/aws-sdk-php/src/Crypto/Polyfill/AesGcm.php b/vendor/aws/aws-sdk-php/src/Crypto/Polyfill/AesGcm.php new file mode 100644 index 0000000..baf8ae2 --- /dev/null +++ b/vendor/aws/aws-sdk-php/src/Crypto/Polyfill/AesGcm.php @@ -0,0 +1,228 @@ +<?php +namespace Aws\Crypto\Polyfill; + +use Aws\Exception\CryptoPolyfillException; +use InvalidArgumentException; +use RangeException; + +/** + * Class AesGcm + * + * This provides a polyfill for AES-GCM encryption/decryption, with caveats: + * + * 1. Only 96-bit nonces are supported. + * 2. Only 128-bit authentication tags are supported. (i.e. non-truncated) + * + * Supports AES key sizes of 128-bit, 192-bit, and 256-bit. + * + * @package Aws\Crypto\Polyfill + */ +class AesGcm +{ + use NeedsTrait; + + /** @var Key $aesKey */ + private $aesKey; + + /** @var int $keySize */ + private $keySize; + + /** @var int $blockSize */ + protected $blockSize = 8192; + + /** + * AesGcm constructor. + * + * @param Key $aesKey + * @param int $keySize + * @param int $blockSize + * + * @throws CryptoPolyfillException + * @throws InvalidArgumentException + * @throws RangeException + */ + public function __construct(Key $aesKey, $keySize = 256, $blockSize = 8192) + { + /* Preconditions: */ + self::needs( + \in_array($keySize, [128, 192, 256], true), + "Key size must be 128, 192, or 256 bits; {$keySize} given", + InvalidArgumentException::class + ); + self::needs( + \is_int($blockSize) && $blockSize > 0 && $blockSize <= PHP_INT_MAX, + 'Block size must be a positive integer.', + RangeException::class + ); + self::needs( + $aesKey->length() << 3 === $keySize, + 'Incorrect key size; expected ' . $keySize . ' bits, got ' . ($aesKey->length() << 3) . ' bits.' + ); + $this->aesKey = $aesKey; + $this->keySize = $keySize; + } + + /** + * Encryption interface for AES-GCM + * + * @param string $plaintext Message to be encrypted + * @param string $nonce Number to be used ONCE + * @param Key $key AES Key + * @param string $aad Additional authenticated data + * @param string &$tag Reference to variable to hold tag + * @param int $keySize Key size (bits) + * @param int $blockSize Block size (bytes) -- How much memory to buffer + * @return string + * @throws InvalidArgumentException + */ + public static function encrypt( + $plaintext, + $nonce, + Key $key, + $aad, + &$tag, + $keySize = 256, + $blockSize = 8192 + ) { + self::needs( + self::strlen($nonce) === 12, + 'Nonce must be exactly 12 bytes', + InvalidArgumentException::class + ); + + $encryptor = new AesGcm($key, $keySize, $blockSize); + list($aadLength, $gmac) = $encryptor->gmacInit($nonce, $aad); + + $ciphertext = \openssl_encrypt( + $plaintext, + "aes-{$encryptor->keySize}-ctr", + $key->get(), + OPENSSL_NO_PADDING | OPENSSL_RAW_DATA, + $nonce . "\x00\x00\x00\x02" + ); + + /* Calculate auth tag in a streaming fashion to minimize memory usage: */ + $ciphertextLength = self::strlen($ciphertext); + for ($i = 0; $i < $ciphertextLength; $i += $encryptor->blockSize) { + $cBlock = new ByteArray(self::substr($ciphertext, $i, $encryptor->blockSize)); + $gmac->update($cBlock); + } + $tag = $gmac->finish($aadLength, $ciphertextLength)->toString(); + return $ciphertext; + } + + /** + * Decryption interface for AES-GCM + * + * @param string $ciphertext Ciphertext to decrypt + * @param string $nonce Number to be used ONCE + * @param Key $key AES key + * @param string $aad Additional authenticated data + * @param string $tag Authentication tag + * @param int $keySize Key size (bits) + * @param int $blockSize Block size (bytes) -- How much memory to buffer + * @return string Plaintext + * + * @throws CryptoPolyfillException + * @throws InvalidArgumentException + */ + public static function decrypt( + $ciphertext, + $nonce, + Key $key, + $aad, + &$tag, + $keySize = 256, + $blockSize = 8192 + ) { + /* Precondition: */ + self::needs( + self::strlen($nonce) === 12, + 'Nonce must be exactly 12 bytes', + InvalidArgumentException::class + ); + + $encryptor = new AesGcm($key, $keySize, $blockSize); + list($aadLength, $gmac) = $encryptor->gmacInit($nonce, $aad); + + /* Calculate auth tag in a streaming fashion to minimize memory usage: */ + $ciphertextLength = self::strlen($ciphertext); + for ($i = 0; $i < $ciphertextLength; $i += $encryptor->blockSize) { + $cBlock = new ByteArray(self::substr($ciphertext, $i, $encryptor->blockSize)); + $gmac->update($cBlock); + } + + /* Validate auth tag in constant-time: */ + $calc = $gmac->finish($aadLength, $ciphertextLength); + $expected = new ByteArray($tag); + self::needs($calc->equals($expected), 'Invalid authentication tag'); + + /* Return plaintext if auth tag check succeeded: */ + return \openssl_decrypt( + $ciphertext, + "aes-{$encryptor->keySize}-ctr", + $key->get(), + OPENSSL_NO_PADDING | OPENSSL_RAW_DATA, + $nonce . "\x00\x00\x00\x02" + ); + } + + /** + * Initialize a Gmac object with the nonce and this object's key. + * + * @param string $nonce Must be exactly 12 bytes long. + * @param string|null $aad + * @return array + */ + protected function gmacInit($nonce, $aad = null) + { + $gmac = new Gmac( + $this->aesKey, + $nonce . "\x00\x00\x00\x01", + $this->keySize + ); + $aadBlock = new ByteArray($aad); + $aadLength = $aadBlock->count(); + $gmac->update($aadBlock); + $gmac->flush(); + return [$aadLength, $gmac]; + } + + /** + * Calculate the length of a string. + * + * Uses the appropriate PHP function without being brittle to + * mbstring.func_overload. + * + * @param string $string + * @return int + */ + protected static function strlen($string) + { + if (\is_callable('\\mb_strlen')) { + return (int) \mb_strlen($string, '8bit'); + } + return (int) \strlen($string); + } + + /** + * Return a substring of the provided string. + * + * Uses the appropriate PHP function without being brittle to + * mbstring.func_overload. + * + * @param string $string + * @param int $offset + * @param int|null $length + * @return string + */ + protected static function substr($string, $offset = 0, $length = null) + { + if (\is_callable('\\mb_substr')) { + return \mb_substr($string, $offset, $length, '8bit'); + } elseif (!\is_null($length)) { + return \substr($string, $offset, $length); + } + return \substr($string, $offset); + } +} |