Completed
Push — master ( d865ae...34c801 )
by Charles
03:27
created

Request::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 2
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace ncryptf;
4
5
use ncryptf\Keypair;
6
use InvalidArgumentException;
7
use SodiumException;
8
9
class Request
10
{
11
    /**
12
     * Sodium CryptoBox Keypair
13
     *
14
     * @var string
15
     */
16
    private $keypair;
17
18
    /**
19
     * 24 byte nonce
20
     *
21
     * @var string
22
     */
23
    private $nonce;
24
25
    /**
26
     * Constructor
27
     *
28
     * @param string $secretKey The 32 byte secret key
29
     * @param string $publicKey The 32 byte public keyy
30
     * 
31
     * @throws InvalidArguementException
32
     */
33
    public function __construct(string $secretKey, string $publicKey)
34
    {
35
        try {
36
            $this->keypair = \sodium_crypto_box_keypair_from_secretkey_and_publickey(
37
                $secretKey,
38
                $publicKey
39
            );
40
        } catch (SodiumException $e) {
41
            throw new InvalidArgumentException($e->getMessage());
42
        }
43
    }
44
45
    /**
46
     * Encrypts a request body
47
     * 
48
     * @param string $request       The raw HTTP request as a string
49
     * @param int    $version       Version to generate, defaults to 2
50
     * @param string $signatureKey  32 byte signature key
51
     * @param string $nonce         Optional nonce. If not provided, a 24 byte nonce will be generated
52
     * @return string
53
     * 
54
     * @throws InvalidArguementException
55
     */
56
    public function encrypt(string $request, string $signatureKey = null, string $nonce = null, int $version = 2) : string
57
    {
58
        $this->nonce = $nonce ?? \random_bytes(SODIUM_CRYPTO_BOX_NONCEBYTES);
59
60
        if ($version === 2) {
61
            if ($signatureKey === null || strlen($signatureKey) !== \SODIUM_CRYPTO_SIGN_SECRETKEYBYTES) {
62
                throw new InvalidArgumentException;
63
            }
64
65
            // Version 2 payloads consist of a 4 byte version header marker, 24 byte nonce, 32 byte public key, x byte payload, 32 byte signature public key, 64 byte signature, followed by a 64 byte checksum
66
            $version = \pack('h*', 'DE259002');
67
            $body = $this->encryptBody($request, $this->nonce);
68
            $publicKey = \sodium_crypto_box_publickey($this->keypair);
69
            $sigPubKey = \sodium_crypto_sign_publickey_from_secretkey($signatureKey);
70
            $payload = $version . $this->nonce . $publicKey . $body . $sigPubKey . $this->sign($request, $signatureKey);
71
            $checksum = sodium_crypto_generichash($payload, $this->nonce, 64);
72
73
            return $payload . $checksum;
74
        }
75
76
        // Version 1 payload is just a single sodium crypto box
77
        return $this->encryptBody($request, $this->nonce);
78
    }
79
80
    /**
81
     * Encrypts a request
82
     *
83
     * @param string $request   The raw HTTP request as a string
84
     * @param string $nonce     Optional nonce. If not provided, a 24 byte nonce will be generated
85
     * @return string
86
     * 
87
     * @throws InvalidArguementException
88
     */
89
    private function encryptBody(string $request, string $nonce) : string
0 ignored issues
show
Unused Code introduced by
The parameter $nonce is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

89
    private function encryptBody(string $request, /** @scrutinizer ignore-unused */ string $nonce) : string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
90
    {
91
        try {
92
            return \sodium_crypto_box(
93
                $request,
94
                $this->nonce,
95
                $this->keypair
96
            );
97
        } catch (SodiumException $e) {
98
            throw new InvalidArgumentException($e->getMessage());
99
        }
100
    }
101
102
    /**
103
     * Creates a detached signature for the keypair
104
     *
105
     * @param string $request
106
     * @param string $secretKey
107
     * @return string
108
     * 
109
     * @throws InvalidArguementException
110
     */
111
    public function sign(string $request, string $secretKey) : string
112
    {
113
        try {
114
            return \sodium_crypto_sign_detached(
115
                $request,
116
                $secretKey
117
            );
118
        } catch (SodiumException $e) {
119
            throw new InvalidArgumentException($e->getMessage());
120
        }
121
    }
122
123
    /**
124
     * Returns the nonce used
125
     *
126
     * @return string
127
     */
128
    public function getNonce() : string
129
    {
130
        return $this->nonce;
131
    }
132
}
133