summaryrefslogtreecommitdiff
path: root/vendor/aws/aws-sdk-php/src/Crypto/Polyfill/AesGcm.php
diff options
context:
space:
mode:
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.php228
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);
+ }
+}