Failed Conditions
Push — master ( 5a4c88...a04b71 )
by Florent
02:03
created

AESCBCHS::checkKeyLength()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2017 Spomky-Labs
9
 *
10
 * This software may be modified and distributed under the terms
11
 * of the MIT license.  See the LICENSE file for details.
12
 */
13
14
namespace Jose\Component\Encryption\Algorithm\ContentEncryption;
15
16
use Jose\Component\Encryption\Algorithm\ContentEncryptionAlgorithm;
17
18
/**
19
 * Class AESCBCHS.
20
 */
21
abstract class AESCBCHS implements ContentEncryptionAlgorithm
22
{
23
    /**
24
     * {@inheritdoc}
25
     */
26
    public function allowedKeyTypes(): array
27
    {
28
        return []; //Irrelevant
29
    }
30
31
    /**
32
     * {@inheritdoc}
33
     */
34
    public function encryptContent(string $data, string $cek, string $iv, ?string $aad, string $encoded_protected_header, ?string &$tag): string
35
    {
36
        $k = mb_substr($cek, $this->getCEKSize() / 16, null, '8bit');
37
        $cyphertext = openssl_encrypt($data, $this->getMode(), $k, OPENSSL_RAW_DATA, $iv);
38
        if (false === $cyphertext) {
39
            throw new \RuntimeException('Unable to encrypt.');
40
        }
41
42
        $tag = $this->calculateAuthenticationTag($cyphertext, $cek, $iv, $aad, $encoded_protected_header);
43
44
        return $cyphertext;
45
    }
46
47
    /**
48
     * @param string      $data
49
     * @param string      $cek
50
     * @param string      $iv
51
     * @param string      $aad
52
     * @param string      $encoded_protected_header
53
     * @param string|null $aad
54
     * @param string      $tag
55
     *
56
     * @return string
57
     */
58
    public function decryptContent(string $data, string $cek, string $iv, ?string $aad, string $encoded_protected_header, string $tag): string
59
    {
60
        if (!$this->isTagValid($data, $cek, $iv, $aad, $encoded_protected_header, $tag)) {
61
            throw new \InvalidArgumentException('Unable to verify the tag.');
62
        }
63
        $k = mb_substr($cek, $this->getCEKSize() / 16, null, '8bit');
64
65
        $plaintext = openssl_decrypt($data, $this->getMode(), $k, OPENSSL_RAW_DATA, $iv);
66
        if (false === $plaintext) {
67
            throw new \RuntimeException('Unable to decrypt.');
68
        }
69
70
        return $plaintext;
71
    }
72
73
    /**
74
     * @param string      $encrypted_data
75
     * @param string      $cek
76
     * @param string      $iv
77
     * @param null|string $aad
78
     * @param string      $encoded_header
79
     *
80
     * @return string
81
     */
82
    protected function calculateAuthenticationTag(string $encrypted_data, string $cek, string $iv, ?string $aad, string $encoded_header): string
83
    {
84
        $calculated_aad = $encoded_header;
85
        if (null !== $aad) {
86
            $calculated_aad .= '.'.$aad;
87
        }
88
        $mac_key = mb_substr($cek, 0, $this->getCEKSize() / 16, '8bit');
89
        $auth_data_length = mb_strlen($encoded_header, '8bit');
90
91
        $secured_input = implode('', [
92
            $calculated_aad,
93
            $iv,
94
            $encrypted_data,
95
            pack('N2', ($auth_data_length / 2147483647) * 8, ($auth_data_length % 2147483647) * 8),
96
        ]);
97
        $hash = hash_hmac($this->getHashAlgorithm(), $secured_input, $mac_key, true);
98
99
        return  mb_substr($hash, 0, mb_strlen($hash, '8bit') / 2, '8bit');
100
    }
101
102
    /**
103
     * @param string      $authentication_tag
104
     * @param string      $encoded_header
105
     * @param string      $encrypted_data
106
     * @param string      $cek
107
     * @param string      $iv
108
     * @param string|null $aad
109
     *
110
     * @return bool
111
     */
112
    protected function isTagValid(string $encrypted_data, string $cek, string $iv, ?string $aad, string $encoded_header, string $authentication_tag): bool
113
    {
114
        return hash_equals($authentication_tag, $this->calculateAuthenticationTag($encrypted_data, $cek, $iv, $aad, $encoded_header));
115
    }
116
117
    /**
118
     * @return string
119
     */
120
    abstract protected function getHashAlgorithm(): string;
121
122
    /**
123
     * @return string
124
     */
125
    abstract protected function getMode(): string;
126
127
    /**
128
     * @return int
129
     */
130
    public function getIVSize(): int
131
    {
132
        return 128;
133
    }
134
}
135