mirror of
https://github.com/SociallyDev/Spaces-API.git
synced 2025-08-20 13:23:47 -07:00
spaces.php
This commit is contained in:
parent
7755490b81
commit
eefa32741e
845 changed files with 50409 additions and 0 deletions
138
aws/Aws/Crypto/AbstractCryptoClient.php
Normal file
138
aws/Aws/Crypto/AbstractCryptoClient.php
Normal file
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
namespace Aws\Crypto;
|
||||
|
||||
use Aws\Crypto\Cipher\CipherMethod;
|
||||
use Aws\Crypto\Cipher\Cbc;
|
||||
use GuzzleHttp\Psr7\Stream;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
abstract class AbstractCryptoClient
|
||||
{
|
||||
private static $supportedCiphers = ['cbc', 'gcm'];
|
||||
|
||||
/**
|
||||
* Returns if the passed cipher name is supported for encryption by the SDK.
|
||||
*
|
||||
* @param string $cipherName The name of a cipher to verify is registered.
|
||||
*
|
||||
* @return bool If the cipher passed is in our supported list.
|
||||
*/
|
||||
public static function isSupportedCipher($cipherName)
|
||||
{
|
||||
return in_array($cipherName, self::$supportedCiphers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an identifier recognizable by `openssl_*` functions, such as
|
||||
* `aes-256-cbc` or `aes-128-ctr`.
|
||||
*
|
||||
* @param string $cipherName Name of the cipher being used for encrypting
|
||||
* or decrypting.
|
||||
* @param int $keySize Size of the encryption key, in bits, that will be
|
||||
* used.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getCipherOpenSslName($cipherName, $keySize)
|
||||
{
|
||||
return "aes-{$keySize}-{$cipherName}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a CipherMethod for the given name, initialized with the other
|
||||
* data passed for use in encrypting or decrypting.
|
||||
*
|
||||
* @param string $cipherName Name of the cipher to generate for encrypting.
|
||||
* @param string $iv Base Initialization Vector for the cipher.
|
||||
* @param int $keySize Size of the encryption key, in bits, that will be
|
||||
* used.
|
||||
*
|
||||
* @return CipherMethod
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function buildCipherMethod($cipherName, $iv, $keySize)
|
||||
{
|
||||
switch ($cipherName) {
|
||||
case 'cbc':
|
||||
return new Cbc(
|
||||
$iv,
|
||||
$keySize
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a reverse lookup to get the openssl_* cipher name from the
|
||||
* AESName passed in from the MetadataEnvelope.
|
||||
*
|
||||
* @param $aesName
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function getCipherFromAesName($aesName)
|
||||
{
|
||||
switch ($aesName) {
|
||||
case 'AES/GCM/NoPadding':
|
||||
return 'gcm';
|
||||
case 'AES/CBC/PKCS5Padding':
|
||||
return 'cbc';
|
||||
default:
|
||||
throw new \RuntimeException('Unrecognized or unsupported'
|
||||
. ' AESName for reverse lookup.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dependency to provide an interface for building an encryption stream for
|
||||
* data given cipher details, metadata, and materials to do so.
|
||||
*
|
||||
* @param Stream $plaintext Plain-text data to be encrypted using the
|
||||
* materials, algorithm, and data provided.
|
||||
* @param array $cipherOptions Options for use in determining the cipher to
|
||||
* be used for encrypting data.
|
||||
* @param MaterialsProvider $provider A provider to supply and encrypt
|
||||
* materials used in encryption.
|
||||
* @param MetadataEnvelope $envelope A storage envelope for encryption
|
||||
* metadata to be added to.
|
||||
*
|
||||
* @return AesStreamInterface
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract public function encrypt(
|
||||
Stream $plaintext,
|
||||
array $cipherOptions,
|
||||
MaterialsProvider $provider,
|
||||
MetadataEnvelope $envelope
|
||||
);
|
||||
|
||||
/**
|
||||
* Dependency to provide an interface for building a decryption stream for
|
||||
* cipher text given metadata and materials to do so.
|
||||
*
|
||||
* @param string $cipherText Plain-text data to be decrypted using the
|
||||
* materials, algorithm, and data provided.
|
||||
* @param MaterialsProvider $provider A provider to supply and encrypt
|
||||
* materials used in encryption.
|
||||
* @param MetadataEnvelope $envelope A storage envelope for encryption
|
||||
* metadata to be read from.
|
||||
* @param array $cipherOptions Additional verification options.
|
||||
*
|
||||
* @return AesStreamInterface
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract public function decrypt(
|
||||
$cipherText,
|
||||
MaterialsProvider $provider,
|
||||
MetadataEnvelope $envelope,
|
||||
array $cipherOptions = []
|
||||
);
|
||||
}
|
144
aws/Aws/Crypto/AesDecryptingStream.php
Normal file
144
aws/Aws/Crypto/AesDecryptingStream.php
Normal file
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
namespace Aws\Crypto;
|
||||
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use \LogicException;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Aws\Crypto\Cipher\CipherMethod;
|
||||
|
||||
/**
|
||||
* @internal Represents a stream of data to be decrypted with passed cipher.
|
||||
*/
|
||||
class AesDecryptingStream implements AesStreamInterface
|
||||
{
|
||||
const BLOCK_SIZE = 16; // 128 bits
|
||||
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $buffer = '';
|
||||
|
||||
/**
|
||||
* @var CipherMethod
|
||||
*/
|
||||
private $cipherMethod;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $key;
|
||||
|
||||
/**
|
||||
* @var StreamInterface
|
||||
*/
|
||||
private $stream;
|
||||
|
||||
/**
|
||||
* @param StreamInterface $cipherText
|
||||
* @param string $key
|
||||
* @param CipherMethod $cipherMethod
|
||||
*/
|
||||
public function __construct(
|
||||
StreamInterface $cipherText,
|
||||
$key,
|
||||
CipherMethod $cipherMethod
|
||||
) {
|
||||
$this->stream = $cipherText;
|
||||
$this->key = $key;
|
||||
$this->cipherMethod = clone $cipherMethod;
|
||||
}
|
||||
|
||||
public function getOpenSslName()
|
||||
{
|
||||
return $this->cipherMethod->getOpenSslName();
|
||||
}
|
||||
|
||||
public function getAesName()
|
||||
{
|
||||
return $this->cipherMethod->getAesName();
|
||||
}
|
||||
|
||||
public function getCurrentIv()
|
||||
{
|
||||
return $this->cipherMethod->getCurrentIv();
|
||||
}
|
||||
|
||||
public function getSize()
|
||||
{
|
||||
$plainTextSize = $this->stream->getSize();
|
||||
|
||||
if ($this->cipherMethod->requiresPadding()) {
|
||||
// PKCS7 padding requires that between 1 and self::BLOCK_SIZE be
|
||||
// added to the plaintext to make it an even number of blocks. The
|
||||
// plaintext is between strlen($cipherText) - self::BLOCK_SIZE and
|
||||
// strlen($cipherText) - 1
|
||||
return null;
|
||||
}
|
||||
|
||||
return $plainTextSize;
|
||||
}
|
||||
|
||||
public function isWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function read($length)
|
||||
{
|
||||
if ($length > strlen($this->buffer)) {
|
||||
$this->buffer .= $this->decryptBlock(
|
||||
self::BLOCK_SIZE * ceil(($length - strlen($this->buffer)) / self::BLOCK_SIZE)
|
||||
);
|
||||
}
|
||||
|
||||
$data = substr($this->buffer, 0, $length);
|
||||
$this->buffer = substr($this->buffer, $length);
|
||||
|
||||
return $data ? $data : '';
|
||||
}
|
||||
|
||||
public function seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
if ($offset === 0 && $whence === SEEK_SET) {
|
||||
$this->buffer = '';
|
||||
$this->cipherMethod->seek(0, SEEK_SET);
|
||||
$this->stream->seek(0, SEEK_SET);
|
||||
} else {
|
||||
throw new LogicException('AES encryption streams only support being'
|
||||
. ' rewound, not arbitrary seeking.');
|
||||
}
|
||||
}
|
||||
|
||||
private function decryptBlock($length)
|
||||
{
|
||||
if ($this->stream->eof()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$cipherText = '';
|
||||
do {
|
||||
$cipherText .= $this->stream->read($length - strlen($cipherText));
|
||||
} while (strlen($cipherText) < $length && !$this->stream->eof());
|
||||
|
||||
$options = OPENSSL_RAW_DATA;
|
||||
if (!$this->stream->eof()
|
||||
&& $this->stream->getSize() !== $this->stream->tell()
|
||||
) {
|
||||
$options |= OPENSSL_ZERO_PADDING;
|
||||
}
|
||||
|
||||
$plaintext = openssl_decrypt(
|
||||
$cipherText,
|
||||
$this->cipherMethod->getOpenSslName(),
|
||||
$this->key,
|
||||
$options,
|
||||
$this->cipherMethod->getCurrentIv()
|
||||
);
|
||||
|
||||
$this->cipherMethod->update($cipherText);
|
||||
|
||||
return $plaintext;
|
||||
}
|
||||
}
|
150
aws/Aws/Crypto/AesEncryptingStream.php
Normal file
150
aws/Aws/Crypto/AesEncryptingStream.php
Normal file
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
namespace Aws\Crypto;
|
||||
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use \LogicException;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Aws\Crypto\Cipher\CipherMethod;
|
||||
|
||||
/**
|
||||
* @internal Represents a stream of data to be encrypted with a passed cipher.
|
||||
*/
|
||||
class AesEncryptingStream implements AesStreamInterface
|
||||
{
|
||||
const BLOCK_SIZE = 16; // 128 bits
|
||||
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $buffer = '';
|
||||
|
||||
/**
|
||||
* @var CipherMethod
|
||||
*/
|
||||
private $cipherMethod;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $key;
|
||||
|
||||
/**
|
||||
* @var StreamInterface
|
||||
*/
|
||||
private $stream;
|
||||
|
||||
/**
|
||||
* @param StreamInterface $plainText
|
||||
* @param string $key
|
||||
* @param CipherMethod $cipherMethod
|
||||
*/
|
||||
public function __construct(
|
||||
StreamInterface $plainText,
|
||||
$key,
|
||||
CipherMethod $cipherMethod
|
||||
) {
|
||||
$this->stream = $plainText;
|
||||
$this->key = $key;
|
||||
$this->cipherMethod = clone $cipherMethod;
|
||||
}
|
||||
|
||||
public function getOpenSslName()
|
||||
{
|
||||
return $this->cipherMethod->getOpenSslName();
|
||||
}
|
||||
|
||||
public function getAesName()
|
||||
{
|
||||
return $this->cipherMethod->getAesName();
|
||||
}
|
||||
|
||||
public function getCurrentIv()
|
||||
{
|
||||
return $this->cipherMethod->getCurrentIv();
|
||||
}
|
||||
|
||||
public function getSize()
|
||||
{
|
||||
$plainTextSize = $this->stream->getSize();
|
||||
|
||||
if ($this->cipherMethod->requiresPadding() && $plainTextSize !== null) {
|
||||
// PKCS7 padding requires that between 1 and self::BLOCK_SIZE be
|
||||
// added to the plaintext to make it an even number of blocks.
|
||||
$padding = self::BLOCK_SIZE - $plainTextSize % self::BLOCK_SIZE;
|
||||
return $plainTextSize + $padding;
|
||||
}
|
||||
|
||||
return $plainTextSize;
|
||||
}
|
||||
|
||||
public function isWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function read($length)
|
||||
{
|
||||
if ($length > strlen($this->buffer)) {
|
||||
$this->buffer .= $this->encryptBlock(
|
||||
self::BLOCK_SIZE * ceil(($length - strlen($this->buffer)) / self::BLOCK_SIZE)
|
||||
);
|
||||
}
|
||||
|
||||
$data = substr($this->buffer, 0, $length);
|
||||
$this->buffer = substr($this->buffer, $length);
|
||||
|
||||
return $data ? $data : '';
|
||||
}
|
||||
|
||||
public function seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
if ($whence === SEEK_CUR) {
|
||||
$offset = $this->tell() + $offset;
|
||||
$whence = SEEK_SET;
|
||||
}
|
||||
|
||||
if ($whence === SEEK_SET) {
|
||||
$this->buffer = '';
|
||||
$wholeBlockOffset
|
||||
= (int) ($offset / self::BLOCK_SIZE) * self::BLOCK_SIZE;
|
||||
$this->stream->seek($wholeBlockOffset);
|
||||
$this->cipherMethod->seek($wholeBlockOffset);
|
||||
$this->read($offset - $wholeBlockOffset);
|
||||
} else {
|
||||
throw new LogicException('Unrecognized whence.');
|
||||
}
|
||||
}
|
||||
|
||||
private function encryptBlock($length)
|
||||
{
|
||||
if ($this->stream->eof()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$plainText = '';
|
||||
do {
|
||||
$plainText .= $this->stream->read($length - strlen($plainText));
|
||||
} while (strlen($plainText) < $length && !$this->stream->eof());
|
||||
|
||||
$options = OPENSSL_RAW_DATA;
|
||||
if (!$this->stream->eof()
|
||||
|| $this->stream->getSize() !== $this->stream->tell()
|
||||
) {
|
||||
$options |= OPENSSL_ZERO_PADDING;
|
||||
}
|
||||
|
||||
$cipherText = openssl_encrypt(
|
||||
$plainText,
|
||||
$this->cipherMethod->getOpenSslName(),
|
||||
$this->key,
|
||||
$options,
|
||||
$this->cipherMethod->getCurrentIv()
|
||||
);
|
||||
|
||||
$this->cipherMethod->update($cipherText);
|
||||
|
||||
return $cipherText;
|
||||
}
|
||||
}
|
96
aws/Aws/Crypto/AesGcmDecryptingStream.php
Normal file
96
aws/Aws/Crypto/AesGcmDecryptingStream.php
Normal file
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
namespace Aws\Crypto;
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use GuzzleHttp\Psr7\LimitStream;
|
||||
use \RuntimeException;
|
||||
|
||||
/**
|
||||
* @internal Represents a stream of data to be gcm decrypted.
|
||||
*/
|
||||
class AesGcmDecryptingStream implements AesStreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
private $aad;
|
||||
|
||||
private $initializationVector;
|
||||
|
||||
private $key;
|
||||
|
||||
private $keySize;
|
||||
|
||||
private $cipherText;
|
||||
|
||||
private $tag;
|
||||
|
||||
private $tagLength;
|
||||
|
||||
/**
|
||||
* @param StreamInterface $cipherText
|
||||
* @param string $key
|
||||
* @param string $initializationVector
|
||||
* @param string $tag
|
||||
* @param string $aad
|
||||
* @param int $tagLength
|
||||
* @param int $keySize
|
||||
*/
|
||||
public function __construct(
|
||||
StreamInterface $cipherText,
|
||||
$key,
|
||||
$initializationVector,
|
||||
$tag,
|
||||
$aad = '',
|
||||
$tagLength = 128,
|
||||
$keySize = 256
|
||||
) {
|
||||
if (version_compare(PHP_VERSION, '7.1', '<')) {
|
||||
throw new RuntimeException(
|
||||
'AES-GCM decryption is only supported in PHP 7.1 or greater'
|
||||
);
|
||||
}
|
||||
|
||||
$this->cipherText = $cipherText;
|
||||
$this->key = $key;
|
||||
$this->initializationVector = $initializationVector;
|
||||
$this->tag = $tag;
|
||||
$this->aad = $aad;
|
||||
$this->tagLength = $tagLength;
|
||||
$this->keySize = $keySize;
|
||||
}
|
||||
|
||||
public function getOpenSslName()
|
||||
{
|
||||
return "aes-{$this->keySize}-gcm";
|
||||
}
|
||||
|
||||
public function getAesName()
|
||||
{
|
||||
return 'AES/GCM/NoPadding';
|
||||
}
|
||||
|
||||
public function getCurrentIv()
|
||||
{
|
||||
return $this->initializationVector;
|
||||
}
|
||||
|
||||
public function createStream()
|
||||
{
|
||||
return Psr7\stream_for(openssl_decrypt(
|
||||
(string) $this->cipherText,
|
||||
$this->getOpenSslName(),
|
||||
$this->key,
|
||||
OPENSSL_RAW_DATA,
|
||||
$this->initializationVector,
|
||||
$this->tag,
|
||||
$this->aad
|
||||
));
|
||||
}
|
||||
|
||||
public function isWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
101
aws/Aws/Crypto/AesGcmEncryptingStream.php
Normal file
101
aws/Aws/Crypto/AesGcmEncryptingStream.php
Normal file
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
namespace Aws\Crypto;
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use \RuntimeException;
|
||||
|
||||
/**
|
||||
* @internal Represents a stream of data to be gcm encrypted.
|
||||
*/
|
||||
class AesGcmEncryptingStream implements AesStreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
private $aad;
|
||||
|
||||
private $initializationVector;
|
||||
|
||||
private $key;
|
||||
|
||||
private $keySize;
|
||||
|
||||
private $plaintext;
|
||||
|
||||
private $tag = '';
|
||||
|
||||
private $tagLength;
|
||||
|
||||
/**
|
||||
* @param StreamInterface $plaintext
|
||||
* @param string $key
|
||||
* @param string $initializationVector
|
||||
* @param string $aad
|
||||
* @param int $tagLength
|
||||
* @param int $keySize
|
||||
*/
|
||||
public function __construct(
|
||||
StreamInterface $plaintext,
|
||||
$key,
|
||||
$initializationVector,
|
||||
$aad = '',
|
||||
$tagLength = 16,
|
||||
$keySize = 256
|
||||
) {
|
||||
if (version_compare(PHP_VERSION, '7.1', '<')) {
|
||||
throw new RuntimeException(
|
||||
'AES-GCM decryption is only supported in PHP 7.1 or greater'
|
||||
);
|
||||
}
|
||||
|
||||
$this->plaintext = $plaintext;
|
||||
$this->key = $key;
|
||||
$this->initializationVector = $initializationVector;
|
||||
$this->aad = $aad;
|
||||
$this->tagLength = $tagLength;
|
||||
$this->keySize = $keySize;
|
||||
}
|
||||
|
||||
public function getOpenSslName()
|
||||
{
|
||||
return "aes-{$this->keySize}-gcm";
|
||||
}
|
||||
|
||||
public function getAesName()
|
||||
{
|
||||
return 'AES/GCM/NoPadding';
|
||||
}
|
||||
|
||||
public function getCurrentIv()
|
||||
{
|
||||
return $this->initializationVector;
|
||||
}
|
||||
|
||||
public function createStream()
|
||||
{
|
||||
return Psr7\stream_for(openssl_encrypt(
|
||||
(string) $this->plaintext,
|
||||
$this->getOpenSslName(),
|
||||
$this->key,
|
||||
OPENSSL_RAW_DATA,
|
||||
$this->initializationVector,
|
||||
$this->tag,
|
||||
$this->aad,
|
||||
$this->tagLength
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTag()
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
|
||||
public function isWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
30
aws/Aws/Crypto/AesStreamInterface.php
Normal file
30
aws/Aws/Crypto/AesStreamInterface.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
namespace Aws\Crypto;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
interface AesStreamInterface extends StreamInterface
|
||||
{
|
||||
/**
|
||||
* Returns an identifier recognizable by `openssl_*` functions, such as
|
||||
* `aes-256-cbc` or `aes-128-ctr`.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOpenSslName();
|
||||
|
||||
/**
|
||||
* Returns an AES recognizable name, such as 'AES/GCM/NoPadding'.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAesName();
|
||||
|
||||
/**
|
||||
* Returns the IV that should be used to initialize the next block in
|
||||
* encrypt or decrypt.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCurrentIv();
|
||||
}
|
82
aws/Aws/Crypto/Cipher/Cbc.php
Normal file
82
aws/Aws/Crypto/Cipher/Cbc.php
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
namespace Aws\Crypto\Cipher;
|
||||
|
||||
use \InvalidArgumentException;
|
||||
use \LogicException;
|
||||
|
||||
/**
|
||||
* An implementation of the CBC cipher for use with an AesEncryptingStream or
|
||||
* AesDecrypting stream.
|
||||
*/
|
||||
class Cbc implements CipherMethod
|
||||
{
|
||||
const BLOCK_SIZE = 16;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $baseIv;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $iv;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $keySize;
|
||||
|
||||
/**
|
||||
* @param string $iv Base Initialization Vector for the cipher.
|
||||
* @param int $keySize Size of the encryption key, in bits, that will be
|
||||
* used.
|
||||
*
|
||||
* @throws InvalidArgumentException Thrown if the passed iv does not match
|
||||
* the iv length required by the cipher.
|
||||
*/
|
||||
public function __construct($iv, $keySize = 256)
|
||||
{
|
||||
$this->baseIv = $this->iv = $iv;
|
||||
$this->keySize = $keySize;
|
||||
|
||||
if (strlen($iv) !== openssl_cipher_iv_length($this->getOpenSslName())) {
|
||||
throw new InvalidArgumentException('Invalid initialization vector');
|
||||
}
|
||||
}
|
||||
|
||||
public function getOpenSslName()
|
||||
{
|
||||
return "aes-{$this->keySize}-cbc";
|
||||
}
|
||||
|
||||
public function getAesName()
|
||||
{
|
||||
return 'AES/CBC/PKCS5Padding';
|
||||
}
|
||||
|
||||
public function getCurrentIv()
|
||||
{
|
||||
return $this->iv;
|
||||
}
|
||||
|
||||
public function requiresPadding()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
if ($offset === 0 && $whence === SEEK_SET) {
|
||||
$this->iv = $this->baseIv;
|
||||
} else {
|
||||
throw new LogicException('CBC initialization only support being'
|
||||
. ' rewound, not arbitrary seeking.');
|
||||
}
|
||||
}
|
||||
|
||||
public function update($cipherTextBlock)
|
||||
{
|
||||
$this->iv = substr($cipherTextBlock, self::BLOCK_SIZE * -1);
|
||||
}
|
||||
}
|
59
aws/Aws/Crypto/Cipher/CipherMethod.php
Normal file
59
aws/Aws/Crypto/Cipher/CipherMethod.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
namespace Aws\Crypto\Cipher;
|
||||
|
||||
interface CipherMethod
|
||||
{
|
||||
/**
|
||||
* Returns an identifier recognizable by `openssl_*` functions, such as
|
||||
* `aes-256-cbc` or `aes-128-ctr`.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOpenSslName();
|
||||
|
||||
/**
|
||||
* Returns an AES recognizable name, such as 'AES/GCM/NoPadding'.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAesName();
|
||||
|
||||
/**
|
||||
* Returns the IV that should be used to initialize the next block in
|
||||
* encrypt or decrypt.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCurrentIv();
|
||||
|
||||
/**
|
||||
* Indicates whether the cipher method used with this IV requires padding
|
||||
* the final block to make sure the plaintext is evenly divisible by the
|
||||
* block size.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function requiresPadding();
|
||||
|
||||
/**
|
||||
* Adjust the return of this::getCurrentIv to reflect a seek performed on
|
||||
* the encryption stream using this IV object.
|
||||
*
|
||||
* @param int $offset
|
||||
* @param int $whence
|
||||
*
|
||||
* @throws LogicException Thrown if the requested seek is not supported by
|
||||
* this IV implementation. For example, a CBC IV
|
||||
* only supports a full rewind ($offset === 0 &&
|
||||
* $whence === SEEK_SET)
|
||||
*/
|
||||
public function seek($offset, $whence = SEEK_SET);
|
||||
|
||||
/**
|
||||
* Take account of the last cipher text block to adjust the return of
|
||||
* this::getCurrentIv
|
||||
*
|
||||
* @param string $cipherTextBlock
|
||||
*/
|
||||
public function update($cipherTextBlock);
|
||||
}
|
179
aws/Aws/Crypto/DecryptionTrait.php
Normal file
179
aws/Aws/Crypto/DecryptionTrait.php
Normal file
|
@ -0,0 +1,179 @@
|
|||
<?php
|
||||
namespace Aws\Crypto;
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\LimitStream;
|
||||
|
||||
trait DecryptionTrait
|
||||
{
|
||||
/**
|
||||
* Dependency to reverse lookup the openssl_* cipher name from the AESName
|
||||
* in the MetadataEnvelope.
|
||||
*
|
||||
* @param $aesName
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract protected function getCipherFromAesName($aesName);
|
||||
|
||||
/**
|
||||
* Dependency to generate a CipherMethod from a set of inputs for loading
|
||||
* in to an AesDecryptingStream.
|
||||
*
|
||||
* @param string $cipherName Name of the cipher to generate for decrypting.
|
||||
* @param string $iv Base Initialization Vector for the cipher.
|
||||
* @param int $keySize Size of the encryption key, in bits, that will be
|
||||
* used.
|
||||
*
|
||||
* @return Cipher\CipherMethod
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract protected function buildCipherMethod($cipherName, $iv, $keySize);
|
||||
|
||||
/**
|
||||
* Builds an AesStreamInterface using cipher options loaded from the
|
||||
* MetadataEnvelope and MaterialsProvider.
|
||||
*
|
||||
* @param string $cipherText Plain-text data to be encrypted using the
|
||||
* materials, algorithm, and data provided.
|
||||
* @param MaterialsProvider $provider A provider to supply and encrypt
|
||||
* materials used in encryption.
|
||||
* @param MetadataEnvelope $envelope A storage envelope for encryption
|
||||
* metadata to be read from.
|
||||
* @param array $cipherOptions Additional verification options.
|
||||
*
|
||||
* @return AesStreamInterface
|
||||
*
|
||||
* @throws \InvalidArgumentException Thrown when a value in $cipherOptions
|
||||
* is not valid.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function decrypt(
|
||||
$cipherText,
|
||||
MaterialsProvider $provider,
|
||||
MetadataEnvelope $envelope,
|
||||
array $cipherOptions = []
|
||||
) {
|
||||
$cipherOptions['Iv'] = base64_decode(
|
||||
$envelope[MetadataEnvelope::IV_HEADER]
|
||||
);
|
||||
|
||||
$cipherOptions['TagLength'] =
|
||||
$envelope[MetadataEnvelope::CRYPTO_TAG_LENGTH_HEADER] / 8;
|
||||
|
||||
$cek = $provider->decryptCek(
|
||||
base64_decode(
|
||||
$envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER]
|
||||
),
|
||||
json_decode(
|
||||
$envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER],
|
||||
true
|
||||
)
|
||||
);
|
||||
$cipherOptions['KeySize'] = strlen($cek) * 8;
|
||||
$cipherOptions['Cipher'] = $this->getCipherFromAesName(
|
||||
$envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER]
|
||||
);
|
||||
|
||||
$decryptionSteam = $this->getDecryptingStream(
|
||||
$cipherText,
|
||||
$cek,
|
||||
$cipherOptions
|
||||
);
|
||||
unset($cek);
|
||||
|
||||
return $decryptionSteam;
|
||||
}
|
||||
|
||||
private function getTagFromCiphertextStream(
|
||||
Psr7\Stream $cipherText,
|
||||
$tagLength
|
||||
) {
|
||||
$cipherTextSize = $cipherText->getSize();
|
||||
if ($cipherTextSize == null || $cipherTextSize <= 0) {
|
||||
throw new \RuntimeException('Cannot decrypt a stream of unknown'
|
||||
. ' size.');
|
||||
}
|
||||
return (string) new LimitStream(
|
||||
$cipherText,
|
||||
$tagLength,
|
||||
$cipherTextSize - $tagLength
|
||||
);
|
||||
}
|
||||
|
||||
private function getStrippedCiphertextStream(
|
||||
Psr7\Stream $cipherText,
|
||||
$tagLength
|
||||
) {
|
||||
$cipherTextSize = $cipherText->getSize();
|
||||
if ($cipherTextSize == null || $cipherTextSize <= 0) {
|
||||
throw new \RuntimeException('Cannot decrypt a stream of unknown'
|
||||
. ' size.');
|
||||
}
|
||||
return new LimitStream(
|
||||
$cipherText,
|
||||
$cipherTextSize - $tagLength,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a stream that wraps the cipher text with the proper cipher and
|
||||
* uses the content encryption key (CEK) to decrypt the data when read.
|
||||
*
|
||||
* @param string $cipherText Plain-text data to be encrypted using the
|
||||
* materials, algorithm, and data provided.
|
||||
* @param string $cek A content encryption key for use by the stream for
|
||||
* encrypting the plaintext data.
|
||||
* @param array $cipherOptions Options for use in determining the cipher to
|
||||
* be used for encrypting data.
|
||||
*
|
||||
* @return AesStreamInterface
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function getDecryptingStream(
|
||||
$cipherText,
|
||||
$cek,
|
||||
$cipherOptions
|
||||
) {
|
||||
$cipherTextStream = Psr7\stream_for($cipherText);
|
||||
switch ($cipherOptions['Cipher']) {
|
||||
case 'gcm':
|
||||
$cipherOptions['Tag'] = $this->getTagFromCiphertextStream(
|
||||
$cipherTextStream,
|
||||
$cipherOptions['TagLength']
|
||||
);
|
||||
|
||||
return new AesGcmDecryptingStream(
|
||||
$this->getStrippedCiphertextStream(
|
||||
$cipherTextStream,
|
||||
$cipherOptions['TagLength']
|
||||
),
|
||||
$cek,
|
||||
$cipherOptions['Iv'],
|
||||
$cipherOptions['Tag'],
|
||||
$cipherOptions['Aad'] = isset($cipherOptions['Aad'])
|
||||
? $cipherOptions['Aad']
|
||||
: null,
|
||||
$cipherOptions['TagLength'] ?: null,
|
||||
$cipherOptions['KeySize']
|
||||
);
|
||||
default:
|
||||
$cipherMethod = $this->buildCipherMethod(
|
||||
$cipherOptions['Cipher'],
|
||||
$cipherOptions['Iv'],
|
||||
$cipherOptions['KeySize']
|
||||
);
|
||||
return new AesDecryptingStream(
|
||||
$cipherTextStream,
|
||||
$cek,
|
||||
$cipherMethod
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
182
aws/Aws/Crypto/EncryptionTrait.php
Normal file
182
aws/Aws/Crypto/EncryptionTrait.php
Normal file
|
@ -0,0 +1,182 @@
|
|||
<?php
|
||||
namespace Aws\Crypto;
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\AppendStream;
|
||||
use GuzzleHttp\Psr7\Stream;
|
||||
|
||||
trait EncryptionTrait
|
||||
{
|
||||
private static $allowedOptions = [
|
||||
'Cipher' => true,
|
||||
'KeySize' => true,
|
||||
'Aad' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* Dependency to generate a CipherMethod from a set of inputs for loading
|
||||
* in to an AesEncryptingStream.
|
||||
*
|
||||
* @param string $cipherName Name of the cipher to generate for encrypting.
|
||||
* @param string $iv Base Initialization Vector for the cipher.
|
||||
* @param int $keySize Size of the encryption key, in bits, that will be
|
||||
* used.
|
||||
*
|
||||
* @return Cipher\CipherMethod
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract protected function buildCipherMethod($cipherName, $iv, $keySize);
|
||||
|
||||
/**
|
||||
* Builds an AesStreamInterface and populates encryption metadata into the
|
||||
* supplied envelope.
|
||||
*
|
||||
* @param Stream $plaintext Plain-text data to be encrypted using the
|
||||
* materials, algorithm, and data provided.
|
||||
* @param array $cipherOptions Options for use in determining the cipher to
|
||||
* be used for encrypting data.
|
||||
* @param MaterialsProvider $provider A provider to supply and encrypt
|
||||
* materials used in encryption.
|
||||
* @param MetadataEnvelope $envelope A storage envelope for encryption
|
||||
* metadata to be added to.
|
||||
*
|
||||
* @return AesStreamInterface
|
||||
*
|
||||
* @throws \InvalidArgumentException Thrown when a value in $cipherOptions
|
||||
* is not valid.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function encrypt(
|
||||
Stream $plaintext,
|
||||
array $cipherOptions,
|
||||
MaterialsProvider $provider,
|
||||
MetadataEnvelope $envelope
|
||||
) {
|
||||
$materialsDescription = $provider->getMaterialsDescription();
|
||||
|
||||
$cipherOptions = array_intersect_key(
|
||||
$cipherOptions,
|
||||
self::$allowedOptions
|
||||
);
|
||||
|
||||
if (empty($cipherOptions['Cipher'])) {
|
||||
throw new \InvalidArgumentException('An encryption cipher must be'
|
||||
. ' specified in the "cipher_options".');
|
||||
} elseif (!self::isSupportedCipher($cipherOptions['Cipher'])) {
|
||||
throw new \InvalidArgumentException('The cipher requested is not'
|
||||
. ' supported by the SDK.');
|
||||
}
|
||||
|
||||
if (empty($cipherOptions['KeySize'])) {
|
||||
$cipherOptions['KeySize'] = 256;
|
||||
}
|
||||
if (!is_int($cipherOptions['KeySize'])) {
|
||||
throw new \InvalidArgumentException('The cipher "KeySize" must be'
|
||||
. ' an integer.');
|
||||
} elseif (!MaterialsProvider::isSupportedKeySize(
|
||||
$cipherOptions['KeySize']
|
||||
)) {
|
||||
throw new \InvalidArgumentException('The cipher "KeySize" requested'
|
||||
. ' is not supported by AES (128, 192, or 256).');
|
||||
}
|
||||
|
||||
$cipherOptions['Iv'] = $provider->generateIv(
|
||||
$this->getCipherOpenSslName(
|
||||
$cipherOptions['Cipher'],
|
||||
$cipherOptions['KeySize']
|
||||
)
|
||||
);
|
||||
|
||||
$cek = $provider->generateCek($cipherOptions['KeySize']);
|
||||
|
||||
list($encryptingStream, $aesName) = $this->getEncryptingStream(
|
||||
$plaintext,
|
||||
$cek,
|
||||
$cipherOptions
|
||||
);
|
||||
|
||||
// Populate envelope data
|
||||
$envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER] =
|
||||
$provider->encryptCek(
|
||||
$cek,
|
||||
$materialsDescription
|
||||
);
|
||||
unset($cek);
|
||||
|
||||
$envelope[MetadataEnvelope::IV_HEADER] =
|
||||
base64_encode($cipherOptions['Iv']);
|
||||
$envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER] =
|
||||
$provider->getWrapAlgorithmName();
|
||||
$envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER] = $aesName;
|
||||
$envelope[MetadataEnvelope::UNENCRYPTED_CONTENT_LENGTH_HEADER] =
|
||||
strlen($plaintext);
|
||||
$envelope[MetadataEnvelope::UNENCRYPTED_CONTENT_MD5_HEADER] =
|
||||
base64_encode(md5($plaintext));
|
||||
$envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER] =
|
||||
json_encode($materialsDescription);
|
||||
if (!empty($cipherOptions['Tag'])) {
|
||||
$envelope[MetadataEnvelope::CRYPTO_TAG_LENGTH_HEADER] =
|
||||
strlen($cipherOptions['Tag']) * 8;
|
||||
}
|
||||
|
||||
return $encryptingStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a stream that wraps the plaintext with the proper cipher and
|
||||
* uses the content encryption key (CEK) to encrypt the data when read.
|
||||
*
|
||||
* @param Stream $plaintext Plain-text data to be encrypted using the
|
||||
* materials, algorithm, and data provided.
|
||||
* @param string $cek A content encryption key for use by the stream for
|
||||
* encrypting the plaintext data.
|
||||
* @param array $cipherOptions Options for use in determining the cipher to
|
||||
* be used for encrypting data.
|
||||
*
|
||||
* @return [AesStreamInterface, string]
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function getEncryptingStream(
|
||||
Stream $plaintext,
|
||||
$cek,
|
||||
&$cipherOptions
|
||||
) {
|
||||
switch ($cipherOptions['Cipher']) {
|
||||
case 'gcm':
|
||||
$cipherOptions['TagLength'] = 16;
|
||||
|
||||
$cipherTextStream = new AesGcmEncryptingStream(
|
||||
$plaintext,
|
||||
$cek,
|
||||
$cipherOptions['Iv'],
|
||||
$cipherOptions['Aad'] = isset($cipherOptions['Aad'])
|
||||
? $cipherOptions['Aad']
|
||||
: null,
|
||||
$cipherOptions['TagLength'],
|
||||
$cipherOptions['KeySize']
|
||||
);
|
||||
|
||||
$appendStream = new AppendStream([
|
||||
$cipherTextStream->createStream()
|
||||
]);
|
||||
$cipherOptions['Tag'] = $cipherTextStream->getTag();
|
||||
$appendStream->addStream(Psr7\stream_for($cipherOptions['Tag']));
|
||||
return [$appendStream, $cipherTextStream->getAesName()];
|
||||
default:
|
||||
$cipherMethod = $this->buildCipherMethod(
|
||||
$cipherOptions['Cipher'],
|
||||
$cipherOptions['Iv'],
|
||||
$cipherOptions['KeySize']
|
||||
);
|
||||
$cipherTextStream = new AesEncryptingStream(
|
||||
$plaintext,
|
||||
$cek,
|
||||
$cipherMethod
|
||||
);
|
||||
return [$cipherTextStream, $cipherTextStream->getAesName()];
|
||||
}
|
||||
}
|
||||
}
|
108
aws/Aws/Crypto/KmsMaterialsProvider.php
Normal file
108
aws/Aws/Crypto/KmsMaterialsProvider.php
Normal file
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
namespace Aws\Crypto;
|
||||
|
||||
use Aws\Kms\KmsClient;
|
||||
|
||||
/**
|
||||
* Uses KMS to supply materials for encrypting and decrypting data.
|
||||
*/
|
||||
class KmsMaterialsProvider extends MaterialsProvider
|
||||
{
|
||||
private $kmsClient;
|
||||
private $kmsKeyId;
|
||||
|
||||
/**
|
||||
* @param KmsClient $kmsClient A KMS Client for use encrypting and
|
||||
* decrypting keys.
|
||||
* @param string $kmsKeyId The private KMS key id to be used for encrypting
|
||||
* and decrypting keys.
|
||||
*/
|
||||
public function __construct(
|
||||
KmsClient $kmsClient,
|
||||
$kmsKeyId = null
|
||||
) {
|
||||
$this->kmsClient = $kmsClient;
|
||||
$this->kmsKeyId = $kmsKeyId;
|
||||
}
|
||||
|
||||
public function fromDecryptionEnvelope(MetadataEnvelope $envelope)
|
||||
{
|
||||
if (empty($envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER])) {
|
||||
throw new \RuntimeException('Not able to detect kms_cmk_id from an'
|
||||
. ' empty materials description.');
|
||||
}
|
||||
|
||||
$materialsDescription = json_decode(
|
||||
$envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER],
|
||||
true
|
||||
);
|
||||
if (empty($materialsDescription['kms_cmk_id'])) {
|
||||
throw new \RuntimeException('Not able to detect kms_cmk_id from kms'
|
||||
. ' materials description.');
|
||||
}
|
||||
|
||||
return new KmsMaterialsProvider(
|
||||
$this->kmsClient,
|
||||
$materialsDescription['kms_cmk_id']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The KMS key id for use in matching this Provider to its keys,
|
||||
* consistently with other SDKs as 'kms_cmk_id'.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMaterialsDescription()
|
||||
{
|
||||
return ['kms_cmk_id' => $this->kmsKeyId];
|
||||
}
|
||||
|
||||
public function getWrapAlgorithmName()
|
||||
{
|
||||
return 'kms';
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a content encryption key (CEK) and description to return an encrypted
|
||||
* key by using KMS' Encrypt API.
|
||||
*
|
||||
* @param string $unencryptedCek Key for use in encrypting other data
|
||||
* that itself needs to be encrypted by the
|
||||
* Provider.
|
||||
* @param string $materialDescription Material Description for use in
|
||||
* encrypting the $cek.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encryptCek($unencryptedCek, $materialDescription)
|
||||
{
|
||||
$encryptedDataKey = $this->kmsClient->encrypt([
|
||||
'Plaintext' => $unencryptedCek,
|
||||
'KeyId' => $this->kmsKeyId,
|
||||
'EncryptionContext' => $materialDescription
|
||||
]);
|
||||
return base64_encode($encryptedDataKey['CiphertextBlob']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an encrypted content encryption key (CEK) and material description
|
||||
* for use decrypting the key by using KMS' Decrypt API.
|
||||
*
|
||||
* @param string $encryptedCek Encrypted key to be decrypted by the Provider
|
||||
* for use decrypting other data.
|
||||
* @param string $materialDescription Material Description for use in
|
||||
* encrypting the $cek.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function decryptCek($encryptedCek, $materialDescription)
|
||||
{
|
||||
$result = $this->kmsClient->decrypt([
|
||||
'CiphertextBlob' => $encryptedCek,
|
||||
'EncryptionContext' => $materialDescription
|
||||
]);
|
||||
|
||||
return $result['Plaintext'];
|
||||
}
|
||||
}
|
105
aws/Aws/Crypto/MaterialsProvider.php
Normal file
105
aws/Aws/Crypto/MaterialsProvider.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
namespace Aws\Crypto;
|
||||
|
||||
abstract class MaterialsProvider
|
||||
{
|
||||
private static $supportedKeySizes = [
|
||||
128 => true,
|
||||
192 => true,
|
||||
256 => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns if the requested size is supported by AES.
|
||||
*
|
||||
* @param int $keySize Size of the requested key in bits.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupportedKeySize($keySize)
|
||||
{
|
||||
return isset(self::$supportedKeySizes[$keySize]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs further initialization of the MaterialsProvider based on the
|
||||
* data inside the MetadataEnvelope.
|
||||
*
|
||||
* @param MetadataEnvelope $envelope A storage envelope for encryption
|
||||
* metadata to be read from.
|
||||
*
|
||||
* @return MaterialsProvider
|
||||
*
|
||||
* @throws \RuntimeException Thrown when there is an empty or improperly
|
||||
* formed materials description in the envelope.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract public function fromDecryptionEnvelope(MetadataEnvelope $envelope);
|
||||
|
||||
/**
|
||||
* Returns the material description for this Provider so it can be verified
|
||||
* by encryption mechanisms.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getMaterialsDescription();
|
||||
|
||||
/**
|
||||
* Returns the wrap algorithm name for this Provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function getWrapAlgorithmName();
|
||||
|
||||
/**
|
||||
* Takes a content encryption key (CEK) and description to return an
|
||||
* encrypted key according to the Provider's specifications.
|
||||
*
|
||||
* @param string $unencryptedCek Key for use in encrypting other data
|
||||
* that itself needs to be encrypted by the
|
||||
* Provider.
|
||||
* @param string $materialDescription Material Description for use in
|
||||
* encrypting the $cek.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function encryptCek($unencryptedCek, $materialDescription);
|
||||
|
||||
/**
|
||||
* Takes an encrypted content encryption key (CEK) and material description
|
||||
* for use decrypting the key according to the Provider's specifications.
|
||||
*
|
||||
* @param string $encryptedCek Encrypted key to be decrypted by the Provider
|
||||
* for use decrypting other data.
|
||||
* @param string $materialDescription Material Description for use in
|
||||
* encrypting the $cek.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function decryptCek($encryptedCek, $materialDescription);
|
||||
|
||||
/**
|
||||
* @param string $keySize Length of a cipher key in bits for generating a
|
||||
* random content encryption key (CEK).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generateCek($keySize)
|
||||
{
|
||||
return openssl_random_pseudo_bytes($keySize / 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $openSslName Cipher OpenSSL name to use for generating
|
||||
* an initialization vector.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generateIv($openSslName)
|
||||
{
|
||||
return openssl_random_pseudo_bytes(
|
||||
openssl_cipher_iv_length($openSslName)
|
||||
);
|
||||
}
|
||||
}
|
57
aws/Aws/Crypto/MetadataEnvelope.php
Normal file
57
aws/Aws/Crypto/MetadataEnvelope.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
namespace Aws\Crypto;
|
||||
|
||||
use Aws\HasDataTrait;
|
||||
use \ArrayAccess;
|
||||
use \IteratorAggregate;
|
||||
use \InvalidArgumentException;
|
||||
use \JsonSerializable;
|
||||
|
||||
/**
|
||||
* Stores encryption metadata for reading and writing.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class MetadataEnvelope implements ArrayAccess, IteratorAggregate, JsonSerializable
|
||||
{
|
||||
use HasDataTrait;
|
||||
|
||||
const CONTENT_KEY_V2_HEADER = 'x-amz-key-v2';
|
||||
const IV_HEADER = 'x-amz-iv';
|
||||
const MATERIALS_DESCRIPTION_HEADER = 'x-amz-matdesc';
|
||||
const KEY_WRAP_ALGORITHM_HEADER = 'x-amz-wrap-alg';
|
||||
const CONTENT_CRYPTO_SCHEME_HEADER = 'x-amz-cek-alg';
|
||||
const CRYPTO_TAG_LENGTH_HEADER = 'x-amz-tag-len';
|
||||
const UNENCRYPTED_CONTENT_MD5_HEADER = 'x-amz-unencrypted-content-md5';
|
||||
const UNENCRYPTED_CONTENT_LENGTH_HEADER = 'x-amz-unencrypted-content-length';
|
||||
|
||||
private static $constants = [];
|
||||
|
||||
public static function getConstantValues()
|
||||
{
|
||||
if (empty(self::$constants)) {
|
||||
$reflection = new \ReflectionClass(static::class);
|
||||
foreach (array_values($reflection->getConstants()) as $constant) {
|
||||
self::$constants[$constant] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return array_keys(self::$constants);
|
||||
}
|
||||
|
||||
public function offsetSet($name, $value)
|
||||
{
|
||||
$constants = self::getConstantValues();
|
||||
if (is_null($name) || !in_array($name, $constants)) {
|
||||
throw new InvalidArgumentException('MetadataEnvelope fields must'
|
||||
. ' must match a predefined offset; use the header constants.');
|
||||
} else {
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
30
aws/Aws/Crypto/MetadataStrategyInterface.php
Normal file
30
aws/Aws/Crypto/MetadataStrategyInterface.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
namespace Aws\Crypto;
|
||||
|
||||
interface MetadataStrategyInterface
|
||||
{
|
||||
/**
|
||||
* Places the information in the MetadataEnvelope to the strategy specific
|
||||
* location. Populates the PutObject arguments with any information
|
||||
* necessary for loading.
|
||||
*
|
||||
* @param MetadataEnvelope $envelope Encryption data to save according to
|
||||
* the strategy.
|
||||
* @param array $args Starting arguments for PutObject.
|
||||
*
|
||||
* @return array Updated arguments for PutObject.
|
||||
*/
|
||||
public function save(MetadataEnvelope $envelope, array $args);
|
||||
|
||||
/**
|
||||
* Generates a MetadataEnvelope according to the specific strategy using the
|
||||
* passed arguments.
|
||||
*
|
||||
* @param array $args Arguments from Command and Result that contains
|
||||
* S3 Object information, relevant headers, and command
|
||||
* configuration.
|
||||
*
|
||||
* @return MetadataEnvelope
|
||||
*/
|
||||
public function load(array $args);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue