Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
Box
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
6 / 6
10
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 validateNonce
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 getNonce
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 getKeyPair
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 encrypt
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 decrypt
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
1<?php declare(strict_types=1);
2/*
3 * This file is part of Aplus Framework Crypto Library.
4 *
5 * (c) Natan Felles <natanfelles@gmail.com>
6 *
7 * For the full copyright and license information, please view the LICENSE
8 * file that was distributed with this source code.
9 */
10namespace Framework\Crypto;
11
12use LengthException;
13use LogicException;
14use SensitiveParameter;
15use SodiumException;
16
17/**
18 * Class Box.
19 *
20 * @package crypto
21 */
22class Box
23{
24    use BoxTrait;
25
26    protected string $secretKey;
27    protected string $publicKey;
28    protected ?string $nonce;
29
30    /**
31     * Box constructor.
32     *
33     * @param string $secretKey
34     * @param string $publicKey
35     * @param string|null $nonce
36     *
37     * @see BoxTrait::makePublicKey()
38     * @see BoxTrait::makeSecretKey()
39     * @see BoxTrait::makeNonce()
40     *
41     * @throws LengthException if nonce is set has not the required length
42     */
43    public function __construct(
44        #[SensitiveParameter] string $secretKey,
45        #[SensitiveParameter] string $publicKey,
46        #[SensitiveParameter] string $nonce = null
47    ) {
48        $this->secretKey = $secretKey;
49        $this->publicKey = $publicKey;
50        if ($nonce !== null) {
51            $this->validateNonce($nonce);
52        }
53        $this->nonce = $nonce;
54    }
55
56    /**
57     * Validates a nonce.
58     *
59     * @param string $nonce
60     *
61     * @throws LengthException if nonce has not the required length
62     */
63    protected function validateNonce(#[SensitiveParameter] string $nonce) : void
64    {
65        $length = \mb_strlen($nonce, '8bit');
66        if ($length !== \SODIUM_CRYPTO_BOX_NONCEBYTES) {
67            throw new LengthException(
68                'Box nonce has not the required length (24 bytes), '
69                . $length . ' given'
70            );
71        }
72    }
73
74    /**
75     * @param string|null $nonce
76     *
77     * @throws LengthException if nonce is set and has not the required length
78     * @throws LogicException if nonce param is null and nonce was not set in
79     * constructor
80     *
81     * @return string
82     */
83    protected function getNonce(#[SensitiveParameter] ?string $nonce) : string
84    {
85        if ($nonce !== null) {
86            $this->validateNonce($nonce);
87            return $nonce;
88        }
89        if ($this->nonce === null) {
90            throw new LogicException('Nonce was not set');
91        }
92        return $this->nonce;
93    }
94
95    /**
96     * Gets the keypair from the secret and public keys.
97     *
98     * @throws SodiumException
99     *
100     * @return string
101     */
102    protected function getKeyPair() : string
103    {
104        return \sodium_crypto_box_keypair_from_secretkey_and_publickey(
105            $this->secretKey,
106            $this->publicKey
107        );
108    }
109
110    /**
111     * Encrypts a box message.
112     *
113     * @param string $message
114     * @param string|null $nonce The message nonce or null to use the nonce set
115     * int the constructor
116     *
117     * @throws LengthException if nonce is set and has not the required length
118     * @throws LogicException if nonce param is null and nonce was not set in
119     * the constructor
120     * @throws SodiumException
121     *
122     * @return string
123     */
124    public function encrypt(
125        #[SensitiveParameter] string $message,
126        #[SensitiveParameter] string $nonce = null
127    ) : string {
128        return \sodium_crypto_box(
129            $message,
130            $this->getNonce($nonce),
131            $this->getKeyPair()
132        );
133    }
134
135    /**
136     * Decrypts a box message ciphertext.
137     *
138     * @param string $ciphertext
139     * @param string|null $nonce The message nonce or null to use the nonce set
140     * int the constructor
141     *
142     * @throws LengthException if nonce is set and has not the required length
143     * @throws LogicException if nonce param is null and nonce was not set in
144     * the constructor
145     * @throws SodiumException
146     *
147     * @return false|string
148     */
149    public function decrypt(
150        #[SensitiveParameter] string $ciphertext,
151        #[SensitiveParameter] string $nonce = null
152    ) : false | string {
153        return \sodium_crypto_box_open(
154            $ciphertext,
155            $this->getNonce($nonce),
156            $this->getKeyPair()
157        );
158    }
159}