PBES1   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 126
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 9
eloc 33
dl 0
loc 126
c 0
b 0
f 0
ccs 32
cts 32
cp 1
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A encrypt() 0 5 1
A encryptWithKey() 0 8 2
A decryptWithKey() 0 11 3
A kdf() 0 3 1
A decrypt() 0 5 1
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace Sop\PKCS5;
6
7
use Sop\CryptoBridge\Crypto;
8
use Sop\CryptoTypes\AlgorithmIdentifier\Cipher\CipherAlgorithmIdentifier;
9
use Sop\PKCS5\HashFunc\HashFunc;
10
use Sop\PKCS5\PBEKD\PBEKDF;
11
use Sop\PKCS5\PBEKD\PBEKDF1;
12
13
/**
14
 * Implements password-based encryption scheme #1.
15
 *
16
 * @see https://tools.ietf.org/html/rfc2898#section-6.1
17
 */
18
class PBES1 extends PBEScheme
19
{
20
    /**
21
     * Hash functor.
22
     *
23
     * @var HashFunc
24
     */
25
    protected $_hashFunc;
26
27
    /**
28
     * Cipher algorithm.
29
     *
30
     * @var CipherAlgorithmIdentifier
31
     */
32
    protected $_cipher;
33
34
    /**
35
     * Salt.
36
     *
37
     * @var string
38
     */
39
    protected $_salt;
40
41
    /**
42
     * Iteration count.
43
     *
44
     * @var int
45
     */
46
    protected $_iterationCount;
47
48
    /**
49
     * Crypto engine.
50
     *
51
     * @var Crypto
52
     */
53
    protected $_crypto;
54
55
    /**
56
     * Padding instance.
57
     *
58
     * @var Padding
59
     */
60
    protected $_padding;
61
62
    /**
63
     * Constructor.
64
     *
65
     * @param HashFunc                  $hash_func       Hash function
66
     * @param CipherAlgorithmIdentifier $cipher          Cipher algorithm
67
     * @param string                    $salt            Salt
68
     * @param int                       $iteration_count Iteration count
69
     * @param null|Crypto               $crypto          Crypto implementation,
70
     *                                                   use default if not set
71
     */
72 15
    public function __construct(HashFunc $hash_func,
73
        CipherAlgorithmIdentifier $cipher, string $salt, int $iteration_count,
74
        ?Crypto $crypto = null)
75
    {
76 15
        $this->_hashFunc = $hash_func;
77 15
        $this->_cipher = $cipher;
78 15
        $this->_salt = $salt;
79 15
        $this->_iterationCount = $iteration_count;
80 15
        $this->_crypto = $crypto ?? Crypto::getDefault();
81 15
        $this->_padding = new Padding(8);
82 15
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87 7
    public function encrypt(string $data, string $password): string
88
    {
89 7
        $key = $this->kdf()->derive($password, $this->_salt,
90 7
            $this->_iterationCount, 16);
91 7
        return $this->encryptWithKey($data, $key);
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     *
97
     * @throws \UnexpectedValueException If key length is invalid
98
     */
99 9
    public function encryptWithKey(string $data, string $key): string
100
    {
101 9
        if (16 !== strlen($key)) {
102 1
            throw new \UnexpectedValueException('Invalid key length.');
103
        }
104 8
        $algo = $this->_cipher->withInitializationVector(substr($key, 8, 8));
105 8
        return $this->_crypto->encrypt($this->_padding->add($data),
106 8
            substr($key, 0, 8), $algo);
107
    }
108
109
    /**
110
     * {@inheritdoc}
111
     */
112 7
    public function decrypt(string $data, string $password): string
113
    {
114 7
        $key = $this->kdf()->derive($password, $this->_salt,
115 7
            $this->_iterationCount, 16);
116 7
        return $this->decryptWithKey($data, $key);
117
    }
118
119
    /**
120
     * {@inheritdoc}
121
     *
122
     * @throws \UnexpectedValueException If decryption fails
123
     */
124 10
    public function decryptWithKey(string $data, string $key): string
125
    {
126 10
        if (16 !== strlen($key)) {
127 1
            throw new \UnexpectedValueException('Invalid key length.');
128
        }
129
        try {
130 9
            $algo = $this->_cipher->withInitializationVector(substr($key, 8, 8));
131 9
            $str = $this->_crypto->decrypt($data, substr($key, 0, 8), $algo);
132 8
            return $this->_padding->remove($str);
133 1
        } catch (\RuntimeException $e) {
134 1
            throw new \UnexpectedValueException('Decryption failed.', 0, $e);
135
        }
136
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141 9
    public function kdf(): PBEKDF
142
    {
143 9
        return new PBEKDF1($this->_hashFunc);
144
    }
145
}
146