KmsMaterialsProvider.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. <?php
  2. namespace Aws\Crypto;
  3. use Aws\Kms\KmsClient;
  4. /**
  5. * Uses KMS to supply materials for encrypting and decrypting data.
  6. *
  7. * Legacy implementation that supports legacy S3EncryptionClient and
  8. * S3EncryptionMultipartUploader, which use an older encryption workflow. Use
  9. * KmsMaterialsProviderV2 with S3EncryptionClientV2 or
  10. * S3EncryptionMultipartUploaderV2 if possible.
  11. *
  12. * @deprecated
  13. */
  14. class KmsMaterialsProvider extends MaterialsProvider implements MaterialsProviderInterface
  15. {
  16. const WRAP_ALGORITHM_NAME = 'kms';
  17. private $kmsClient;
  18. private $kmsKeyId;
  19. /**
  20. * @param KmsClient $kmsClient A KMS Client for use encrypting and
  21. * decrypting keys.
  22. * @param string $kmsKeyId The private KMS key id to be used for encrypting
  23. * and decrypting keys.
  24. */
  25. public function __construct(
  26. KmsClient $kmsClient,
  27. $kmsKeyId = null
  28. ) {
  29. $this->kmsClient = $kmsClient;
  30. $this->kmsKeyId = $kmsKeyId;
  31. }
  32. public function fromDecryptionEnvelope(MetadataEnvelope $envelope)
  33. {
  34. if (empty($envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER])) {
  35. throw new \RuntimeException('Not able to detect the materials description.');
  36. }
  37. $materialsDescription = json_decode(
  38. $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER],
  39. true
  40. );
  41. if (empty($materialsDescription['kms_cmk_id'])
  42. && empty($materialsDescription['aws:x-amz-cek-alg'])) {
  43. throw new \RuntimeException('Not able to detect kms_cmk_id (legacy'
  44. . ' implementation) or aws:x-amz-cek-alg (current implementation)'
  45. . ' from kms materials description.');
  46. }
  47. return new self(
  48. $this->kmsClient,
  49. isset($materialsDescription['kms_cmk_id'])
  50. ? $materialsDescription['kms_cmk_id']
  51. : null
  52. );
  53. }
  54. /**
  55. * The KMS key id for use in matching this Provider to its keys,
  56. * consistently with other SDKs as 'kms_cmk_id'.
  57. *
  58. * @return array
  59. */
  60. public function getMaterialsDescription()
  61. {
  62. return ['kms_cmk_id' => $this->kmsKeyId];
  63. }
  64. public function getWrapAlgorithmName()
  65. {
  66. return self::WRAP_ALGORITHM_NAME;
  67. }
  68. /**
  69. * Takes a content encryption key (CEK) and description to return an encrypted
  70. * key by using KMS' Encrypt API.
  71. *
  72. * @param string $unencryptedCek Key for use in encrypting other data
  73. * that itself needs to be encrypted by the
  74. * Provider.
  75. * @param string $materialDescription Material Description for use in
  76. * encrypting the $cek.
  77. *
  78. * @return string
  79. */
  80. public function encryptCek($unencryptedCek, $materialDescription)
  81. {
  82. $encryptedDataKey = $this->kmsClient->encrypt([
  83. 'Plaintext' => $unencryptedCek,
  84. 'KeyId' => $this->kmsKeyId,
  85. 'EncryptionContext' => $materialDescription
  86. ]);
  87. return base64_encode($encryptedDataKey['CiphertextBlob']);
  88. }
  89. /**
  90. * Takes an encrypted content encryption key (CEK) and material description
  91. * for use decrypting the key by using KMS' Decrypt API.
  92. *
  93. * @param string $encryptedCek Encrypted key to be decrypted by the Provider
  94. * for use decrypting other data.
  95. * @param string $materialDescription Material Description for use in
  96. * encrypting the $cek.
  97. *
  98. * @return string
  99. */
  100. public function decryptCek($encryptedCek, $materialDescription)
  101. {
  102. $result = $this->kmsClient->decrypt([
  103. 'CiphertextBlob' => $encryptedCek,
  104. 'EncryptionContext' => $materialDescription
  105. ]);
  106. return $result['Plaintext'];
  107. }
  108. }