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\LimitStream;
6
use Psr\Http\Message\StreamInterface;
7
 
8
trait DecryptionTrait
9
{
10
    /**
11
     * Dependency to reverse lookup the openssl_* cipher name from the AESName
12
     * in the MetadataEnvelope.
13
     *
14
     * @param $aesName
15
     *
16
     * @return string
17
     *
18
     * @internal
19
     */
20
    abstract protected function getCipherFromAesName($aesName);
21
 
22
    /**
23
     * Dependency to generate a CipherMethod from a set of inputs for loading
24
     * in to an AesDecryptingStream.
25
     *
26
     * @param string $cipherName Name of the cipher to generate for decrypting.
27
     * @param string $iv Base Initialization Vector for the cipher.
28
     * @param int $keySize Size of the encryption key, in bits, that will be
29
     *                     used.
30
     *
31
     * @return Cipher\CipherMethod
32
     *
33
     * @internal
34
     */
35
    abstract protected function buildCipherMethod($cipherName, $iv, $keySize);
36
 
37
    /**
38
     * Builds an AesStreamInterface using cipher options loaded from the
39
     * MetadataEnvelope and MaterialsProvider. Can decrypt data from both the
40
     * legacy and V2 encryption client workflows.
41
     *
42
     * @param string $cipherText Plain-text data to be encrypted using the
43
     *                           materials, algorithm, and data provided.
44
     * @param MaterialsProviderInterface $provider A provider to supply and encrypt
45
     *                                             materials used in encryption.
46
     * @param MetadataEnvelope $envelope A storage envelope for encryption
47
     *                                   metadata to be read from.
48
     * @param array $cipherOptions Additional verification options.
49
     *
50
     * @return AesStreamInterface
51
     *
52
     * @throws \InvalidArgumentException Thrown when a value in $cipherOptions
53
     *                                   is not valid.
54
     *
55
     * @internal
56
     */
57
    public function decrypt(
58
        $cipherText,
59
        MaterialsProviderInterface $provider,
60
        MetadataEnvelope $envelope,
61
        array $cipherOptions = []
62
    ) {
63
        $cipherOptions['Iv'] = base64_decode(
64
            $envelope[MetadataEnvelope::IV_HEADER]
65
        );
66
 
67
        $cipherOptions['TagLength'] =
68
            $envelope[MetadataEnvelope::CRYPTO_TAG_LENGTH_HEADER] / 8;
69
 
70
        $cek = $provider->decryptCek(
71
            base64_decode(
72
                $envelope[MetadataEnvelope::CONTENT_KEY_V2_HEADER]
73
            ),
74
            json_decode(
75
                $envelope[MetadataEnvelope::MATERIALS_DESCRIPTION_HEADER],
76
                true
77
            )
78
        );
79
        $cipherOptions['KeySize'] = strlen($cek) * 8;
80
        $cipherOptions['Cipher'] = $this->getCipherFromAesName(
81
            $envelope[MetadataEnvelope::CONTENT_CRYPTO_SCHEME_HEADER]
82
        );
83
 
84
        $decryptionStream = $this->getDecryptingStream(
85
            $cipherText,
86
            $cek,
87
            $cipherOptions
88
        );
89
        unset($cek);
90
 
91
        return $decryptionStream;
92
    }
93
 
94
    private function getTagFromCiphertextStream(
95
        StreamInterface $cipherText,
96
        $tagLength
97
    ) {
98
        $cipherTextSize = $cipherText->getSize();
99
        if ($cipherTextSize == null || $cipherTextSize <= 0) {
100
            throw new \RuntimeException('Cannot decrypt a stream of unknown'
101
                . ' size.');
102
        }
103
        return (string) new LimitStream(
104
            $cipherText,
105
            $tagLength,
106
            $cipherTextSize - $tagLength
107
        );
108
    }
109
 
110
    private function getStrippedCiphertextStream(
111
        StreamInterface $cipherText,
112
        $tagLength
113
    ) {
114
        $cipherTextSize = $cipherText->getSize();
115
        if ($cipherTextSize == null || $cipherTextSize <= 0) {
116
            throw new \RuntimeException('Cannot decrypt a stream of unknown'
117
                . ' size.');
118
        }
119
        return new LimitStream(
120
            $cipherText,
121
            $cipherTextSize - $tagLength,
122
 
123
        );
124
    }
125
 
126
    /**
127
     * Generates a stream that wraps the cipher text with the proper cipher and
128
     * uses the content encryption key (CEK) to decrypt the data when read.
129
     *
130
     * @param string $cipherText Plain-text data to be encrypted using the
131
     *                           materials, algorithm, and data provided.
132
     * @param string $cek A content encryption key for use by the stream for
133
     *                    encrypting the plaintext data.
134
     * @param array $cipherOptions Options for use in determining the cipher to
135
     *                             be used for encrypting data.
136
     *
137
     * @return AesStreamInterface
138
     *
139
     * @internal
140
     */
141
    protected function getDecryptingStream(
142
        $cipherText,
143
        $cek,
144
        $cipherOptions
145
    ) {
146
        $cipherTextStream = Psr7\Utils::streamFor($cipherText);
147
        switch ($cipherOptions['Cipher']) {
148
            case 'gcm':
149
                $cipherOptions['Tag'] = $this->getTagFromCiphertextStream(
150
                        $cipherTextStream,
151
                        $cipherOptions['TagLength']
152
                    );
153
 
154
                return new AesGcmDecryptingStream(
155
                    $this->getStrippedCiphertextStream(
156
                        $cipherTextStream,
157
                        $cipherOptions['TagLength']
158
                    ),
159
                    $cek,
160
                    $cipherOptions['Iv'],
161
                    $cipherOptions['Tag'],
162
                    $cipherOptions['Aad'] = isset($cipherOptions['Aad'])
163
                        ? $cipherOptions['Aad']
164
                        : '',
165
                    $cipherOptions['TagLength'] ?: null,
166
                    $cipherOptions['KeySize']
167
                );
168
            default:
169
                $cipherMethod = $this->buildCipherMethod(
170
                    $cipherOptions['Cipher'],
171
                    $cipherOptions['Iv'],
172
                    $cipherOptions['KeySize']
173
                );
174
                return new AesDecryptingStream(
175
                    $cipherTextStream,
176
                    $cek,
177
                    $cipherMethod
178
                );
179
        }
180
    }
181
}