1<?php
2
3if (class_exists('ParagonIE_Sodium_Core_ChaCha20_Ctx', false)) {
4 return;
5}
6
7/**
8 * Class ParagonIE_Sodium_Core32_ChaCha20_Ctx
9 */
10class ParagonIE_Sodium_Core32_ChaCha20_Ctx extends ParagonIE_Sodium_Core32_Util implements ArrayAccess
11{
12 /**
13 * @var SplFixedArray internally, <int, ParagonIE_Sodium_Core32_Int32>
14 */
15 protected $container;
16
17 /**
18 * ParagonIE_Sodium_Core_ChaCha20_Ctx constructor.
19 *
20 * @internal You should not use this directly from another application
21 *
22 * @param string $key ChaCha20 key.
23 * @param string $iv Initialization Vector (a.k.a. nonce).
24 * @param string $counter The initial counter value.
25 * Defaults to 8 0x00 bytes.
26 * @throws InvalidArgumentException
27 * @throws SodiumException
28 * @throws TypeError
29 */
30 public function __construct($key = '', $iv = '', $counter = '')
31 {
32 if (self::strlen($key) !== 32) {
33 throw new InvalidArgumentException('ChaCha20 expects a 256-bit key.');
34 }
35 if (self::strlen($iv) !== 8) {
36 throw new InvalidArgumentException('ChaCha20 expects a 64-bit nonce.');
37 }
38 $this->container = new SplFixedArray(16);
39
40 /* "expand 32-byte k" as per ChaCha20 spec */
41 $this->container[0] = new ParagonIE_Sodium_Core32_Int32(array(0x6170, 0x7865));
42 $this->container[1] = new ParagonIE_Sodium_Core32_Int32(array(0x3320, 0x646e));
43 $this->container[2] = new ParagonIE_Sodium_Core32_Int32(array(0x7962, 0x2d32));
44 $this->container[3] = new ParagonIE_Sodium_Core32_Int32(array(0x6b20, 0x6574));
45
46 $this->container[4] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 0, 4));
47 $this->container[5] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 4, 4));
48 $this->container[6] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 8, 4));
49 $this->container[7] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 12, 4));
50 $this->container[8] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 16, 4));
51 $this->container[9] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 20, 4));
52 $this->container[10] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 24, 4));
53 $this->container[11] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($key, 28, 4));
54
55 if (empty($counter)) {
56 $this->container[12] = new ParagonIE_Sodium_Core32_Int32();
57 $this->container[13] = new ParagonIE_Sodium_Core32_Int32();
58 } else {
59 $this->container[12] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($counter, 0, 4));
60 $this->container[13] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($counter, 4, 4));
61 }
62 $this->container[14] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 0, 4));
63 $this->container[15] = ParagonIE_Sodium_Core32_Int32::fromReverseString(self::substr($iv, 4, 4));
64 }
65
66 /**
67 * @internal You should not use this directly from another application
68 *
69 * @param int $offset
70 * @param int|ParagonIE_Sodium_Core32_Int32 $value
71 * @return void
72 */
73 #[ReturnTypeWillChange]
74 public function offsetSet($offset, $value)
75 {
76 if (!is_int($offset)) {
77 throw new InvalidArgumentException('Expected an integer');
78 }
79 if ($value instanceof ParagonIE_Sodium_Core32_Int32) {
80 /*
81 } elseif (is_int($value)) {
82 $value = ParagonIE_Sodium_Core32_Int32::fromInt($value);
83 */
84 } else {
85 throw new InvalidArgumentException('Expected an integer');
86 }
87 $this->container[$offset] = $value;
88 }
89
90 /**
91 * @internal You should not use this directly from another application
92 *
93 * @param int $offset
94 * @return bool
95 * @psalm-suppress MixedArrayOffset
96 */
97 #[ReturnTypeWillChange]
98 public function offsetExists($offset)
99 {
100 return isset($this->container[$offset]);
101 }
102
103 /**
104 * @internal You should not use this directly from another application
105 *
106 * @param int $offset
107 * @return void
108 * @psalm-suppress MixedArrayOffset
109 */
110 #[ReturnTypeWillChange]
111 public function offsetUnset($offset)
112 {
113 unset($this->container[$offset]);
114 }
115
116 /**
117 * @internal You should not use this directly from another application
118 *
119 * @param int $offset
120 * @return mixed|null
121 * @psalm-suppress MixedArrayOffset
122 */
123 #[ReturnTypeWillChange]
124 public function offsetGet($offset)
125 {
126 return isset($this->container[$offset])
127 ? $this->container[$offset]
128 : null;
129 }
130}
131