Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
namespace Aws\Crypto;
3
 
4
use GuzzleHttp\Psr7;
5
use GuzzleHttp\Psr7\AppendStream;
6
use GuzzleHttp\Psr7\Stream;
7
 
8
trait EncryptionTrait
9
{
10
    private static $allowedOptions = [
11
        'Cipher' => true,
12
        'KeySize' => true,
13
        'Aad' => true,
14
    ];
15
 
16
    /**
17
     * Dependency to generate a CipherMethod from a set of inputs for loading
18
     * in to an AesEncryptingStream.
19
     *
20
     * @param string $cipherName Name of the cipher to generate for encrypting.
21
     * @param string $iv Base Initialization Vector for the cipher.
22
     * @param int $keySize Size of the encryption key, in bits, that will be
23
     *                     used.
24
     *
25
     * @return Cipher\CipherMethod
26
     *
27
     * @internal
28
     */
29
    abstract protected function buildCipherMethod($cipherName, $iv, $keySize);
30
 
31
    /**
32
     * Builds an AesStreamInterface and populates encryption metadata into the
33
     * supplied envelope.
34
     *
35
     * @param Stream $plaintext Plain-text data to be encrypted using the
36
     *                          materials, algorithm, and data provided.
37
     * @param array $cipherOptions Options for use in determining the cipher to
38
     *                             be used for encrypting data.
39
     * @param MaterialsProvider $provider A provider to supply and encrypt
40
     *                                    materials used in encryption.
41
     * @param MetadataEnvelope $envelope A storage envelope for encryption
42
     *                                   metadata to be added to.
43
     *
44
     * @return AesStreamInterface
45
     *
46
     * @throws \InvalidArgumentException Thrown when a value in $cipherOptions
47
     *                                   is not valid.
48
     *
49
     * @internal
50
     */
51
    public function encrypt(
52
        Stream $plaintext,
53
        array $cipherOptions,
54
        MaterialsProvider $provider,
55
        MetadataEnvelope $envelope
56
    ) {
57
        $materialsDescription = $provider->getMaterialsDescription();
58
 
59
        $cipherOptions = array_intersect_key(
60
            $cipherOptions,
61
            self::$allowedOptions
62
        );
63
 
64
        if (empty($cipherOptions['Cipher'])) {
65
            throw new \InvalidArgumentException('An encryption cipher must be'
66
                . ' specified in the "cipher_options".');
67
        }
68
 
69
        if (!self::isSupportedCipher($cipherOptions['Cipher'])) {
70
            throw new \InvalidArgumentException('The cipher requested is not'
71
                . ' supported by the SDK.');
72
        }
73
 
74
        if (empty($cipherOptions['KeySize'])) {
75
            $cipherOptions['KeySize'] = 256;
76
        }
77
        if (!is_int($cipherOptions['KeySize'])) {
78
            throw new \InvalidArgumentException('The cipher "KeySize" must be'
79
                . ' an integer.');
80
        }
81
 
82
        if (!MaterialsProvider::isSupportedKeySize(
83
            $cipherOptions['KeySize']
84
        )) {
85
            throw new \InvalidArgumentException('The cipher "KeySize" requested'
86
                . ' is not supported by AES (128, 192, or 256).');
87
        }
88
 
89
        $cipherOptions['Iv'] = $provider->generateIv(
90
            $this->getCipherOpenSslName(
91
                $cipherOptions['Cipher'],
92
                $cipherOptions['KeySize']
93
            )
94
        );
95
 
96
        $cek = $provider->generateCek($cipherOptions['KeySize']);
97
 
98
        list($encryptingStream, $aesName) = $this->getEncryptingStream(
99
            $plaintext,
100
            $cek,
101
            $cipherOptions
102
        );
103
 
104
        // Populate envelope data
105
        $envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER] =
106
            $provider->encryptCek(
107
                $cek,
108
                $materialsDescription
109
            );
110
        unset($cek);
111
 
112
        $envelope[MetadataEnvelope::IV_HEADER] =
113
            base64_encode($cipherOptions['Iv']);
114
        $envelope[MetadataEnvelope::KEY_WRAP_ALGORITHM_HEADER] =
115
            $provider->getWrapAlgorithmName();
116
        $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER] = $aesName;
117
        $envelope[MetadataEnvelope::UNENCRYPTED_CONTENT_LENGTH_HEADER] =
118
            strlen($plaintext);
119
        $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER] =
120
            json_encode($materialsDescription);
121
        if (!empty($cipherOptions['Tag'])) {
122
            $envelope[MetadataEnvelope::CRYPTO_TAG_LENGTH_HEADER] =
123
                strlen($cipherOptions['Tag']) * 8;
124
        }
125
 
126
        return $encryptingStream;
127
    }
128
 
129
    /**
130
     * Generates a stream that wraps the plaintext with the proper cipher and
131
     * uses the content encryption key (CEK) to encrypt the data when read.
132
     *
133
     * @param Stream $plaintext Plain-text data to be encrypted using the
134
     *                          materials, algorithm, and data provided.
135
     * @param string $cek A content encryption key for use by the stream for
136
     *                    encrypting the plaintext data.
137
     * @param array $cipherOptions Options for use in determining the cipher to
138
     *                             be used for encrypting data.
139
     *
140
     * @return [AesStreamInterface, string]
141
     *
142
     * @internal
143
     */
144
    protected function getEncryptingStream(
145
        Stream $plaintext,
146
        $cek,
147
        &$cipherOptions
148
    ) {
149
        switch ($cipherOptions['Cipher']) {
150
            case 'gcm':
151
                $cipherOptions['TagLength'] = 16;
152
 
153
                $cipherTextStream = new AesGcmEncryptingStream(
154
                    $plaintext,
155
                    $cek,
156
                    $cipherOptions['Iv'],
157
                    $cipherOptions['Aad'] = isset($cipherOptions['Aad'])
158
                        ? $cipherOptions['Aad']
159
                        : '',
160
                    $cipherOptions['TagLength'],
161
                    $cipherOptions['KeySize']
162
                );
163
 
164
                if (!empty($cipherOptions['Aad'])) {
165
                    trigger_error("'Aad' has been supplied for content encryption"
166
                        . " with " . $cipherTextStream->getAesName() . ". The"
167
                        . " PHP SDK encryption client can decrypt an object"
168
                        . " encrypted in this way, but other AWS SDKs may not be"
169
                        . " able to.", E_USER_WARNING);
170
                }
171
 
172
                $appendStream = new AppendStream([
173
                    $cipherTextStream->createStream()
174
                ]);
175
                $cipherOptions['Tag'] = $cipherTextStream->getTag();
176
                $appendStream->addStream(Psr7\Utils::streamFor($cipherOptions['Tag']));
177
                return [$appendStream, $cipherTextStream->getAesName()];
178
            default:
179
                $cipherMethod = $this->buildCipherMethod(
180
                    $cipherOptions['Cipher'],
181
                    $cipherOptions['Iv'],
182
                    $cipherOptions['KeySize']
183
                );
184
                $cipherTextStream = new AesEncryptingStream(
185
                    $plaintext,
186
                    $cek,
187
                    $cipherMethod
188
                );
189
                return [$cipherTextStream, $cipherTextStream->getAesName()];
190
        }
191
    }
192
}