|
1 <?php |
|
2 |
|
3 if (!defined('SODIUM_COMPAT_AEGIS_C0')) { |
|
4 define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62"); |
|
5 } |
|
6 if (!defined('SODIUM_COMPAT_AEGIS_C1')) { |
|
7 define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd"); |
|
8 } |
|
9 |
|
10 class ParagonIE_Sodium_Core_AEGIS128L extends ParagonIE_Sodium_Core_AES |
|
11 { |
|
12 /** |
|
13 * @param string $ct |
|
14 * @param string $tag |
|
15 * @param string $ad |
|
16 * @param string $key |
|
17 * @param string $nonce |
|
18 * @return string |
|
19 * @throws SodiumException |
|
20 */ |
|
21 public static function decrypt($ct, $tag, $ad, $key, $nonce) |
|
22 { |
|
23 $state = self::init($key, $nonce); |
|
24 $ad_blocks = (self::strlen($ad) + 31) >> 5; |
|
25 for ($i = 0; $i < $ad_blocks; ++$i) { |
|
26 $ai = self::substr($ad, $i << 5, 32); |
|
27 if (self::strlen($ai) < 32) { |
|
28 $ai = str_pad($ai, 32, "\0", STR_PAD_RIGHT); |
|
29 } |
|
30 $state->absorb($ai); |
|
31 } |
|
32 |
|
33 $msg = ''; |
|
34 $cn = self::strlen($ct) & 31; |
|
35 $ct_blocks = self::strlen($ct) >> 5; |
|
36 for ($i = 0; $i < $ct_blocks; ++$i) { |
|
37 $msg .= $state->dec(self::substr($ct, $i << 5, 32)); |
|
38 } |
|
39 if ($cn) { |
|
40 $start = $ct_blocks << 5; |
|
41 $msg .= $state->decPartial(self::substr($ct, $start, $cn)); |
|
42 } |
|
43 $expected_tag = $state->finalize( |
|
44 self::strlen($ad) << 3, |
|
45 self::strlen($msg) << 3 |
|
46 ); |
|
47 if (!self::hashEquals($expected_tag, $tag)) { |
|
48 try { |
|
49 // The RFC says to erase msg, so we shall try: |
|
50 ParagonIE_Sodium_Compat::memzero($msg); |
|
51 } catch (SodiumException $ex) { |
|
52 // Do nothing if we cannot memzero |
|
53 } |
|
54 throw new SodiumException('verification failed'); |
|
55 } |
|
56 return $msg; |
|
57 } |
|
58 |
|
59 /** |
|
60 * @param string $msg |
|
61 * @param string $ad |
|
62 * @param string $key |
|
63 * @param string $nonce |
|
64 * @return array |
|
65 * |
|
66 * @throws SodiumException |
|
67 */ |
|
68 public static function encrypt($msg, $ad, $key, $nonce) |
|
69 { |
|
70 $state = self::init($key, $nonce); |
|
71 // ad_blocks = Split(ZeroPad(ad, 256), 256) |
|
72 // for ai in ad_blocks: |
|
73 // Absorb(ai) |
|
74 $ad_len = self::strlen($ad); |
|
75 $msg_len = self::strlen($msg); |
|
76 $ad_blocks = ($ad_len + 31) >> 5; |
|
77 for ($i = 0; $i < $ad_blocks; ++$i) { |
|
78 $ai = self::substr($ad, $i << 5, 32); |
|
79 if (self::strlen($ai) < 32) { |
|
80 $ai = str_pad($ai, 32, "\0", STR_PAD_RIGHT); |
|
81 } |
|
82 $state->absorb($ai); |
|
83 } |
|
84 |
|
85 // msg_blocks = Split(ZeroPad(msg, 256), 256) |
|
86 // for xi in msg_blocks: |
|
87 // ct = ct || Enc(xi) |
|
88 $ct = ''; |
|
89 $msg_blocks = ($msg_len + 31) >> 5; |
|
90 for ($i = 0; $i < $msg_blocks; ++$i) { |
|
91 $xi = self::substr($msg, $i << 5, 32); |
|
92 if (self::strlen($xi) < 32) { |
|
93 $xi = str_pad($xi, 32, "\0", STR_PAD_RIGHT); |
|
94 } |
|
95 $ct .= $state->enc($xi); |
|
96 } |
|
97 // tag = Finalize(|ad|, |msg|) |
|
98 // ct = Truncate(ct, |msg|) |
|
99 $tag = $state->finalize( |
|
100 $ad_len << 3, |
|
101 $msg_len << 3 |
|
102 ); |
|
103 // return ct and tag |
|
104 return array( |
|
105 self::substr($ct, 0, $msg_len), |
|
106 $tag |
|
107 ); |
|
108 } |
|
109 |
|
110 /** |
|
111 * @param string $key |
|
112 * @param string $nonce |
|
113 * @return ParagonIE_Sodium_Core_AEGIS_State128L |
|
114 */ |
|
115 public static function init($key, $nonce) |
|
116 { |
|
117 return ParagonIE_Sodium_Core_AEGIS_State128L::init($key, $nonce); |
|
118 } |
|
119 } |