diff options
-rw-r--r-- | ext/sodium/libsodium.c | 245 | ||||
-rw-r--r-- | ext/sodium/php_libsodium.h | 7 | ||||
-rw-r--r-- | ext/sodium/tests/crypto_kx.phpt | 47 |
3 files changed, 234 insertions, 65 deletions
diff --git a/ext/sodium/libsodium.c b/ext/sodium/libsodium.c index 34bf7d4a2e..a176485a8c 100644 --- a/ext/sodium/libsodium.c +++ b/ext/sodium/libsodium.c @@ -159,6 +159,16 @@ ZEND_BEGIN_ARG_INFO_EX(AI_MaybeKeyAndLength, 0, 0, 0) ZEND_ARG_INFO(0, length) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(AI_KXClientSession, 0, 0, 2) + ZEND_ARG_INFO(0, client_keypair) + ZEND_ARG_INFO(0, server_key) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(AI_KXServerSession, 0, 0, 2) + ZEND_ARG_INFO(0, server_keypair) + ZEND_ARG_INFO(0, client_key) +ZEND_END_ARG_INFO() + #if defined(HAVE_CRYPTO_AEAD_AES256GCM) && defined(crypto_aead_aes256gcm_KEYBYTES) && \ (defined(__amd64) || defined(__amd64__) || defined(__x86_64__) || defined(__i386__) || \ defined(_M_AMD64) || defined(_M_IX86)) @@ -195,7 +205,12 @@ const zend_function_entry sodium_functions[] = { PHP_FE(sodium_crypto_box_seal_open, AI_StringAndKey) #endif PHP_FE(sodium_crypto_box_secretkey, AI_Key) - PHP_FE(sodium_crypto_kx, AI_FourStrings) + PHP_FE(sodium_crypto_kx_keypair, AI_None) + PHP_FE(sodium_crypto_kx_publickey, AI_Key) + PHP_FE(sodium_crypto_kx_secretkey, AI_Key) + PHP_FE(sodium_crypto_kx_seed_keypair, AI_String) + PHP_FE(sodium_crypto_kx_client_session_keys, AI_KXClientSession) + PHP_FE(sodium_crypto_kx_server_session_keys, AI_KXServerSession) PHP_FE(sodium_crypto_generichash, AI_StringAndMaybeKeyAndLength) PHP_FE(sodium_crypto_generichash_init, AI_MaybeKeyAndLength) PHP_FE(sodium_crypto_generichash_update, AI_StateByReferenceAndString) @@ -368,12 +383,23 @@ PHP_MINIT_FUNCTION(sodium) crypto_box_NONCEBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_BOX_SEEDBYTES", crypto_box_SEEDBYTES, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KX_BYTES", - crypto_kx_BYTES, CONST_CS | CONST_PERSISTENT); +#ifndef crypto_kx_SEEDBYTES +# define crypto_kx_SEEDBYTES 32 +# define crypto_kx_SESSIONKEYBYTES 32 +# define crypto_kx_PUBLICKEYBYTES 32 +# define crypto_kx_SECRETKEYBYTES 32 +#endif + REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KX_SEEDBYTES", + crypto_kx_SEEDBYTES, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KX_SESSIONKEYBYTES", + crypto_kx_SESSIONKEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KX_PUBLICKEYBYTES", crypto_kx_PUBLICKEYBYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KX_SECRETKEYBYTES", crypto_kx_SECRETKEYBYTES, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_KX_KEYPAIRBYTES", + crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES, + CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_GENERICHASH_BYTES", crypto_generichash_BYTES, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SODIUM_CRYPTO_GENERICHASH_BYTES_MIN", @@ -2480,56 +2506,197 @@ PHP_FUNCTION(sodium_crypto_scalarmult) RETURN_STR(q); } -PHP_FUNCTION(sodium_crypto_kx) +PHP_FUNCTION(sodium_crypto_kx_seed_keypair) +{ + unsigned char *sk; + unsigned char *pk; + unsigned char *seed; + size_t seed_len; + zend_string *keypair; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", + &seed, &seed_len) == FAILURE) { + return; + } + if (seed_len != crypto_kx_SEEDBYTES) { + zend_throw_exception(sodium_exception_ce, "seed must be CRYPTO_KX_SEEDBYTES bytes", 0); + return; + } + (void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_PUBLICKEYBYTES ? 1 : -1]); + (void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_SECRETKEYBYTES ? 1 : -1]); + keypair = zend_string_alloc(crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES, 0); + sk = (unsigned char *) ZSTR_VAL(keypair); + pk = sk + crypto_kx_SECRETKEYBYTES; + crypto_generichash(sk, crypto_kx_SECRETKEYBYTES, + seed, crypto_kx_SEEDBYTES, NULL, 0); + if (crypto_scalarmult_base(pk, sk) != 0) { + zend_throw_exception(sodium_exception_ce, "internal error", 0); + return; + } + ZSTR_VAL(keypair)[crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES] = 0; + RETURN_STR(keypair); +} + +PHP_FUNCTION(sodium_crypto_kx_keypair) +{ + unsigned char *sk; + unsigned char *pk; + zend_string *keypair; + + keypair = zend_string_alloc(crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES, 0); + sk = (unsigned char *) ZSTR_VAL(keypair); + pk = sk + crypto_kx_SECRETKEYBYTES; + randombytes_buf(sk, crypto_kx_SECRETKEYBYTES); + if (crypto_scalarmult_base(pk, sk) != 0) { + zend_throw_exception(sodium_exception_ce, "internal error", 0); + return; + } + RETURN_STR(keypair); +} + +PHP_FUNCTION(sodium_crypto_kx_secretkey) +{ + zend_string *secretkey; + unsigned char *keypair; + size_t keypair_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", + &keypair, &keypair_len) == FAILURE) { + return; + } + if (keypair_len != + crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "keypair should be CRYPTO_KX_KEYPAIRBYTES bytes", + 0); + return; + } + secretkey = zend_string_alloc(crypto_kx_SECRETKEYBYTES, 0); + memcpy(ZSTR_VAL(secretkey), keypair, crypto_kx_SECRETKEYBYTES); + ZSTR_VAL(secretkey)[crypto_kx_SECRETKEYBYTES] = 0; + + RETURN_STR(secretkey); +} + +PHP_FUNCTION(sodium_crypto_kx_publickey) +{ + zend_string *publickey; + unsigned char *keypair; + size_t keypair_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", + &keypair, &keypair_len) == FAILURE) { + return; + } + if (keypair_len != + crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, + "keypair should be CRYPTO_KX_KEYPAIRBYTES bytes", + 0); + return; + } + publickey = zend_string_alloc(crypto_kx_PUBLICKEYBYTES, 0); + memcpy(ZSTR_VAL(publickey), keypair + crypto_kx_SECRETKEYBYTES, + crypto_kx_PUBLICKEYBYTES); + ZSTR_VAL(publickey)[crypto_kx_PUBLICKEYBYTES] = 0; + + RETURN_STR(publickey); +} + +PHP_FUNCTION(sodium_crypto_kx_client_session_keys) { crypto_generichash_state h; - unsigned char q[crypto_scalarmult_BYTES]; - zend_string *sharedkey; - unsigned char *client_publickey; - unsigned char *publickey; - unsigned char *secretkey; - unsigned char *server_publickey; - size_t client_publickey_len; - size_t publickey_len; - size_t secretkey_len; - size_t server_publickey_len; + unsigned char q[crypto_scalarmult_BYTES]; + unsigned char *keypair; + unsigned char *client_sk; + unsigned char *client_pk; + unsigned char *server_pk; + unsigned char session_keys[2 * crypto_kx_SESSIONKEYBYTES]; + size_t keypair_len; + size_t server_pk_len; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssss", - &secretkey, &secretkey_len, - &publickey, &publickey_len, - &client_publickey, &client_publickey_len, - &server_publickey, &server_publickey_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", + &keypair, &keypair_len, + &server_pk, &server_pk_len) == FAILURE) { return; } - if (secretkey_len != crypto_kx_SECRETKEYBYTES) { - zend_throw_exception(sodium_exception_ce, "crypto_kx(): secret key must be CRYPTO_KX_SECRETKEY bytes", 0); + if (keypair_len != crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, "keypair must be CRYPTO_KX_KEYPAIRBYTES bytes", 0); return; } - if (publickey_len != crypto_kx_PUBLICKEYBYTES || - client_publickey_len != crypto_kx_PUBLICKEYBYTES || - server_publickey_len != crypto_kx_PUBLICKEYBYTES) { - zend_throw_exception(sodium_exception_ce, "crypto_kx(): public keys must be CRYPTO_KX_PUBLICKEY bytes", 0); + if (server_pk_len != crypto_kx_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, "public keys must be CRYPTO_KX_PUBLICKEYBYTES bytes", 0); return; } - (void) sizeof(int[crypto_scalarmult_SCALARBYTES == - crypto_kx_PUBLICKEYBYTES ? 1 : -1]); - (void) sizeof(int[crypto_scalarmult_SCALARBYTES == - crypto_kx_SECRETKEYBYTES ? 1 : -1]); - if (crypto_scalarmult(q, secretkey, publickey) != 0) { - zend_throw_exception(sodium_exception_ce, "crypto_kx(): internal error", 0); + client_sk = &keypair[0]; + client_pk = &keypair[crypto_kx_SECRETKEYBYTES]; + (void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_PUBLICKEYBYTES ? 1 : -1]); + (void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_SECRETKEYBYTES ? 1 : -1]); + if (crypto_scalarmult(q, client_sk, server_pk) != 0) { + zend_throw_exception(sodium_exception_ce, "internal error", 0); return; } - sharedkey = zend_string_alloc(crypto_kx_BYTES, 0); - crypto_generichash_init(&h, NULL, 0U, crypto_generichash_BYTES); + crypto_generichash_init(&h, NULL, 0U, 2 * crypto_kx_SESSIONKEYBYTES); crypto_generichash_update(&h, q, sizeof q); sodium_memzero(q, sizeof q); - crypto_generichash_update(&h, client_publickey, client_publickey_len); - crypto_generichash_update(&h, server_publickey, server_publickey_len); - crypto_generichash_final(&h, (unsigned char *) ZSTR_VAL(sharedkey), - crypto_kx_BYTES); - ZSTR_VAL(sharedkey)[crypto_kx_BYTES] = 0; + crypto_generichash_update(&h, client_pk, crypto_kx_PUBLICKEYBYTES); + crypto_generichash_update(&h, server_pk, crypto_kx_PUBLICKEYBYTES); + crypto_generichash_final(&h, session_keys, 2 * crypto_kx_SESSIONKEYBYTES); + array_init(return_value); + add_next_index_stringl(return_value, + (const char *) session_keys, + crypto_kx_SESSIONKEYBYTES); + add_next_index_stringl(return_value, + (const char *) session_keys + crypto_kx_SESSIONKEYBYTES, + crypto_kx_SESSIONKEYBYTES); +} - RETURN_STR(sharedkey); +PHP_FUNCTION(sodium_crypto_kx_server_session_keys) +{ + crypto_generichash_state h; + unsigned char q[crypto_scalarmult_BYTES]; + unsigned char *keypair; + unsigned char *server_sk; + unsigned char *server_pk; + unsigned char *client_pk; + unsigned char session_keys[2 * crypto_kx_SESSIONKEYBYTES]; + size_t keypair_len; + size_t client_pk_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", + &keypair, &keypair_len, + &client_pk, &client_pk_len) == FAILURE) { + return; + } + if (keypair_len != crypto_kx_SECRETKEYBYTES + crypto_kx_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, "keypair must be CRYPTO_KX_KEYPAIRBYTES bytes", 0); + return; + } + if (client_pk_len != crypto_kx_PUBLICKEYBYTES) { + zend_throw_exception(sodium_exception_ce, "public keys must be CRYPTO_KX_PUBLICKEYBYTES bytes", 0); + return; + } + server_sk = &keypair[0]; + server_pk = &keypair[crypto_kx_SECRETKEYBYTES]; + (void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_PUBLICKEYBYTES ? 1 : -1]); + (void) sizeof(int[crypto_scalarmult_SCALARBYTES == crypto_kx_SECRETKEYBYTES ? 1 : -1]); + if (crypto_scalarmult(q, server_sk, client_pk) != 0) { + zend_throw_exception(sodium_exception_ce, "internal error", 0); + return; + } + crypto_generichash_init(&h, NULL, 0U, 2 * crypto_kx_SESSIONKEYBYTES); + crypto_generichash_update(&h, q, sizeof q); + sodium_memzero(q, sizeof q); + crypto_generichash_update(&h, client_pk, crypto_kx_PUBLICKEYBYTES); + crypto_generichash_update(&h, server_pk, crypto_kx_PUBLICKEYBYTES); + crypto_generichash_final(&h, session_keys, 2 * crypto_kx_SESSIONKEYBYTES); + array_init(return_value); + add_next_index_stringl(return_value, + (const char *) session_keys + crypto_kx_SESSIONKEYBYTES, + crypto_kx_SESSIONKEYBYTES); + add_next_index_stringl(return_value, + (const char *) session_keys, + crypto_kx_SESSIONKEYBYTES); } PHP_FUNCTION(sodium_crypto_auth) diff --git a/ext/sodium/php_libsodium.h b/ext/sodium/php_libsodium.h index 93d92e3e03..6e6e3fbe2d 100644 --- a/ext/sodium/php_libsodium.h +++ b/ext/sodium/php_libsodium.h @@ -59,7 +59,12 @@ PHP_FUNCTION(sodium_crypto_generichash); PHP_FUNCTION(sodium_crypto_generichash_final); PHP_FUNCTION(sodium_crypto_generichash_init); PHP_FUNCTION(sodium_crypto_generichash_update); -PHP_FUNCTION(sodium_crypto_kx); +PHP_FUNCTION(sodium_crypto_kx_client_session_keys); +PHP_FUNCTION(sodium_crypto_kx_keypair); +PHP_FUNCTION(sodium_crypto_kx_publickey); +PHP_FUNCTION(sodium_crypto_kx_secretkey); +PHP_FUNCTION(sodium_crypto_kx_seed_keypair); +PHP_FUNCTION(sodium_crypto_kx_server_session_keys); PHP_FUNCTION(sodium_crypto_pwhash); PHP_FUNCTION(sodium_crypto_pwhash_str); PHP_FUNCTION(sodium_crypto_pwhash_str_verify); diff --git a/ext/sodium/tests/crypto_kx.phpt b/ext/sodium/tests/crypto_kx.phpt index ef8c5f7a63..a1dd00a0a7 100644 --- a/ext/sodium/tests/crypto_kx.phpt +++ b/ext/sodium/tests/crypto_kx.phpt @@ -4,34 +4,31 @@ Check for libsodium-based key exchange <?php if (!extension_loaded("sodium")) print "skip"; ?> --FILE-- <?php -$client_secretkey = sodium_hex2bin("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a"); -$client_publickey = sodium_crypto_box_publickey_from_secretkey($client_secretkey); +$client_seed = sodium_hex2bin('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'); +$client_keypair = sodium_crypto_kx_seed_keypair($client_seed); +$server_seed = sodium_hex2bin('f123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde0'); +$server_keypair = sodium_crypto_kx_seed_keypair($server_seed); -$server_secretkey = sodium_hex2bin("948f00e90a246fb5909f8648c2ac6f21515771235523266439e0d775ba0c3671"); -$server_publickey = sodium_crypto_box_publickey_from_secretkey($server_secretkey); +var_dump(sodium_bin2hex($client_keypair)); +var_dump(sodium_bin2hex($server_keypair)); -$shared_key_computed_by_client = - sodium_crypto_kx($client_secretkey, $server_publickey, - $client_publickey, $server_publickey); +$client_session_keys = + sodium_crypto_kx_client_session_keys($client_keypair, + sodium_crypto_kx_publickey($server_keypair)); -$shared_key_computed_by_server = - sodium_crypto_kx($server_secretkey, $client_publickey, - $client_publickey, $server_publickey); +$server_session_keys = + sodium_crypto_kx_server_session_keys($server_keypair, + sodium_crypto_kx_publickey($client_keypair)); -var_dump(sodium_bin2hex($shared_key_computed_by_client)); -var_dump(sodium_bin2hex($shared_key_computed_by_server)); -try { - sodium_crypto_kx( - substr($client_secretkey, 1), - $server_publickey, - $client_publickey, - $server_publickey - ); -} catch (SodiumException $ex) { - var_dump(true); -} +var_dump(sodium_bin2hex($client_session_keys[0])); +var_dump(sodium_bin2hex($server_session_keys[1])); +var_dump(sodium_bin2hex($client_session_keys[1])); +var_dump(sodium_bin2hex($server_session_keys[0])); ?> --EXPECT-- -string(64) "509a1580c2ee30c565317e29e0fea0b1c232e0ef3a7871d91dc64814b19a3bd2" -string(64) "509a1580c2ee30c565317e29e0fea0b1c232e0ef3a7871d91dc64814b19a3bd2" -bool(true) +string(128) "b85c84f9828524519d32b97cd3dda961fdba2dbf407ae4601e2129229aa463c224eaf70f070a925d6d5176f20495d4d90867624d9a10379e2a9aef0955c9bf4e" +string(128) "016e814c32b8b66225a403db45bf50fdd1966fb802c3115bf8aa90738c6a02de420ccdb534930fed9aaff12188bedc76e66251f399c404f2e4a15678fd4a484a" +string(64) "99a430e61d718b71979ebcea6735c4648bc828cfb456890aeda4b628b77d5ac7" +string(64) "99a430e61d718b71979ebcea6735c4648bc828cfb456890aeda4b628b77d5ac7" +string(64) "876bef865a5ab3f4ae569ea5aaefe5014c3ec22a558c0a2f0274aa9985bd328d" +string(64) "876bef865a5ab3f4ae569ea5aaefe5014c3ec22a558c0a2f0274aa9985bd328d" |