DigitalEnvelope   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 157
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 12
eloc 46
c 2
b 0
f 0
dl 0
loc 157
ccs 35
cts 35
cp 1
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 3
A openEnvelope() 0 14 4
A __clone() 0 8 2
A sealEnvelope() 0 13 2
A __destruct() 0 4 1
1
<?php
2
3
/**
4
 * Cryptographic digital envelope protocol for secure data transfers.
5
 */
6
7
namespace CryptoManana\CryptographicProtocol;
8
9
use CryptoManana\Core\Abstractions\Containers\AbstractCryptographicProtocol as CryptographicProtocol;
10
use CryptoManana\Core\Abstractions\Randomness\AbstractRandomness as RandomnessSource;
11
use CryptoManana\Core\Abstractions\Randomness\AbstractGenerator as RandomnessGenerator;
12
use CryptoManana\Core\Abstractions\MessageDigestion\AbstractKeyedHashFunction as KeyedHashFunction;
13
use CryptoManana\Core\Abstractions\MessageEncryption\AbstractBlockCipherAlgorithm as SymmetricBlockCipher;
14
use CryptoManana\Core\Abstractions\MessageEncryption\AbstractAsymmetricEncryptionAlgorithm as AsymmetricEncryption;
15
use CryptoManana\Core\Interfaces\MessageEncryption\DataEncryptionInterface as DataEncryption;
16
use CryptoManana\Core\Interfaces\Containers\DigitalEnvelopeInterface as DigitalEnvelopeProcessing;
17
use CryptoManana\Core\Interfaces\Containers\RandomnessInjectableInterface as RandomGeneratorSetter;
18
use CryptoManana\Core\Interfaces\Containers\KeyedDigestionInjectableInterface as KeyedHashFunctionSetter;
19
use CryptoManana\Core\Interfaces\Containers\SymmetricEncryptionInjectableInterface as SymmetricCipherSetter;
20
use CryptoManana\Core\Interfaces\Containers\AsymmetricEncryptionInjectableInterface as AsymmetricCipherSetter;
21
use CryptoManana\Core\Traits\Containers\RandomnessInjectableTrait as RandomGeneratorSetterImplementation;
22
use CryptoManana\Core\Traits\Containers\KeyedDigestionInjectableTrait as KeyedHashFunctionSetterImplementation;
23
use CryptoManana\Core\Traits\Containers\SymmetricEncryptionInjectableTrait as SymmetricCipherSetterImplementation;
24
use CryptoManana\Core\Traits\Containers\AsymmetricEncryptionInjectableTrait as AsymmetricCipherSetterImplementation;
25
use CryptoManana\Randomness\CryptoRandom as DefaultRandomnessSource;
26
use CryptoManana\DataStructures\EnvelopeData as EnvelopeStructure;
27
28
/**
29
 * Class DigitalEnvelope - The digital envelope cryptographic protocol object.
30
 *
31
 * @package CryptoManana\CryptographicProtocol
32
 *
33
 * @mixin RandomGeneratorSetterImplementation
34
 * @mixin KeyedHashFunctionSetterImplementation
35
 * @mixin SymmetricCipherSetterImplementation
36
 * @mixin AsymmetricCipherSetterImplementation
37
 */
38
class DigitalEnvelope extends CryptographicProtocol implements
39
    RandomGeneratorSetter,
40
    KeyedHashFunctionSetter,
41
    SymmetricCipherSetter,
42
    AsymmetricCipherSetter,
43
    DigitalEnvelopeProcessing
44
{
45
    /**
46
     * Dependency injection via a setter method implementation.
47
     *
48
     * {@internal Reusable implementation of `RandomnessInjectableInterface`. }}
49
     */
50
    use RandomGeneratorSetterImplementation;
51
52
    /**
53
     * The message keyed digestion service dependency injection via a setter method implementation.
54
     *
55
     * {@internal Reusable implementation of `KeyedDigestionInjectableInterface`. }}
56
     */
57
    use KeyedHashFunctionSetterImplementation;
58
59
    /**
60
     * The message symmetric encryption service dependency injection via a setter method implementation.
61
     *
62
     * {@internal Reusable implementation of `SymmetricEncryptionInjectableInterface`. }}
63
     */
64
    use SymmetricCipherSetterImplementation;
65
66
    /**
67
     * The message asymmetric encryption service dependency injection via a setter method.
68
     *
69
     * {@internal Reusable implementation of `AsymmetricEncryptionInjectableInterface`. }}
70
     */
71
    use AsymmetricCipherSetterImplementation;
72
73
    /**
74
     * The pseudo-random generator service property storage.
75
     *
76
     * @var RandomnessSource|RandomnessGenerator|null The pseudo-random generator service.
77
     */
78
    protected $randomnessSource = null;
79
80
    /**
81
     * The message keyed digestion service property storage.
82
     *
83
     * @var KeyedHashFunction|null The message keyed digestion service.
84
     */
85
    protected $keyedDigestionSource = null;
86
87
    /**
88
     * The message encryption symmetric algorithm service property storage.
89
     *
90
     * @var SymmetricBlockCipher|DataEncryption|null The symmetric message encryption service.
91
     */
92
    protected $symmetricCipherSource = null;
93
94
    /**
95
     * The message asymmetric encryption algorithm service property storage.
96
     *
97
     * @var AsymmetricEncryption|DataEncryption|null The message asymmetric encryption service.
98
     */
99
    protected $asymmetricCipherSource = null;
100
101
    /**
102
     * Container constructor.
103
     *
104
     * @param AsymmetricEncryption|DataEncryption|null $asymmetric The asymmetric message encryption service.
105
     * @param SymmetricBlockCipher|null $symmetric the message encryption service.
106
     *
107
     * @throws \Exception Initialization validation.
108
     */
109 13
    public function __construct(AsymmetricEncryption $asymmetric = null, SymmetricBlockCipher $symmetric = null)
110
    {
111 13
        if ($asymmetric instanceof DataEncryption) {
112 11
            $this->asymmetricCipherSource = $asymmetric;
113
        } else {
114 2
            throw new \RuntimeException('No asymmetric encryption service has been set.');
115
        }
116
117 11
        if ($symmetric instanceof DataEncryption) {
118 11
            $this->symmetricCipherSource = $symmetric;
119
        } else {
120 2
            throw new \RuntimeException('No symmetric encryption service has been set.');
121
        }
122
123 11
        $this->randomnessSource = new DefaultRandomnessSource();
124 11
        $this->keyedDigestionSource = null;
125
    }
126
127
    /**
128
     * Container destructor.
129
     */
130 11
    public function __destruct()
131
    {
132 11
        unset($this->randomnessSource, $this->keyedDigestionSource);
133 11
        unset($this->symmetricCipherSource, $this->asymmetricCipherSource);
134
    }
135
136
    /**
137
     * Container cloning via deep copy.
138
     */
139 2
    public function __clone()
140
    {
141 2
        $this->randomnessSource = clone $this->randomnessSource;
142 2
        $this->symmetricCipherSource = clone $this->symmetricCipherSource;
143 2
        $this->asymmetricCipherSource = clone $this->asymmetricCipherSource;
144
145 2
        if ($this->keyedDigestionSource !== null) {
146 2
            $this->keyedDigestionSource = clone $this->keyedDigestionSource;
147
        }
148
    }
149
150
    /**
151
     * Seals the envelope with the secured information inside.
152
     *
153
     * @param string $plainData The plain message information.
154
     *
155
     * @return EnvelopeStructure The sealed envelope object.
156
     * @throws \Exception Validation errors.
157
     */
158 8
    public function sealEnvelope($plainData)
159
    {
160 8
        $key = $this->randomnessSource->getBytes(64);
161 8
        $iv = $this->randomnessSource->getBytes(64);
162
163 8
        $this->symmetricCipherSource->setSecretKey($key)->setInitializationVector($iv);
164
165 8
        $cipherData = $this->symmetricCipherSource->encryptData($plainData);
166 7
        $key = $this->asymmetricCipherSource->encryptData($key);
167 7
        $iv = $this->asymmetricCipherSource->encryptData($iv);
168 7
        $macTag = isset($this->keyedDigestionSource) ? $this->keyedDigestionSource->hashData($cipherData) : '';
169
170 7
        return new EnvelopeStructure($key, $iv, $cipherData, $macTag);
171
    }
172
173
    /**
174
     * Opens the envelope and extracts secured information from it.
175
     *
176
     * @param EnvelopeStructure $envelopeData The sealed envelope object.
177
     *
178
     * @return string The plain message information.
179
     * @throws \Exception Validation errors.
180
     */
181 4
    public function openEnvelope(EnvelopeStructure $envelopeData)
182
    {
183 4
        $key = $this->asymmetricCipherSource->decryptData($envelopeData->key);
184 4
        $iv = $this->asymmetricCipherSource->decryptData($envelopeData->iv);
185
186 4
        $this->symmetricCipherSource->setSecretKey($key)->setInitializationVector($iv);
187
188 4
        if (isset($this->keyedDigestionSource) && isset($envelopeData->authenticationTag)) {
189 4
            if (!$this->keyedDigestionSource->verifyHash($envelopeData->cipherData, $envelopeData->authenticationTag)) {
190 2
                throw new \RuntimeException('Wrong MAC tag, the data has been tampered with or defected.');
191
            }
192
        }
193
194 2
        return $this->symmetricCipherSource->decryptData($envelopeData->cipherData);
195
    }
196
}
197