Skip to content

Commit 309d461

Browse files
committed
Add onetimeauth functions
1 parent ef8dcbd commit 309d461

File tree

6 files changed

+167
-1
lines changed

6 files changed

+167
-1
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ PHP NEWS
191191
- Sodium:
192192
. Add support for AEGIS-128L and AEGIS-256 (jedisct1)
193193
. Enable AES-GCM on aarch64 with the ARM crypto extensions (jedisct1)
194+
. Add sodium_crypto_onetimeauth_* functions for one-time Poly1305
195+
MAC generation and verification (Ayesh Karunaratne)
194196

195197
- Standard:
196198
. Implement GH-12188 (Indication for the int size in phpinfo()). (timwolla)

UPGRADING

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,12 @@ PHP 8.4 UPGRADE NOTES
435435
that was introduced in libsodium 1.0.19.
436436
. sodium_crypto_aead_aes256gcm_*() functions are now enabled on aarch64 CPUs
437437
with the ARM cryptographic extensions.
438+
. Added sodium_crypto_onetimeauth(), sodium_crypto_onetimeauth_keygen(), and
439+
sodium_crypto_onetimeauth_verify() functions for one-time Message
440+
Authentication Code, key generation, and verification. These MACs are
441+
based on Poly1305, and is 16 bytes long. Due to its output size,
442+
Poly1305 is recommended for online protocols, exchanging many small
443+
messages, rather than for authenticating very large files.
438444

439445
- Standard:
440446
. Added the http_get_last_response_headers() and
@@ -541,6 +547,10 @@ PHP 8.4 UPGRADE NOTES
541547
- Sockets:
542548
. SO_EXCLUSIVEADDRUSE (Windows only).
543549

550+
- Sodium:
551+
. SODIUM_CRYPTO_ONETIMEAUTH_BYTES
552+
. SODIUM_CRYPTO_ONETIMEAUTH_KEYBYTES
553+
544554
- XML:
545555
. Added XML_OPTION_PARSE_HUGE to allow large inputs in xml_parse and
546556
xml_parse_into_struct.

ext/sodium/libsodium.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2942,6 +2942,68 @@ PHP_FUNCTION(sodium_crypto_auth_verify)
29422942
RETURN_TRUE;
29432943
}
29442944

2945+
PHP_FUNCTION(sodium_crypto_onetimeauth)
2946+
{
2947+
zend_string *mac;
2948+
char *key;
2949+
char *msg;
2950+
size_t msg_len;
2951+
size_t key_len;
2952+
2953+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss",
2954+
&msg, &msg_len,
2955+
&key, &key_len) == FAILURE) {
2956+
sodium_remove_param_values_from_backtrace(EG(exception));
2957+
RETURN_THROWS();
2958+
}
2959+
if (key_len != crypto_onetimeauth_KEYBYTES) {
2960+
zend_argument_error(sodium_exception_ce, 2, "must be SODIUM_CRYPTO_ONETIMEAUTH_KEYBYTES bytes long");
2961+
RETURN_THROWS();
2962+
}
2963+
mac = zend_string_alloc(crypto_onetimeauth_BYTES, 0);
2964+
if (crypto_onetimeauth((unsigned char *) ZSTR_VAL(mac),
2965+
(const unsigned char *) msg, msg_len,
2966+
(const unsigned char *) key) != 0) {
2967+
zend_throw_exception(sodium_exception_ce, "internal error", 0);
2968+
RETURN_THROWS();
2969+
}
2970+
ZSTR_VAL(mac)[crypto_onetimeauth_KEYBYTES] = 0;
2971+
2972+
RETURN_STR(mac);
2973+
}
2974+
2975+
PHP_FUNCTION(sodium_crypto_onetimeauth_verify)
2976+
{
2977+
char *mac;
2978+
char *key;
2979+
char *msg;
2980+
size_t mac_len;
2981+
size_t msg_len;
2982+
size_t key_len;
2983+
2984+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
2985+
&mac, &mac_len,
2986+
&msg, &msg_len,
2987+
&key, &key_len) == FAILURE) {
2988+
sodium_remove_param_values_from_backtrace(EG(exception));
2989+
RETURN_THROWS();
2990+
}
2991+
if (key_len != crypto_onetimeauth_KEYBYTES) {
2992+
zend_argument_error(sodium_exception_ce, 3, "must be SODIUM_CRYPTO_ONETIMEAUTH_KEYBYTES bytes long");
2993+
RETURN_THROWS();
2994+
}
2995+
if (mac_len != crypto_onetimeauth_BYTES) {
2996+
zend_argument_error(sodium_exception_ce, 1, "must be SODIUM_CRYPTO_ONETIMEAUTH_BYTES bytes long");
2997+
RETURN_THROWS();
2998+
}
2999+
if (crypto_onetimeauth_verify((const unsigned char *) mac,
3000+
(const unsigned char *) msg, msg_len,
3001+
(const unsigned char *) key) != 0) {
3002+
RETURN_FALSE;
3003+
}
3004+
RETURN_TRUE;
3005+
}
3006+
29453007
PHP_FUNCTION(sodium_crypto_sign_ed25519_sk_to_curve25519)
29463008
{
29473009
zend_string *ecdhkey;
@@ -3103,6 +3165,17 @@ PHP_FUNCTION(sodium_crypto_auth_keygen)
31033165
RETURN_STRINGL((const char *) key, sizeof key);
31043166
}
31053167

3168+
PHP_FUNCTION(sodium_crypto_onetimeauth_keygen)
3169+
{
3170+
unsigned char key[crypto_onetimeauth_KEYBYTES];
3171+
3172+
if (zend_parse_parameters_none() == FAILURE) {
3173+
RETURN_THROWS();
3174+
}
3175+
randombytes_buf(key, sizeof key);
3176+
RETURN_STRINGL((const char *) key, sizeof key);
3177+
}
3178+
31063179
PHP_FUNCTION(sodium_crypto_generichash_keygen)
31073180
{
31083181
unsigned char key[crypto_generichash_KEYBYTES];

ext/sodium/libsodium.stub.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,16 @@
158158
* @cvalue crypto_auth_KEYBYTES
159159
*/
160160
const SODIUM_CRYPTO_AUTH_KEYBYTES = UNKNOWN;
161+
/**
162+
* @var int
163+
* @cvalue crypto_onetimeauth_BYTES
164+
*/
165+
const SODIUM_CRYPTO_ONETIMEAUTH_BYTES = UNKNOWN;
166+
/**
167+
* @var int
168+
* @cvalue crypto_onetimeauth_KEYBYTES
169+
*/
170+
const SODIUM_CRYPTO_ONETIMEAUTH_KEYBYTES = UNKNOWN;
161171
/**
162172
* @var int
163173
* @cvalue crypto_box_SEALBYTES
@@ -595,6 +605,12 @@ function sodium_crypto_auth_keygen(): string {}
595605

596606
function sodium_crypto_auth_verify(string $mac, string $message, #[\SensitiveParameter] string $key): bool {}
597607

608+
function sodium_crypto_onetimeauth(string $message, #[\SensitiveParameter] string $key): string {}
609+
610+
function sodium_crypto_onetimeauth_keygen(): string {}
611+
612+
function sodium_crypto_onetimeauth_verify(string $mac, string $message, #[\SensitiveParameter] string $key): bool {}
613+
598614
function sodium_crypto_box(#[\SensitiveParameter] string $message, string $nonce, #[\SensitiveParameter] string $key_pair): string {}
599615

600616
function sodium_crypto_box_keypair(): string {}

ext/sodium/libsodium_arginfo.h

Lines changed: 19 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
--TEST--
2+
Tests for libsodium onetimeauth functionality
3+
--EXTENSIONS--
4+
sodium
5+
--FILE--
6+
<?php
7+
$msg = random_bytes(1000);
8+
$key = sodium_crypto_onetimeauth_keygen();
9+
$mac = sodium_crypto_onetimeauth($msg, $key);
10+
11+
// This should validate
12+
var_dump(sodium_crypto_onetimeauth_verify($mac, $msg, $key));
13+
14+
$bad_key = random_bytes(SODIUM_CRYPTO_ONETIMEAUTH_KEYBYTES - 1);
15+
try {
16+
$mac = sodium_crypto_onetimeauth($msg, $bad_key);
17+
echo 'Fail!', PHP_EOL;
18+
} catch (SodiumException $ex) {
19+
echo $ex->getMessage(), PHP_EOL;
20+
}
21+
22+
// Flip the first bit
23+
$badmsg = $msg;
24+
$badmsg[0] = \chr(\ord($badmsg[0]) ^ 0x80);
25+
var_dump(sodium_crypto_onetimeauth_verify($mac, $badmsg, $key));
26+
27+
// Let's flip a bit pseudo-randomly
28+
$badmsg = $msg;
29+
$badmsg[$i=mt_rand(0, 999)] = \chr(
30+
\ord($msg[$i]) ^ (
31+
1 << mt_rand(0, 7)
32+
)
33+
);
34+
35+
var_dump(sodium_crypto_onetimeauth_verify($mac, $badmsg, $key));
36+
37+
// Now let's change a bit in the MAC
38+
$badmac = $mac;
39+
$badmac[0] = \chr(\ord($badmac[0]) ^ 0x80);
40+
var_dump(sodium_crypto_onetimeauth_verify($badmac, $msg, $key));
41+
?>
42+
--EXPECT--
43+
bool(true)
44+
sodium_crypto_onetimeauth(): Argument #2 ($key) must be SODIUM_CRYPTO_ONETIMEAUTH_KEYBYTES bytes long
45+
bool(false)
46+
bool(false)
47+
bool(false)

0 commit comments

Comments
 (0)