Upgrade/Install: Update sodium_compat to v1.12.1.
This includes a speedup for signature verification on most platforms and bugfixes for 32-bit platforms. Props paragoninitiativeenterprises, lukaswaudentio. Fixes #48371. Built from https://develop.svn.wordpress.org/trunk@46858 git-svn-id: http://core.svn.wordpress.org/trunk@46658 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
dd47d5aa81
commit
d4ef90b236
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* ISC License
|
||||
*
|
||||
* Copyright (c) 2016-2018
|
||||
* Copyright (c) 2016-2019
|
||||
* Paragon Initiative Enterprises <security at paragonie dot com>
|
||||
*
|
||||
* Copyright (c) 2013-2018
|
||||
* Copyright (c) 2013-2019
|
||||
* Frank Denis <j at pureftpd dot org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
|
|
|
@ -43,7 +43,17 @@ if (PHP_VERSION_ID >= 50300) {
|
|||
// unless PHP >= 5.3.0
|
||||
require_once dirname(__FILE__) . '/lib/namespaced.php';
|
||||
require_once dirname(__FILE__) . '/lib/sodium_compat.php';
|
||||
} else {
|
||||
require_once dirname(__FILE__) . '/src/PHP52/SplFixedArray.php';
|
||||
}
|
||||
if (PHP_VERSION_ID < 70200 || !extension_loaded('sodium')) {
|
||||
require_once dirname(__FILE__) . '/lib/php72compat.php';
|
||||
if (PHP_VERSION_ID >= 50300 && !defined('SODIUM_CRYPTO_SCALARMULT_BYTES')) {
|
||||
require_once dirname(__FILE__) . '/lib/php72compat_const.php';
|
||||
}
|
||||
if (PHP_VERSION_ID >= 70000) {
|
||||
assert(class_exists('ParagonIE_Sodium_Compat'), 'Possible filesystem/autoloader bug?');
|
||||
} else {
|
||||
assert(class_exists('ParagonIE_Sodium_Compat'));
|
||||
}
|
||||
require_once (dirname(__FILE__) . '/lib/php72compat.php');
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
"paragonie/random_compat": ">=1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^3|^4|^5"
|
||||
"phpunit/phpunit": "^3|^4|^5|^6|^7"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "PHP < 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security.",
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
namespace Sodium;
|
||||
|
||||
require_once dirname(dirname(__FILE__)) . '/autoload.php';
|
||||
|
||||
use ParagonIE_Sodium_Compat;
|
||||
|
||||
const CRYPTO_AEAD_AES256GCM_KEYBYTES = ParagonIE_Sodium_Compat::CRYPTO_AEAD_AES256GCM_KEYBYTES;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
require_once dirname(dirname(__FILE__)) . '/autoload.php';
|
||||
|
||||
if (PHP_VERSION_ID < 50300) {
|
||||
return;
|
||||
}
|
||||
|
@ -36,7 +38,7 @@ spl_autoload_register(function ($class) {
|
|||
// Replace the namespace prefix with the base directory, replace namespace
|
||||
// separators with directory separators in the relative class name, append
|
||||
// with .php
|
||||
$file = dirname(__DIR__) . '/namespaced/' . str_replace('\\', '/', $relative_class) . '.php';
|
||||
$file = dirname(dirname(__FILE__)) . '/namespaced/' . str_replace('\\', '/', $relative_class) . '.php';
|
||||
// if the file exists, require it
|
||||
if (file_exists($file)) {
|
||||
require_once $file;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?php
|
||||
|
||||
require_once dirname(dirname(__FILE__)) . '/autoload.php';
|
||||
|
||||
/**
|
||||
* This file will monkey patch the pure-PHP implementation in place of the
|
||||
* PECL functions and constants, but only if they do not already exist.
|
||||
|
@ -8,6 +10,10 @@
|
|||
* ParagonIE_Sodium_Compat method or class constant, respectively.
|
||||
*/
|
||||
foreach (array(
|
||||
'BASE64_VARIANT_ORIGINAL',
|
||||
'BASE64_VARIANT_ORIGINAL_NO_PADDING',
|
||||
'BASE64_VARIANT_URLSAFE',
|
||||
'BASE64_VARIANT_URLSAFE_NO_PADDING',
|
||||
'CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES',
|
||||
'CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES',
|
||||
'CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES',
|
||||
|
@ -29,10 +35,17 @@ foreach (array(
|
|||
'CRYPTO_BOX_MACBYTES',
|
||||
'CRYPTO_BOX_NONCEBYTES',
|
||||
'CRYPTO_BOX_SEEDBYTES',
|
||||
'CRYPTO_KDF_BYTES_MIN',
|
||||
'CRYPTO_KDF_BYTES_MAX',
|
||||
'CRYPTO_KDF_CONTEXTBYTES',
|
||||
'CRYPTO_KDF_KEYBYTES',
|
||||
'CRYPTO_KX_BYTES',
|
||||
'CRYPTO_KX_KEYPAIRBYTES',
|
||||
'CRYPTO_KX_PRIMITIVE',
|
||||
'CRYPTO_KX_SEEDBYTES',
|
||||
'CRYPTO_KX_PUBLICKEYBYTES',
|
||||
'CRYPTO_KX_SECRETKEYBYTES',
|
||||
'CRYPTO_KX_SESSIONKEYBYTES',
|
||||
'CRYPTO_GENERICHASH_BYTES',
|
||||
'CRYPTO_GENERICHASH_BYTES_MIN',
|
||||
'CRYPTO_GENERICHASH_BYTES_MAX',
|
||||
|
@ -56,6 +69,14 @@ foreach (array(
|
|||
'CRYPTO_SECRETBOX_KEYBYTES',
|
||||
'CRYPTO_SECRETBOX_MACBYTES',
|
||||
'CRYPTO_SECRETBOX_NONCEBYTES',
|
||||
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES',
|
||||
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES',
|
||||
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES',
|
||||
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH',
|
||||
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL',
|
||||
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY',
|
||||
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL',
|
||||
'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX',
|
||||
'CRYPTO_SIGN_BYTES',
|
||||
'CRYPTO_SIGN_SEEDBYTES',
|
||||
'CRYPTO_SIGN_PUBLICKEYBYTES',
|
||||
|
@ -68,11 +89,52 @@ foreach (array(
|
|||
'VERSION_STRING'
|
||||
) as $constant
|
||||
) {
|
||||
if (!defined("SODIUM_$constant")) {
|
||||
if (!defined("SODIUM_$constant") && defined("ParagonIE_Sodium_Compat::$constant")) {
|
||||
define("SODIUM_$constant", constant("ParagonIE_Sodium_Compat::$constant"));
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_callable('sodium_add')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::add()
|
||||
* @param string $val
|
||||
* @param string $addv
|
||||
* @return void
|
||||
* @throws SodiumException
|
||||
*/
|
||||
function sodium_add(&$val, $addv)
|
||||
{
|
||||
ParagonIE_Sodium_Compat::add($val, $addv);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_base642bin')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::bin2base64()
|
||||
* @param string $string
|
||||
* @param int $variant
|
||||
* @param string $ignore
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
* @throws TypeError
|
||||
*/
|
||||
function sodium_base642bin($string, $variant, $ignore ='')
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::base642bin($string, $variant, $ignore);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_bin2base64')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::bin2base64()
|
||||
* @param string $string
|
||||
* @param int $variant
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
* @throws TypeError
|
||||
*/
|
||||
function sodium_bin2base64($string, $variant)
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::bin2base64($string, $variant);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_bin2hex')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::hex2bin()
|
||||
|
@ -186,6 +248,7 @@ if (!is_callable('sodium_crypto_aead_chacha20poly1305_keygen')) {
|
|||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_keygen()
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_aead_chacha20poly1305_keygen()
|
||||
{
|
||||
|
@ -232,6 +295,7 @@ if (!is_callable('sodium_crypto_aead_chacha20poly1305_ietf_keygen')) {
|
|||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_keygen()
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_aead_chacha20poly1305_ietf_keygen()
|
||||
{
|
||||
|
@ -278,6 +342,7 @@ if (!is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_keygen')) {
|
|||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_keygen()
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_aead_xchacha20poly1305_ietf_keygen()
|
||||
{
|
||||
|
@ -302,6 +367,7 @@ if (!is_callable('sodium_crypto_auth_keygen')) {
|
|||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_auth_keygen()
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_auth_keygen()
|
||||
{
|
||||
|
@ -516,6 +582,7 @@ if (!is_callable('sodium_crypto_generichash_keygen')) {
|
|||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_generichash_keygen()
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_generichash_keygen()
|
||||
{
|
||||
|
@ -536,6 +603,37 @@ if (!is_callable('sodium_crypto_generichash_update')) {
|
|||
ParagonIE_Sodium_Compat::crypto_generichash_update($ctx, $message);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_kdf_keygen')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_kdf_keygen()
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_kdf_keygen()
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_kdf_keygen();
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_kdf_derive_from_key')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_kdf_derive_from_key()
|
||||
* @param int $subkey_len
|
||||
* @param int $subkey_id
|
||||
* @param string $context
|
||||
* @param string $key
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_kdf_derive_from_key($subkey_len, $subkey_id, $context, $key)
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_kdf_derive_from_key(
|
||||
$subkey_len,
|
||||
$subkey_id,
|
||||
$context,
|
||||
$key
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_kx')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_kx()
|
||||
|
@ -557,6 +655,73 @@ if (!is_callable('sodium_crypto_kx')) {
|
|||
);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_kx_seed_keypair')) {
|
||||
/**
|
||||
* @param string $seed
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_kx_seed_keypair($seed)
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_kx_seed_keypair($seed);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_kx_keypair')) {
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_kx_keypair()
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_kx_keypair();
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_kx_client_session_keys')) {
|
||||
/**
|
||||
* @param string $keypair
|
||||
* @param string $serverPublicKey
|
||||
* @return array{0: string, 1: string}
|
||||
* @throws SodiumException
|
||||
*/
|
||||
function sodium_crypto_kx_client_session_keys($keypair, $serverPublicKey)
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_kx_client_session_keys($keypair, $serverPublicKey);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_kx_server_session_keys')) {
|
||||
/**
|
||||
* @param string $keypair
|
||||
* @param string $clientPublicKey
|
||||
* @return array{0: string, 1: string}
|
||||
* @throws SodiumException
|
||||
*/
|
||||
function sodium_crypto_kx_server_session_keys($keypair, $clientPublicKey)
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_kx_server_session_keys($keypair, $clientPublicKey);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_kx_secretkey')) {
|
||||
/**
|
||||
* @param string $keypair
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_kx_secretkey($keypair)
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_kx_secretkey($keypair);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_kx_publickey')) {
|
||||
/**
|
||||
* @param string $keypair
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_kx_publickey($keypair)
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_kx_publickey($keypair);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_pwhash')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_pwhash()
|
||||
|
@ -590,6 +755,21 @@ if (!is_callable('sodium_crypto_pwhash_str')) {
|
|||
return ParagonIE_Sodium_Compat::crypto_pwhash_str($passwd, $opslimit, $memlimit);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_pwhash_str_needs_rehash')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_pwhash_str_needs_rehash()
|
||||
* @param string $hash
|
||||
* @param int $opslimit
|
||||
* @param int $memlimit
|
||||
* @return bool
|
||||
*
|
||||
* @throws SodiumException
|
||||
*/
|
||||
function sodium_crypto_pwhash_str_needs_rehash($hash, $opslimit, $memlimit)
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_pwhash_str_needs_rehash($hash, $opslimit, $memlimit);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_pwhash_str_verify')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_pwhash_str_verify()
|
||||
|
@ -696,6 +876,7 @@ if (!is_callable('sodium_crypto_secretbox_keygen')) {
|
|||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_secretbox_keygen()
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_secretbox_keygen()
|
||||
{
|
||||
|
@ -721,6 +902,77 @@ if (!is_callable('sodium_crypto_secretbox_open')) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_init_push')) {
|
||||
/**
|
||||
* @param string $key
|
||||
* @return array<int, string>
|
||||
* @throws SodiumException
|
||||
*/
|
||||
function sodium_crypto_secretstream_xchacha20poly1305_init_push($key)
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_init_push($key);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_push')) {
|
||||
/**
|
||||
* @param string $state
|
||||
* @param string $msg
|
||||
* @param string $aad
|
||||
* @param int $tag
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
*/
|
||||
function sodium_crypto_secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_push($state, $msg, $aad, $tag);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_init_pull')) {
|
||||
/**
|
||||
* @param string $header
|
||||
* @param string $key
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_secretstream_xchacha20poly1305_init_pull($header, $key)
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_init_pull($header, $key);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_pull')) {
|
||||
/**
|
||||
* @param string $state
|
||||
* @param string $cipher
|
||||
* @param string $aad
|
||||
* @return bool|array{0: string, 1: int}
|
||||
* @throws SodiumException
|
||||
*/
|
||||
function sodium_crypto_secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '')
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_pull($state, $cipher, $aad);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_rekey')) {
|
||||
/**
|
||||
* @param string $state
|
||||
* @return void
|
||||
* @throws SodiumException
|
||||
*/
|
||||
function sodium_crypto_secretstream_xchacha20poly1305_rekey(&$state)
|
||||
{
|
||||
ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_rekey($state);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_keygen')) {
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_secretstream_xchacha20poly1305_keygen()
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_keygen();
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_shorthash')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_shorthash()
|
||||
|
@ -739,6 +991,7 @@ if (!is_callable('sodium_crypto_shorthash_keygen')) {
|
|||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_shorthash_keygen()
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_shorthash_keygen()
|
||||
{
|
||||
|
@ -773,6 +1026,20 @@ if (!is_callable('sodium_crypto_sign_detached')) {
|
|||
return ParagonIE_Sodium_Compat::crypto_sign_detached($message, $sk);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_sign_keypair_from_secretkey_and_publickey')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_sign_keypair_from_secretkey_and_publickey()
|
||||
* @param string $sk
|
||||
* @param string $pk
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
* @throws TypeError
|
||||
*/
|
||||
function sodium_crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk)
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_crypto_sign_keypair')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_sign_keypair()
|
||||
|
@ -915,6 +1182,7 @@ if (!is_callable('sodium_crypto_stream_keygen')) {
|
|||
/**
|
||||
* @see ParagonIE_Sodium_Compat::crypto_stream_keygen()
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_crypto_stream_keygen()
|
||||
{
|
||||
|
@ -1019,6 +1287,34 @@ if (!is_callable('sodium_memzero')) {
|
|||
ParagonIE_Sodium_Compat::memzero($str);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_pad')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::pad()
|
||||
* @param string $unpadded
|
||||
* @param int $blockSize
|
||||
* @return int
|
||||
* @throws SodiumException
|
||||
* @throws TypeError
|
||||
*/
|
||||
function sodium_pad($unpadded, $blockSize)
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::pad($unpadded, $blockSize, true);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_unpad')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::pad()
|
||||
* @param string $padded
|
||||
* @param int $blockSize
|
||||
* @return int
|
||||
* @throws SodiumException
|
||||
* @throws TypeError
|
||||
*/
|
||||
function sodium_unpad($padded, $blockSize)
|
||||
{
|
||||
return ParagonIE_Sodium_Compat::unpad($padded, $blockSize, true);
|
||||
}
|
||||
}
|
||||
if (!is_callable('sodium_randombytes_buf')) {
|
||||
/**
|
||||
* @see ParagonIE_Sodium_Compat::randombytes_buf()
|
||||
|
@ -1049,6 +1345,7 @@ if (!is_callable('sodium_randombytes_random16')) {
|
|||
/**
|
||||
* @see ParagonIE_Sodium_Compat::randombytes_random16()
|
||||
* @return int
|
||||
* @throws Exception
|
||||
*/
|
||||
function sodium_randombytes_random16()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
const SODIUM_LIBRARY_MAJOR_VERSION = 9;
|
||||
const SODIUM_LIBRARY_MINOR_VERSION = 1;
|
||||
const SODIUM_LIBRARY_VERSION = '1.0.8';
|
||||
|
||||
const SODIUM_BASE64_VARIANT_ORIGINAL = 1;
|
||||
const SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING = 3;
|
||||
const SODIUM_BASE64_VARIANT_URLSAFE = 5;
|
||||
const SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING = 7;
|
||||
const SODIUM_CRYPTO_AEAD_AES256GCM_KEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_AEAD_AES256GCM_NSECBYTES = 0;
|
||||
const SODIUM_CRYPTO_AEAD_AES256GCM_NPUBBYTES = 12;
|
||||
const SODIUM_CRYPTO_AEAD_AES256GCM_ABYTES = 16;
|
||||
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES = 0;
|
||||
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES = 8;
|
||||
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_ABYTES = 16;
|
||||
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES = 0;
|
||||
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES = 12;
|
||||
const SODIUM_CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES = 16;
|
||||
const SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES = 0;
|
||||
const SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES = 24;
|
||||
const SODIUM_CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES = 16;
|
||||
const SODIUM_CRYPTO_AUTH_BYTES = 32;
|
||||
const SODIUM_CRYPTO_AUTH_KEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_BOX_SEALBYTES = 16;
|
||||
const SODIUM_CRYPTO_BOX_SECRETKEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_BOX_PUBLICKEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_BOX_KEYPAIRBYTES = 64;
|
||||
const SODIUM_CRYPTO_BOX_MACBYTES = 16;
|
||||
const SODIUM_CRYPTO_BOX_NONCEBYTES = 24;
|
||||
const SODIUM_CRYPTO_BOX_SEEDBYTES = 32;
|
||||
const SODIUM_CRYPTO_KDF_BYTES_MIN = 16;
|
||||
const SODIUM_CRYPTO_KDF_BYTES_MAX = 64;
|
||||
const SODIUM_CRYPTO_KDF_CONTEXTBYTES = 8;
|
||||
const SODIUM_CRYPTO_KDF_KEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_KX_BYTES = 32;
|
||||
const SODIUM_CRYPTO_KX_PRIMITIVE = 'x25519blake2b';
|
||||
const SODIUM_CRYPTO_KX_SEEDBYTES = 32;
|
||||
const SODIUM_CRYPTO_KX_KEYPAIRBYTES = 64;
|
||||
const SODIUM_CRYPTO_KX_PUBLICKEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_KX_SECRETKEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_KX_SESSIONKEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_GENERICHASH_BYTES = 32;
|
||||
const SODIUM_CRYPTO_GENERICHASH_BYTES_MIN = 16;
|
||||
const SODIUM_CRYPTO_GENERICHASH_BYTES_MAX = 64;
|
||||
const SODIUM_CRYPTO_GENERICHASH_KEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_GENERICHASH_KEYBYTES_MIN = 16;
|
||||
const SODIUM_CRYPTO_GENERICHASH_KEYBYTES_MAX = 64;
|
||||
const SODIUM_CRYPTO_PWHASH_SALTBYTES = 16;
|
||||
const SODIUM_CRYPTO_PWHASH_STRPREFIX = '$argon2id$';
|
||||
const SODIUM_CRYPTO_PWHASH_ALG_ARGON2I13 = 1;
|
||||
const SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13 = 2;
|
||||
const SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE = 33554432;
|
||||
const SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE = 4;
|
||||
const SODIUM_CRYPTO_PWHASH_MEMLIMIT_MODERATE = 134217728;
|
||||
const SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE = 6;
|
||||
const SODIUM_CRYPTO_PWHASH_MEMLIMIT_SENSITIVE = 536870912;
|
||||
const SODIUM_CRYPTO_PWHASH_OPSLIMIT_SENSITIVE = 8;
|
||||
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES = 32;
|
||||
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX = '$7$';
|
||||
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE = 534288;
|
||||
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE = 16777216;
|
||||
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE = 33554432;
|
||||
const SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE = 1073741824;
|
||||
const SODIUM_CRYPTO_SCALARMULT_BYTES = 32;
|
||||
const SODIUM_CRYPTO_SCALARMULT_SCALARBYTES = 32;
|
||||
const SODIUM_CRYPTO_SHORTHASH_BYTES = 8;
|
||||
const SODIUM_CRYPTO_SHORTHASH_KEYBYTES = 16;
|
||||
const SODIUM_CRYPTO_SECRETBOX_KEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_SECRETBOX_MACBYTES = 16;
|
||||
const SODIUM_CRYPTO_SECRETBOX_NONCEBYTES = 24;
|
||||
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES = 17;
|
||||
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES = 24;
|
||||
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH = 0;
|
||||
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL = 1;
|
||||
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY = 2;
|
||||
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL = 3;
|
||||
const SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX = 0x3fffffff80;
|
||||
const SODIUM_CRYPTO_SIGN_BYTES = 64;
|
||||
const SODIUM_CRYPTO_SIGN_SEEDBYTES = 32;
|
||||
const SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_SIGN_SECRETKEYBYTES = 64;
|
||||
const SODIUM_CRYPTO_SIGN_KEYPAIRBYTES = 96;
|
||||
const SODIUM_CRYPTO_STREAM_KEYBYTES = 32;
|
||||
const SODIUM_CRYPTO_STREAM_NONCEBYTES = 24;
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
namespace Sodium;
|
||||
|
||||
require_once dirname(dirname(__FILE__)) . '/autoload.php';
|
||||
|
||||
use ParagonIE_Sodium_Compat;
|
||||
|
||||
/**
|
||||
|
|
|
@ -49,6 +49,10 @@ class ParagonIE_Sodium_Compat
|
|||
const VERSION_STRING = 'polyfill-1.0.8';
|
||||
|
||||
// From libsodium
|
||||
const BASE64_VARIANT_ORIGINAL = 1;
|
||||
const BASE64_VARIANT_ORIGINAL_NO_PADDING = 3;
|
||||
const BASE64_VARIANT_URLSAFE = 5;
|
||||
const BASE64_VARIANT_URLSAFE_NO_PADDING = 7;
|
||||
const CRYPTO_AEAD_AES256GCM_KEYBYTES = 32;
|
||||
const CRYPTO_AEAD_AES256GCM_NSECBYTES = 0;
|
||||
const CRYPTO_AEAD_AES256GCM_NPUBBYTES = 12;
|
||||
|
@ -74,10 +78,17 @@ class ParagonIE_Sodium_Compat
|
|||
const CRYPTO_BOX_MACBYTES = 16;
|
||||
const CRYPTO_BOX_NONCEBYTES = 24;
|
||||
const CRYPTO_BOX_SEEDBYTES = 32;
|
||||
const CRYPTO_KDF_BYTES_MIN = 16;
|
||||
const CRYPTO_KDF_BYTES_MAX = 64;
|
||||
const CRYPTO_KDF_CONTEXTBYTES = 8;
|
||||
const CRYPTO_KDF_KEYBYTES = 32;
|
||||
const CRYPTO_KX_BYTES = 32;
|
||||
const CRYPTO_KX_PRIMITIVE = 'x25519blake2b';
|
||||
const CRYPTO_KX_SEEDBYTES = 32;
|
||||
const CRYPTO_KX_KEYPAIRBYTES = 64;
|
||||
const CRYPTO_KX_PUBLICKEYBYTES = 32;
|
||||
const CRYPTO_KX_SECRETKEYBYTES = 32;
|
||||
const CRYPTO_KX_SESSIONKEYBYTES = 32;
|
||||
const CRYPTO_GENERICHASH_BYTES = 32;
|
||||
const CRYPTO_GENERICHASH_BYTES_MIN = 16;
|
||||
const CRYPTO_GENERICHASH_BYTES_MAX = 64;
|
||||
|
@ -85,7 +96,7 @@ class ParagonIE_Sodium_Compat
|
|||
const CRYPTO_GENERICHASH_KEYBYTES_MIN = 16;
|
||||
const CRYPTO_GENERICHASH_KEYBYTES_MAX = 64;
|
||||
const CRYPTO_PWHASH_SALTBYTES = 16;
|
||||
const CRYPTO_PWHASH_STRPREFIX = '$argon2i$';
|
||||
const CRYPTO_PWHASH_STRPREFIX = '$argon2id$';
|
||||
const CRYPTO_PWHASH_ALG_ARGON2I13 = 1;
|
||||
const CRYPTO_PWHASH_ALG_ARGON2ID13 = 2;
|
||||
const CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE = 33554432;
|
||||
|
@ -107,6 +118,14 @@ class ParagonIE_Sodium_Compat
|
|||
const CRYPTO_SECRETBOX_KEYBYTES = 32;
|
||||
const CRYPTO_SECRETBOX_MACBYTES = 16;
|
||||
const CRYPTO_SECRETBOX_NONCEBYTES = 24;
|
||||
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES = 17;
|
||||
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES = 24;
|
||||
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES = 32;
|
||||
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH = 0;
|
||||
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL = 1;
|
||||
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY = 2;
|
||||
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL = 3;
|
||||
const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX = 0x3fffffff80;
|
||||
const CRYPTO_SIGN_BYTES = 64;
|
||||
const CRYPTO_SIGN_SEEDBYTES = 32;
|
||||
const CRYPTO_SIGN_PUBLICKEYBYTES = 32;
|
||||
|
@ -115,6 +134,110 @@ class ParagonIE_Sodium_Compat
|
|||
const CRYPTO_STREAM_KEYBYTES = 32;
|
||||
const CRYPTO_STREAM_NONCEBYTES = 24;
|
||||
|
||||
/**
|
||||
* Add two numbers (little-endian unsigned), storing the value in the first
|
||||
* parameter.
|
||||
*
|
||||
* This mutates $val.
|
||||
*
|
||||
* @param string $val
|
||||
* @param string $addv
|
||||
* @return void
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function add(&$val, $addv)
|
||||
{
|
||||
$val_len = ParagonIE_Sodium_Core_Util::strlen($val);
|
||||
$addv_len = ParagonIE_Sodium_Core_Util::strlen($addv);
|
||||
if ($val_len !== $addv_len) {
|
||||
throw new SodiumException('values must have the same length');
|
||||
}
|
||||
$A = ParagonIE_Sodium_Core_Util::stringToIntArray($val);
|
||||
$B = ParagonIE_Sodium_Core_Util::stringToIntArray($addv);
|
||||
|
||||
$c = 0;
|
||||
for ($i = 0; $i < $val_len; $i++) {
|
||||
$c += ($A[$i] + $B[$i]);
|
||||
$A[$i] = ($c & 0xff);
|
||||
$c >>= 8;
|
||||
}
|
||||
$val = ParagonIE_Sodium_Core_Util::intArrayToString($A);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $encoded
|
||||
* @param int $variant
|
||||
* @param string $ignore
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function base642bin($encoded, $variant, $ignore = '')
|
||||
{
|
||||
/* Type checks: */
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($encoded, 'string', 1);
|
||||
|
||||
/** @var string $encoded */
|
||||
$encoded = (string) $encoded;
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($encoded) === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Just strip before decoding
|
||||
if (!empty($ignore)) {
|
||||
$encoded = str_replace($ignore, '', $encoded);
|
||||
}
|
||||
|
||||
try {
|
||||
switch ($variant) {
|
||||
case self::BASE64_VARIANT_ORIGINAL:
|
||||
return ParagonIE_Sodium_Core_Base64_Original::decode($encoded, true);
|
||||
case self::BASE64_VARIANT_ORIGINAL_NO_PADDING:
|
||||
return ParagonIE_Sodium_Core_Base64_Original::decode($encoded, false);
|
||||
case self::BASE64_VARIANT_URLSAFE:
|
||||
return ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, true);
|
||||
case self::BASE64_VARIANT_URLSAFE_NO_PADDING:
|
||||
return ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, false);
|
||||
default:
|
||||
throw new SodiumException('invalid base64 variant identifier');
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
if ($ex instanceof SodiumException) {
|
||||
throw $ex;
|
||||
}
|
||||
throw new SodiumException('invalid base64 string');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $decoded
|
||||
* @param int $variant
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function bin2base64($decoded, $variant)
|
||||
{
|
||||
/* Type checks: */
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($decoded, 'string', 1);
|
||||
/** @var string $decoded */
|
||||
$decoded = (string) $decoded;
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($decoded) === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
switch ($variant) {
|
||||
case self::BASE64_VARIANT_ORIGINAL:
|
||||
return ParagonIE_Sodium_Core_Base64_Original::encode($decoded);
|
||||
case self::BASE64_VARIANT_ORIGINAL_NO_PADDING:
|
||||
return ParagonIE_Sodium_Core_Base64_Original::encodeUnpadded($decoded);
|
||||
case self::BASE64_VARIANT_URLSAFE:
|
||||
return ParagonIE_Sodium_Core_Base64_UrlSafe::encode($decoded);
|
||||
case self::BASE64_VARIANT_URLSAFE_NO_PADDING:
|
||||
return ParagonIE_Sodium_Core_Base64_UrlSafe::encodeUnpadded($decoded);
|
||||
default:
|
||||
throw new SodiumException('invalid base64 variant identifier');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache-timing-safe implementation of bin2hex().
|
||||
*
|
||||
|
@ -1310,6 +1433,7 @@ class ParagonIE_Sodium_Compat
|
|||
* @throws TypeError
|
||||
* @psalm-suppress MixedArgument
|
||||
* @psalm-suppress ReferenceConstraintViolation
|
||||
* @psalm-suppress ConflictingReferenceConstraint
|
||||
*/
|
||||
public static function crypto_generichash_final(&$ctx, $length = self::CRYPTO_GENERICHASH_BYTES)
|
||||
{
|
||||
|
@ -1324,6 +1448,14 @@ class ParagonIE_Sodium_Compat
|
|||
$func = '\\Sodium\\crypto_generichash_final';
|
||||
return (string) $func($ctx, $length);
|
||||
}
|
||||
if ($length < 1) {
|
||||
try {
|
||||
self::memzero($ctx);
|
||||
} catch (SodiumException $ex) {
|
||||
unset($ctx);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
if (PHP_INT_SIZE === 4) {
|
||||
$result = ParagonIE_Sodium_Crypto32::generichash_final($ctx, $length);
|
||||
} else {
|
||||
|
@ -1379,6 +1511,53 @@ class ParagonIE_Sodium_Compat
|
|||
return ParagonIE_Sodium_Crypto::generichash_init($key, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a BLAKE2b hashing context, for use in a streaming interface.
|
||||
*
|
||||
* @param string|null $key If specified must be a string between 16 and 64 bytes
|
||||
* @param int $length The size of the desired hash output
|
||||
* @param string $salt Salt (up to 16 bytes)
|
||||
* @param string $personal Personalization string (up to 16 bytes)
|
||||
* @return string A BLAKE2 hashing context, encoded as a string
|
||||
* (To be 100% compatible with ext/libsodium)
|
||||
* @throws SodiumException
|
||||
* @throws TypeError
|
||||
* @psalm-suppress MixedArgument
|
||||
*/
|
||||
public static function crypto_generichash_init_salt_personal(
|
||||
$key = '',
|
||||
$length = self::CRYPTO_GENERICHASH_BYTES,
|
||||
$salt = '',
|
||||
$personal = ''
|
||||
) {
|
||||
/* Type checks: */
|
||||
if (is_null($key)) {
|
||||
$key = '';
|
||||
}
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 1);
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2);
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3);
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($personal, 'string', 4);
|
||||
$salt = str_pad($salt, 16, "\0", STR_PAD_RIGHT);
|
||||
$personal = str_pad($personal, 16, "\0", STR_PAD_RIGHT);
|
||||
|
||||
/* Input validation: */
|
||||
if (!empty($key)) {
|
||||
/*
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
|
||||
throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.');
|
||||
}
|
||||
*/
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
|
||||
throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.');
|
||||
}
|
||||
}
|
||||
if (PHP_INT_SIZE === 4) {
|
||||
return ParagonIE_Sodium_Crypto32::generichash_init_salt_personal($key, $length, $salt, $personal);
|
||||
}
|
||||
return ParagonIE_Sodium_Crypto::generichash_init_salt_personal($key, $length, $salt, $personal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a BLAKE2b hashing context with additional data.
|
||||
*
|
||||
|
@ -1424,6 +1603,65 @@ class ParagonIE_Sodium_Compat
|
|||
return random_bytes(self::CRYPTO_GENERICHASH_KEYBYTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $subkey_len
|
||||
* @param int $subkey_id
|
||||
* @param string $context
|
||||
* @param string $key
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function crypto_kdf_derive_from_key(
|
||||
$subkey_len,
|
||||
$subkey_id,
|
||||
$context,
|
||||
$key
|
||||
) {
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($subkey_len, 'int', 1);
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($subkey_id, 'int', 2);
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($context, 'string', 3);
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
|
||||
$subkey_id = (int) $subkey_id;
|
||||
$subkey_len = (int) $subkey_len;
|
||||
$context = (string) $context;
|
||||
$key = (string) $key;
|
||||
|
||||
if ($subkey_len < self::CRYPTO_KDF_BYTES_MIN) {
|
||||
throw new SodiumException('subkey cannot be smaller than SODIUM_CRYPTO_KDF_BYTES_MIN');
|
||||
}
|
||||
if ($subkey_len > self::CRYPTO_KDF_BYTES_MAX) {
|
||||
throw new SodiumException('subkey cannot be larger than SODIUM_CRYPTO_KDF_BYTES_MAX');
|
||||
}
|
||||
if ($subkey_id < 0) {
|
||||
throw new SodiumException('subkey_id cannot be negative');
|
||||
}
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($context) !== self::CRYPTO_KDF_CONTEXTBYTES) {
|
||||
throw new SodiumException('context should be SODIUM_CRYPTO_KDF_CONTEXTBYTES bytes');
|
||||
}
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_KDF_KEYBYTES) {
|
||||
throw new SodiumException('key should be SODIUM_CRYPTO_KDF_KEYBYTES bytes');
|
||||
}
|
||||
|
||||
$salt = ParagonIE_Sodium_Core_Util::store64_le($subkey_id);
|
||||
$state = self::crypto_generichash_init_salt_personal(
|
||||
$key,
|
||||
$subkey_len,
|
||||
$salt,
|
||||
$context
|
||||
);
|
||||
return self::crypto_generichash_final($state, $subkey_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
* @throws Error
|
||||
*/
|
||||
public static function crypto_kdf_keygen()
|
||||
{
|
||||
return random_bytes(self::CRYPTO_KDF_KEYBYTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a key exchange, between a designated client and a server.
|
||||
*
|
||||
|
@ -1510,6 +1748,149 @@ class ParagonIE_Sodium_Compat
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $seed
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function crypto_kx_seed_keypair($seed)
|
||||
{
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1);
|
||||
|
||||
$seed = (string) $seed;
|
||||
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($seed) !== self::CRYPTO_KX_SEEDBYTES) {
|
||||
throw new SodiumException('seed must be SODIUM_CRYPTO_KX_SEEDBYTES bytes');
|
||||
}
|
||||
|
||||
$sk = self::crypto_generichash($seed, '', self::CRYPTO_KX_SECRETKEYBYTES);
|
||||
$pk = self::crypto_scalarmult_base($sk);
|
||||
return $sk . $pk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function crypto_kx_keypair()
|
||||
{
|
||||
$sk = self::randombytes_buf(self::CRYPTO_KX_SECRETKEYBYTES);
|
||||
$pk = self::crypto_scalarmult_base($sk);
|
||||
return $sk . $pk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $keypair
|
||||
* @param string $serverPublicKey
|
||||
* @return array{0: string, 1: string}
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function crypto_kx_client_session_keys($keypair, $serverPublicKey)
|
||||
{
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($serverPublicKey, 'string', 2);
|
||||
|
||||
$keypair = (string) $keypair;
|
||||
$serverPublicKey = (string) $serverPublicKey;
|
||||
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_KX_KEYPAIRBYTES) {
|
||||
throw new SodiumException('keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes');
|
||||
}
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($serverPublicKey) !== self::CRYPTO_KX_PUBLICKEYBYTES) {
|
||||
throw new SodiumException('public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes');
|
||||
}
|
||||
|
||||
$sk = self::crypto_kx_secretkey($keypair);
|
||||
$pk = self::crypto_kx_publickey($keypair);
|
||||
$h = self::crypto_generichash_init(null, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
|
||||
self::crypto_generichash_update($h, self::crypto_scalarmult($sk, $serverPublicKey));
|
||||
self::crypto_generichash_update($h, $pk);
|
||||
self::crypto_generichash_update($h, $serverPublicKey);
|
||||
$sessionKeys = self::crypto_generichash_final($h, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
|
||||
return array(
|
||||
ParagonIE_Sodium_Core_Util::substr(
|
||||
$sessionKeys,
|
||||
0,
|
||||
self::CRYPTO_KX_SESSIONKEYBYTES
|
||||
),
|
||||
ParagonIE_Sodium_Core_Util::substr(
|
||||
$sessionKeys,
|
||||
self::CRYPTO_KX_SESSIONKEYBYTES,
|
||||
self::CRYPTO_KX_SESSIONKEYBYTES
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $keypair
|
||||
* @param string $clientPublicKey
|
||||
* @return array{0: string, 1: string}
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function crypto_kx_server_session_keys($keypair, $clientPublicKey)
|
||||
{
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($clientPublicKey, 'string', 2);
|
||||
|
||||
$keypair = (string) $keypair;
|
||||
$clientPublicKey = (string) $clientPublicKey;
|
||||
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_KX_KEYPAIRBYTES) {
|
||||
throw new SodiumException('keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes');
|
||||
}
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($clientPublicKey) !== self::CRYPTO_KX_PUBLICKEYBYTES) {
|
||||
throw new SodiumException('public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes');
|
||||
}
|
||||
|
||||
$sk = self::crypto_kx_secretkey($keypair);
|
||||
$pk = self::crypto_kx_publickey($keypair);
|
||||
$h = self::crypto_generichash_init(null, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
|
||||
self::crypto_generichash_update($h, self::crypto_scalarmult($sk, $clientPublicKey));
|
||||
self::crypto_generichash_update($h, $clientPublicKey);
|
||||
self::crypto_generichash_update($h, $pk);
|
||||
$sessionKeys = self::crypto_generichash_final($h, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
|
||||
return array(
|
||||
ParagonIE_Sodium_Core_Util::substr(
|
||||
$sessionKeys,
|
||||
self::CRYPTO_KX_SESSIONKEYBYTES,
|
||||
self::CRYPTO_KX_SESSIONKEYBYTES
|
||||
),
|
||||
ParagonIE_Sodium_Core_Util::substr(
|
||||
$sessionKeys,
|
||||
0,
|
||||
self::CRYPTO_KX_SESSIONKEYBYTES
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $kp
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function crypto_kx_secretkey($kp)
|
||||
{
|
||||
return ParagonIE_Sodium_Core_Util::substr(
|
||||
$kp,
|
||||
0,
|
||||
self::CRYPTO_KX_SECRETKEYBYTES
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $kp
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function crypto_kx_publickey($kp)
|
||||
{
|
||||
return ParagonIE_Sodium_Core_Util::substr(
|
||||
$kp,
|
||||
self::CRYPTO_KX_SECRETKEYBYTES,
|
||||
self::CRYPTO_KX_PUBLICKEYBYTES
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $outlen
|
||||
* @param string $passwd
|
||||
|
@ -1592,6 +1973,36 @@ class ParagonIE_Sodium_Compat
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we need to rehash this password?
|
||||
*
|
||||
* @param string $hash
|
||||
* @param int $opslimit
|
||||
* @param int $memlimit
|
||||
* @return bool
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function crypto_pwhash_str_needs_rehash($hash, $opslimit, $memlimit)
|
||||
{
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 1);
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2);
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3);
|
||||
|
||||
// Just grab the first 4 pieces.
|
||||
$pieces = explode('$', (string) $hash);
|
||||
$prefix = implode('$', array_slice($pieces, 0, 4));
|
||||
|
||||
// Rebuild the expected header.
|
||||
/** @var int $ops */
|
||||
$ops = (int) $opslimit;
|
||||
/** @var int $mem */
|
||||
$mem = (int) $memlimit >> 10;
|
||||
$encoded = self::CRYPTO_PWHASH_STRPREFIX . 'v=19$m=' . $mem . ',t=' . $ops . ',p=1';
|
||||
|
||||
// Do they match? If so, we don't need to rehash, so return false.
|
||||
return !ParagonIE_Sodium_Core_Util::hashEquals($encoded, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $passwd
|
||||
* @param string $hash
|
||||
|
@ -1987,6 +2398,111 @@ class ParagonIE_Sodium_Compat
|
|||
return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return array<int, string> Returns a state and a header.
|
||||
* @throws Exception
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function crypto_secretstream_xchacha20poly1305_init_push($key)
|
||||
{
|
||||
if (PHP_INT_SIZE === 4) {
|
||||
return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_push($key);
|
||||
}
|
||||
return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_push($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $header
|
||||
* @param string $key
|
||||
* @return string Returns a state.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function crypto_secretstream_xchacha20poly1305_init_pull($header, $key)
|
||||
{
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($header) < self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES) {
|
||||
throw new SodiumException(
|
||||
'header size should be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES bytes'
|
||||
);
|
||||
}
|
||||
if (PHP_INT_SIZE === 4) {
|
||||
return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_pull($key, $header);
|
||||
}
|
||||
return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_pull($key, $header);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
* @param string $msg
|
||||
* @param string $aad
|
||||
* @param int $tag
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function crypto_secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
|
||||
{
|
||||
if (PHP_INT_SIZE === 4) {
|
||||
return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_push(
|
||||
$state,
|
||||
$msg,
|
||||
$aad,
|
||||
$tag
|
||||
);
|
||||
}
|
||||
return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_push(
|
||||
$state,
|
||||
$msg,
|
||||
$aad,
|
||||
$tag
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
* @param string $msg
|
||||
* @param string $aad
|
||||
* @return bool|array{0: string, 1: int}
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function crypto_secretstream_xchacha20poly1305_pull(&$state, $msg, $aad = '')
|
||||
{
|
||||
if (PHP_INT_SIZE === 4) {
|
||||
return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_pull(
|
||||
$state,
|
||||
$msg,
|
||||
$aad
|
||||
);
|
||||
}
|
||||
return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_pull(
|
||||
$state,
|
||||
$msg,
|
||||
$aad
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function crypto_secretstream_xchacha20poly1305_keygen()
|
||||
{
|
||||
return random_bytes(self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
* @return void
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function crypto_secretstream_xchacha20poly1305_rekey(&$state)
|
||||
{
|
||||
if (PHP_INT_SIZE === 4) {
|
||||
ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_rekey($state);
|
||||
} else {
|
||||
ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_rekey($state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a SipHash-2-4 hash of a message for a given key.
|
||||
*
|
||||
|
@ -2136,6 +2652,32 @@ class ParagonIE_Sodium_Compat
|
|||
return ParagonIE_Sodium_Core_Ed25519::keypair();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sk
|
||||
* @param string $pk
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk)
|
||||
{
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($sk, 'string', 1);
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($pk, 'string', 1);
|
||||
$sk = (string) $sk;
|
||||
$pk = (string) $pk;
|
||||
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($sk) !== self::CRYPTO_SIGN_SECRETKEYBYTES) {
|
||||
throw new SodiumException('secretkey should be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes');
|
||||
}
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($pk) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) {
|
||||
throw new SodiumException('publickey should be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes');
|
||||
}
|
||||
|
||||
if (self::useNewSodiumAPI()) {
|
||||
return sodium_crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk);
|
||||
}
|
||||
return $sk . $pk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an Ed25519 keypair from a seed.
|
||||
*
|
||||
|
@ -2624,6 +3166,9 @@ class ParagonIE_Sodium_Compat
|
|||
ParagonIE_Sodium_Core_Util::declareScalarType($left, 'string', 1);
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2);
|
||||
|
||||
if (self::useNewSodiumAPI()) {
|
||||
return sodium_memcmp($left, $right);
|
||||
}
|
||||
if (self::use_fallback('memcmp')) {
|
||||
return (int) call_user_func('\\Sodium\\memcmp', $left, $right);
|
||||
}
|
||||
|
@ -2668,6 +3213,158 @@ class ParagonIE_Sodium_Compat
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $unpadded
|
||||
* @param int $blockSize
|
||||
* @param bool $dontFallback
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function pad($unpadded, $blockSize, $dontFallback = false)
|
||||
{
|
||||
/* Type checks: */
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($unpadded, 'string', 1);
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($blockSize, 'int', 2);
|
||||
|
||||
$unpadded = (string) $unpadded;
|
||||
$blockSize = (int) $blockSize;
|
||||
|
||||
if (self::useNewSodiumAPI() && !$dontFallback) {
|
||||
return (string) sodium_pad($unpadded, $blockSize);
|
||||
}
|
||||
|
||||
if ($blockSize <= 0) {
|
||||
throw new SodiumException(
|
||||
'block size cannot be less than 1'
|
||||
);
|
||||
}
|
||||
$unpadded_len = ParagonIE_Sodium_Core_Util::strlen($unpadded);
|
||||
$xpadlen = ($blockSize - 1);
|
||||
if (($blockSize & ($blockSize - 1)) === 0) {
|
||||
$xpadlen -= $unpadded_len & ($blockSize - 1);
|
||||
} else {
|
||||
$xpadlen -= $unpadded_len % $blockSize;
|
||||
}
|
||||
|
||||
$xpadded_len = $unpadded_len + $xpadlen;
|
||||
$padded = str_repeat("\0", $xpadded_len - 1);
|
||||
if ($unpadded_len > 0) {
|
||||
$st = 1;
|
||||
$i = 0;
|
||||
$k = $unpadded_len;
|
||||
for ($j = 0; $j <= $xpadded_len; ++$j) {
|
||||
$i = (int) $i;
|
||||
$k = (int) $k;
|
||||
$st = (int) $st;
|
||||
if ($j >= $unpadded_len) {
|
||||
$padded[$j] = "\0";
|
||||
} else {
|
||||
$padded[$j] = $unpadded[$j];
|
||||
}
|
||||
/** @var int $k */
|
||||
$k -= $st;
|
||||
$st = (int) (~(
|
||||
(
|
||||
(
|
||||
($k >> 48)
|
||||
|
|
||||
($k >> 32)
|
||||
|
|
||||
($k >> 16)
|
||||
|
|
||||
$k
|
||||
) - 1
|
||||
) >> 16
|
||||
)
|
||||
) & 1;
|
||||
$i += $st;
|
||||
}
|
||||
}
|
||||
|
||||
$mask = 0;
|
||||
$tail = $xpadded_len;
|
||||
for ($i = 0; $i < $blockSize; ++$i) {
|
||||
# barrier_mask = (unsigned char)
|
||||
# (((i ^ xpadlen) - 1U) >> ((sizeof(size_t) - 1U) * CHAR_BIT));
|
||||
$barrier_mask = (($i ^ $xpadlen) -1) >> ((PHP_INT_SIZE << 3) - 1);
|
||||
# tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask);
|
||||
$padded[$tail - $i] = ParagonIE_Sodium_Core_Util::intToChr(
|
||||
(ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]) & $mask)
|
||||
|
|
||||
(0x80 & $barrier_mask)
|
||||
);
|
||||
# mask |= barrier_mask;
|
||||
$mask |= $barrier_mask;
|
||||
}
|
||||
return $padded;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $padded
|
||||
* @param int $blockSize
|
||||
* @param bool $dontFallback
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function unpad($padded, $blockSize, $dontFallback = false)
|
||||
{
|
||||
/* Type checks: */
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($padded, 'string', 1);
|
||||
ParagonIE_Sodium_Core_Util::declareScalarType($blockSize, 'int', 2);
|
||||
|
||||
$padded = (string) $padded;
|
||||
$blockSize = (int) $blockSize;
|
||||
|
||||
if (self::useNewSodiumAPI() && !$dontFallback) {
|
||||
return (string) sodium_unpad($padded, $blockSize);
|
||||
}
|
||||
if ($blockSize <= 0) {
|
||||
throw new SodiumException('block size cannot be less than 1');
|
||||
}
|
||||
$padded_len = ParagonIE_Sodium_Core_Util::strlen($padded);
|
||||
if ($padded_len < $blockSize) {
|
||||
throw new SodiumException('invalid padding');
|
||||
}
|
||||
|
||||
# tail = &padded[padded_len - 1U];
|
||||
$tail = $padded_len - 1;
|
||||
|
||||
$acc = 0;
|
||||
$valid = 0;
|
||||
$pad_len = 0;
|
||||
|
||||
$found = 0;
|
||||
for ($i = 0; $i < $blockSize; ++$i) {
|
||||
# c = tail[-i];
|
||||
$c = ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]);
|
||||
|
||||
# is_barrier =
|
||||
# (( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U;
|
||||
$is_barrier = (
|
||||
(
|
||||
($acc - 1) & ($pad_len - 1) & (($c ^ 80) - 1)
|
||||
) >> 7
|
||||
) & 1;
|
||||
$is_barrier &= ~$found;
|
||||
$found |= $is_barrier;
|
||||
|
||||
# acc |= c;
|
||||
$acc |= $c;
|
||||
|
||||
# pad_len |= i & (1U + ~is_barrier);
|
||||
$pad_len |= $i & (1 + ~$is_barrier);
|
||||
|
||||
# valid |= (unsigned char) is_barrier;
|
||||
$valid |= ($is_barrier & 0xff);
|
||||
}
|
||||
# unpadded_len = padded_len - 1U - pad_len;
|
||||
$unpadded_len = $padded_len - 1 - $pad_len;
|
||||
if ($valid !== 1) {
|
||||
throw new SodiumException('invalid padding');
|
||||
}
|
||||
return ParagonIE_Sodium_Core_Util::substr($padded, 0, $unpadded_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will sodium_compat run fast on the current hardware and PHP configuration?
|
||||
*
|
||||
|
|
|
@ -88,10 +88,10 @@ abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util
|
|||
{
|
||||
$l = ($x[1] + $y[1]) & 0xffffffff;
|
||||
return self::new64(
|
||||
$x[0] + $y[0] + (
|
||||
(int) ($x[0] + $y[0] + (
|
||||
($l < $x[1]) ? 1 : 0
|
||||
),
|
||||
$l
|
||||
)),
|
||||
(int) $l
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -132,8 +132,8 @@ abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util
|
|||
throw new SodiumException('y[1] is not an integer');
|
||||
}
|
||||
return self::new64(
|
||||
(int) ($x[0] ^ $y[0]),
|
||||
(int) ($x[1] ^ $y[1])
|
||||
(int) (($x[0] ^ $y[0]) & 0xffffffff),
|
||||
(int) (($x[1] ^ $y[1]) & 0xffffffff)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -299,12 +299,13 @@ abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util
|
|||
*/
|
||||
protected static function context()
|
||||
{
|
||||
$ctx = new SplFixedArray(5);
|
||||
$ctx = new SplFixedArray(6);
|
||||
$ctx[0] = new SplFixedArray(8); // h
|
||||
$ctx[1] = new SplFixedArray(2); // t
|
||||
$ctx[2] = new SplFixedArray(2); // f
|
||||
$ctx[3] = new SplFixedArray(256); // buf
|
||||
$ctx[4] = 0; // buflen
|
||||
$ctx[5] = 0; // last_node (uint8_t)
|
||||
|
||||
for ($i = 8; $i--;) {
|
||||
$ctx[0][$i] = self::$iv[$i];
|
||||
|
@ -550,6 +551,8 @@ abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util
|
|||
*
|
||||
* @param SplFixedArray|null $key
|
||||
* @param int $outlen
|
||||
* @param SplFixedArray|null $salt
|
||||
* @param SplFixedArray|null $personal
|
||||
* @return SplFixedArray
|
||||
* @throws SodiumException
|
||||
* @throws TypeError
|
||||
|
@ -559,8 +562,12 @@ abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util
|
|||
* @psalm-suppress MixedArrayAssignment
|
||||
* @psalm-suppress MixedArrayOffset
|
||||
*/
|
||||
public static function init($key = null, $outlen = 64)
|
||||
{
|
||||
public static function init(
|
||||
$key = null,
|
||||
$outlen = 64,
|
||||
$salt = null,
|
||||
$personal = null
|
||||
) {
|
||||
self::pseudoConstructor();
|
||||
$klen = 0;
|
||||
|
||||
|
@ -578,6 +585,7 @@ abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util
|
|||
$ctx = self::context();
|
||||
|
||||
$p = new SplFixedArray(64);
|
||||
// Zero our param buffer...
|
||||
for ($i = 64; --$i;) {
|
||||
$p[$i] = 0;
|
||||
}
|
||||
|
@ -587,10 +595,32 @@ abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util
|
|||
$p[2] = 1; // fanout
|
||||
$p[3] = 1; // depth
|
||||
|
||||
if ($salt instanceof SplFixedArray) {
|
||||
// salt: [32] through [47]
|
||||
for ($i = 0; $i < 16; ++$i) {
|
||||
$p[32 + $i] = (int) $salt[$i];
|
||||
}
|
||||
}
|
||||
if ($personal instanceof SplFixedArray) {
|
||||
// personal: [48] through [63]
|
||||
for ($i = 0; $i < 16; ++$i) {
|
||||
$p[48 + $i] = (int) $personal[$i];
|
||||
}
|
||||
}
|
||||
|
||||
$ctx[0][0] = self::xor64(
|
||||
$ctx[0][0],
|
||||
self::load64($p, 0)
|
||||
);
|
||||
if ($salt instanceof SplFixedArray || $personal instanceof SplFixedArray) {
|
||||
// We need to do what blake2b_init_param() does:
|
||||
for ($i = 1; $i < 8; ++$i) {
|
||||
$ctx[0][$i] = self::xor64(
|
||||
$ctx[0][$i],
|
||||
self::load64($p, $i << 3)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($klen > 0 && $key instanceof SplFixedArray) {
|
||||
$block = new SplFixedArray(128);
|
||||
|
@ -601,6 +631,7 @@ abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util
|
|||
$block[$i] = $key[$i];
|
||||
}
|
||||
self::update($ctx, $block, 128);
|
||||
$ctx[4] = 128;
|
||||
}
|
||||
|
||||
return $ctx;
|
||||
|
@ -693,7 +724,7 @@ abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util
|
|||
self::intToChr(($ctx4 >> 56) & 0xff)
|
||||
));
|
||||
# uint8_t last_node;
|
||||
return $str . "\x00";
|
||||
return $str . self::intToChr($ctx[5]) . str_repeat("\x00", 23);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -746,7 +777,6 @@ abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util
|
|||
# uint8_t buf[2 * 128];
|
||||
$ctx[3] = self::stringToSplFixedArray(self::substr($string, 96, 256));
|
||||
|
||||
|
||||
# uint8_t buf[2 * 128];
|
||||
$int = 0;
|
||||
for ($i = 0; $i < 8; ++$i) {
|
||||
|
|
|
@ -0,0 +1,213 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class ParagonIE_Sodium_Core_Base64
|
||||
*
|
||||
* Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
|
||||
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
|
||||
*
|
||||
* We have to copy/paste the contents into the variant files because PHP 5.2
|
||||
* doesn't support late static binding, and we have no better workaround
|
||||
* available that won't break PHP 7+. Therefore, we're forced to duplicate code.
|
||||
*/
|
||||
abstract class ParagonIE_Sodium_Core_Base64_Common
|
||||
{
|
||||
/**
|
||||
* Encode into Base64
|
||||
*
|
||||
* Base64 character set "[A-Z][a-z][0-9]+/"
|
||||
*
|
||||
* @param string $src
|
||||
* @return string
|
||||
* @throws TypeError
|
||||
*/
|
||||
public static function encode($src)
|
||||
{
|
||||
return self::doEncode($src, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode into Base64, no = padding
|
||||
*
|
||||
* Base64 character set "[A-Z][a-z][0-9]+/"
|
||||
*
|
||||
* @param string $src
|
||||
* @return string
|
||||
* @throws TypeError
|
||||
*/
|
||||
public static function encodeUnpadded($src)
|
||||
{
|
||||
return self::doEncode($src, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $src
|
||||
* @param bool $pad Include = padding?
|
||||
* @return string
|
||||
* @throws TypeError
|
||||
*/
|
||||
protected static function doEncode($src, $pad = true)
|
||||
{
|
||||
$dest = '';
|
||||
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
|
||||
// Main loop (no padding):
|
||||
for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
|
||||
/** @var array<int, int> $chunk */
|
||||
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3));
|
||||
$b0 = $chunk[1];
|
||||
$b1 = $chunk[2];
|
||||
$b2 = $chunk[3];
|
||||
|
||||
$dest .=
|
||||
self::encode6Bits( $b0 >> 2 ) .
|
||||
self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
|
||||
self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) .
|
||||
self::encode6Bits( $b2 & 63);
|
||||
}
|
||||
// The last chunk, which may have padding:
|
||||
if ($i < $srcLen) {
|
||||
/** @var array<int, int> $chunk */
|
||||
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
|
||||
$b0 = $chunk[1];
|
||||
if ($i + 1 < $srcLen) {
|
||||
$b1 = $chunk[2];
|
||||
$dest .=
|
||||
self::encode6Bits($b0 >> 2) .
|
||||
self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
|
||||
self::encode6Bits(($b1 << 2) & 63);
|
||||
if ($pad) {
|
||||
$dest .= '=';
|
||||
}
|
||||
} else {
|
||||
$dest .=
|
||||
self::encode6Bits( $b0 >> 2) .
|
||||
self::encode6Bits(($b0 << 4) & 63);
|
||||
if ($pad) {
|
||||
$dest .= '==';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* decode from base64 into binary
|
||||
*
|
||||
* Base64 character set "./[A-Z][a-z][0-9]"
|
||||
*
|
||||
* @param string $src
|
||||
* @param bool $strictPadding
|
||||
* @return string
|
||||
* @throws RangeException
|
||||
* @throws TypeError
|
||||
* @psalm-suppress RedundantCondition
|
||||
*/
|
||||
public static function decode($src, $strictPadding = false)
|
||||
{
|
||||
// Remove padding
|
||||
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
|
||||
if ($srcLen === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($strictPadding) {
|
||||
if (($srcLen & 3) === 0) {
|
||||
if ($src[$srcLen - 1] === '=') {
|
||||
$srcLen--;
|
||||
if ($src[$srcLen - 1] === '=') {
|
||||
$srcLen--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (($srcLen & 3) === 1) {
|
||||
throw new RangeException(
|
||||
'Incorrect padding'
|
||||
);
|
||||
}
|
||||
if ($src[$srcLen - 1] === '=') {
|
||||
throw new RangeException(
|
||||
'Incorrect padding'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$src = rtrim($src, '=');
|
||||
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
|
||||
}
|
||||
|
||||
$err = 0;
|
||||
$dest = '';
|
||||
// Main loop (no padding):
|
||||
for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
|
||||
/** @var array<int, int> $chunk */
|
||||
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4));
|
||||
$c0 = self::decode6Bits($chunk[1]);
|
||||
$c1 = self::decode6Bits($chunk[2]);
|
||||
$c2 = self::decode6Bits($chunk[3]);
|
||||
$c3 = self::decode6Bits($chunk[4]);
|
||||
|
||||
$dest .= pack(
|
||||
'CCC',
|
||||
((($c0 << 2) | ($c1 >> 4)) & 0xff),
|
||||
((($c1 << 4) | ($c2 >> 2)) & 0xff),
|
||||
((($c2 << 6) | $c3 ) & 0xff)
|
||||
);
|
||||
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
|
||||
}
|
||||
// The last chunk, which may have padding:
|
||||
if ($i < $srcLen) {
|
||||
/** @var array<int, int> $chunk */
|
||||
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
|
||||
$c0 = self::decode6Bits($chunk[1]);
|
||||
|
||||
if ($i + 2 < $srcLen) {
|
||||
$c1 = self::decode6Bits($chunk[2]);
|
||||
$c2 = self::decode6Bits($chunk[3]);
|
||||
$dest .= pack(
|
||||
'CC',
|
||||
((($c0 << 2) | ($c1 >> 4)) & 0xff),
|
||||
((($c1 << 4) | ($c2 >> 2)) & 0xff)
|
||||
);
|
||||
$err |= ($c0 | $c1 | $c2) >> 8;
|
||||
} elseif ($i + 1 < $srcLen) {
|
||||
$c1 = self::decode6Bits($chunk[2]);
|
||||
$dest .= pack(
|
||||
'C',
|
||||
((($c0 << 2) | ($c1 >> 4)) & 0xff)
|
||||
);
|
||||
$err |= ($c0 | $c1) >> 8;
|
||||
} elseif ($i < $srcLen && $strictPadding) {
|
||||
$err |= 1;
|
||||
}
|
||||
}
|
||||
/** @var bool $check */
|
||||
$check = ($err === 0);
|
||||
if (!$check) {
|
||||
throw new RangeException(
|
||||
'Base64::decode() only expects characters in the correct base64 alphabet'
|
||||
);
|
||||
}
|
||||
return $dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses bitwise operators instead of table-lookups to turn 6-bit integers
|
||||
* into 8-bit integers.
|
||||
*
|
||||
* Base64 character set:
|
||||
* [A-Z] [a-z] [0-9] + /
|
||||
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
|
||||
*
|
||||
* @param int $src
|
||||
* @return int
|
||||
*/
|
||||
abstract protected static function decode6Bits($src);
|
||||
|
||||
/**
|
||||
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
|
||||
* into 6-bit integers.
|
||||
*
|
||||
* @param int $src
|
||||
* @return string
|
||||
*/
|
||||
abstract protected static function encode6Bits($src);
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class ParagonIE_Sodium_Core_Base64
|
||||
*
|
||||
* Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
|
||||
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
|
||||
*/
|
||||
class ParagonIE_Sodium_Core_Base64_Original
|
||||
{
|
||||
// COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE
|
||||
/**
|
||||
* Encode into Base64
|
||||
*
|
||||
* Base64 character set "[A-Z][a-z][0-9]+/"
|
||||
*
|
||||
* @param string $src
|
||||
* @return string
|
||||
* @throws TypeError
|
||||
*/
|
||||
public static function encode($src)
|
||||
{
|
||||
return self::doEncode($src, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode into Base64, no = padding
|
||||
*
|
||||
* Base64 character set "[A-Z][a-z][0-9]+/"
|
||||
*
|
||||
* @param string $src
|
||||
* @return string
|
||||
* @throws TypeError
|
||||
*/
|
||||
public static function encodeUnpadded($src)
|
||||
{
|
||||
return self::doEncode($src, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $src
|
||||
* @param bool $pad Include = padding?
|
||||
* @return string
|
||||
* @throws TypeError
|
||||
*/
|
||||
protected static function doEncode($src, $pad = true)
|
||||
{
|
||||
$dest = '';
|
||||
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
|
||||
// Main loop (no padding):
|
||||
for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
|
||||
/** @var array<int, int> $chunk */
|
||||
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3));
|
||||
$b0 = $chunk[1];
|
||||
$b1 = $chunk[2];
|
||||
$b2 = $chunk[3];
|
||||
|
||||
$dest .=
|
||||
self::encode6Bits( $b0 >> 2 ) .
|
||||
self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
|
||||
self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) .
|
||||
self::encode6Bits( $b2 & 63);
|
||||
}
|
||||
// The last chunk, which may have padding:
|
||||
if ($i < $srcLen) {
|
||||
/** @var array<int, int> $chunk */
|
||||
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
|
||||
$b0 = $chunk[1];
|
||||
if ($i + 1 < $srcLen) {
|
||||
$b1 = $chunk[2];
|
||||
$dest .=
|
||||
self::encode6Bits($b0 >> 2) .
|
||||
self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
|
||||
self::encode6Bits(($b1 << 2) & 63);
|
||||
if ($pad) {
|
||||
$dest .= '=';
|
||||
}
|
||||
} else {
|
||||
$dest .=
|
||||
self::encode6Bits( $b0 >> 2) .
|
||||
self::encode6Bits(($b0 << 4) & 63);
|
||||
if ($pad) {
|
||||
$dest .= '==';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* decode from base64 into binary
|
||||
*
|
||||
* Base64 character set "./[A-Z][a-z][0-9]"
|
||||
*
|
||||
* @param string $src
|
||||
* @param bool $strictPadding
|
||||
* @return string
|
||||
* @throws RangeException
|
||||
* @throws TypeError
|
||||
* @psalm-suppress RedundantCondition
|
||||
*/
|
||||
public static function decode($src, $strictPadding = false)
|
||||
{
|
||||
// Remove padding
|
||||
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
|
||||
if ($srcLen === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($strictPadding) {
|
||||
if (($srcLen & 3) === 0) {
|
||||
if ($src[$srcLen - 1] === '=') {
|
||||
$srcLen--;
|
||||
if ($src[$srcLen - 1] === '=') {
|
||||
$srcLen--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (($srcLen & 3) === 1) {
|
||||
throw new RangeException(
|
||||
'Incorrect padding'
|
||||
);
|
||||
}
|
||||
if ($src[$srcLen - 1] === '=') {
|
||||
throw new RangeException(
|
||||
'Incorrect padding'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$src = rtrim($src, '=');
|
||||
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
|
||||
}
|
||||
|
||||
$err = 0;
|
||||
$dest = '';
|
||||
// Main loop (no padding):
|
||||
for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
|
||||
/** @var array<int, int> $chunk */
|
||||
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4));
|
||||
$c0 = self::decode6Bits($chunk[1]);
|
||||
$c1 = self::decode6Bits($chunk[2]);
|
||||
$c2 = self::decode6Bits($chunk[3]);
|
||||
$c3 = self::decode6Bits($chunk[4]);
|
||||
|
||||
$dest .= pack(
|
||||
'CCC',
|
||||
((($c0 << 2) | ($c1 >> 4)) & 0xff),
|
||||
((($c1 << 4) | ($c2 >> 2)) & 0xff),
|
||||
((($c2 << 6) | $c3) & 0xff)
|
||||
);
|
||||
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
|
||||
}
|
||||
// The last chunk, which may have padding:
|
||||
if ($i < $srcLen) {
|
||||
/** @var array<int, int> $chunk */
|
||||
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
|
||||
$c0 = self::decode6Bits($chunk[1]);
|
||||
|
||||
if ($i + 2 < $srcLen) {
|
||||
$c1 = self::decode6Bits($chunk[2]);
|
||||
$c2 = self::decode6Bits($chunk[3]);
|
||||
$dest .= pack(
|
||||
'CC',
|
||||
((($c0 << 2) | ($c1 >> 4)) & 0xff),
|
||||
((($c1 << 4) | ($c2 >> 2)) & 0xff)
|
||||
);
|
||||
$err |= ($c0 | $c1 | $c2) >> 8;
|
||||
} elseif ($i + 1 < $srcLen) {
|
||||
$c1 = self::decode6Bits($chunk[2]);
|
||||
$dest .= pack(
|
||||
'C',
|
||||
((($c0 << 2) | ($c1 >> 4)) & 0xff)
|
||||
);
|
||||
$err |= ($c0 | $c1) >> 8;
|
||||
} elseif ($i < $srcLen && $strictPadding) {
|
||||
$err |= 1;
|
||||
}
|
||||
}
|
||||
/** @var bool $check */
|
||||
$check = ($err === 0);
|
||||
if (!$check) {
|
||||
throw new RangeException(
|
||||
'Base64::decode() only expects characters in the correct base64 alphabet'
|
||||
);
|
||||
}
|
||||
return $dest;
|
||||
}
|
||||
// COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE
|
||||
|
||||
/**
|
||||
* Uses bitwise operators instead of table-lookups to turn 6-bit integers
|
||||
* into 8-bit integers.
|
||||
*
|
||||
* Base64 character set:
|
||||
* [A-Z] [a-z] [0-9] + /
|
||||
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
|
||||
*
|
||||
* @param int $src
|
||||
* @return int
|
||||
*/
|
||||
protected static function decode6Bits($src)
|
||||
{
|
||||
$ret = -1;
|
||||
|
||||
// if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
|
||||
$ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);
|
||||
|
||||
// if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
|
||||
$ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70);
|
||||
|
||||
// if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
|
||||
$ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5);
|
||||
|
||||
// if ($src == 0x2b) $ret += 62 + 1;
|
||||
$ret += (((0x2a - $src) & ($src - 0x2c)) >> 8) & 63;
|
||||
|
||||
// if ($src == 0x2f) ret += 63 + 1;
|
||||
$ret += (((0x2e - $src) & ($src - 0x30)) >> 8) & 64;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
|
||||
* into 6-bit integers.
|
||||
*
|
||||
* @param int $src
|
||||
* @return string
|
||||
*/
|
||||
protected static function encode6Bits($src)
|
||||
{
|
||||
$diff = 0x41;
|
||||
|
||||
// if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
|
||||
$diff += ((25 - $src) >> 8) & 6;
|
||||
|
||||
// if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
|
||||
$diff -= ((51 - $src) >> 8) & 75;
|
||||
|
||||
// if ($src > 61) $diff += 0x2b - 0x30 - 10; // -15
|
||||
$diff -= ((61 - $src) >> 8) & 15;
|
||||
|
||||
// if ($src > 62) $diff += 0x2f - 0x2b - 1; // 3
|
||||
$diff += ((62 - $src) >> 8) & 3;
|
||||
|
||||
return pack('C', $src + $diff);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class ParagonIE_Sodium_Core_Base64UrlSafe
|
||||
*
|
||||
* Copyright (c) 2016 - 2018 Paragon Initiative Enterprises.
|
||||
* Copyright (c) 2014 Steve "Sc00bz" Thomas (steve at tobtu dot com)
|
||||
*/
|
||||
class ParagonIE_Sodium_Core_Base64_UrlSafe
|
||||
{
|
||||
// COPY ParagonIE_Sodium_Core_Base64_Common STARTING HERE
|
||||
/**
|
||||
* Encode into Base64
|
||||
*
|
||||
* Base64 character set "[A-Z][a-z][0-9]+/"
|
||||
*
|
||||
* @param string $src
|
||||
* @return string
|
||||
* @throws TypeError
|
||||
*/
|
||||
public static function encode($src)
|
||||
{
|
||||
return self::doEncode($src, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode into Base64, no = padding
|
||||
*
|
||||
* Base64 character set "[A-Z][a-z][0-9]+/"
|
||||
*
|
||||
* @param string $src
|
||||
* @return string
|
||||
* @throws TypeError
|
||||
*/
|
||||
public static function encodeUnpadded($src)
|
||||
{
|
||||
return self::doEncode($src, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $src
|
||||
* @param bool $pad Include = padding?
|
||||
* @return string
|
||||
* @throws TypeError
|
||||
*/
|
||||
protected static function doEncode($src, $pad = true)
|
||||
{
|
||||
$dest = '';
|
||||
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
|
||||
// Main loop (no padding):
|
||||
for ($i = 0; $i + 3 <= $srcLen; $i += 3) {
|
||||
/** @var array<int, int> $chunk */
|
||||
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 3));
|
||||
$b0 = $chunk[1];
|
||||
$b1 = $chunk[2];
|
||||
$b2 = $chunk[3];
|
||||
|
||||
$dest .=
|
||||
self::encode6Bits( $b0 >> 2 ) .
|
||||
self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
|
||||
self::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) .
|
||||
self::encode6Bits( $b2 & 63);
|
||||
}
|
||||
// The last chunk, which may have padding:
|
||||
if ($i < $srcLen) {
|
||||
/** @var array<int, int> $chunk */
|
||||
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
|
||||
$b0 = $chunk[1];
|
||||
if ($i + 1 < $srcLen) {
|
||||
$b1 = $chunk[2];
|
||||
$dest .=
|
||||
self::encode6Bits($b0 >> 2) .
|
||||
self::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
|
||||
self::encode6Bits(($b1 << 2) & 63);
|
||||
if ($pad) {
|
||||
$dest .= '=';
|
||||
}
|
||||
} else {
|
||||
$dest .=
|
||||
self::encode6Bits( $b0 >> 2) .
|
||||
self::encode6Bits(($b0 << 4) & 63);
|
||||
if ($pad) {
|
||||
$dest .= '==';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* decode from base64 into binary
|
||||
*
|
||||
* Base64 character set "./[A-Z][a-z][0-9]"
|
||||
*
|
||||
* @param string $src
|
||||
* @param bool $strictPadding
|
||||
* @return string
|
||||
* @throws RangeException
|
||||
* @throws TypeError
|
||||
* @psalm-suppress RedundantCondition
|
||||
*/
|
||||
public static function decode($src, $strictPadding = false)
|
||||
{
|
||||
// Remove padding
|
||||
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
|
||||
if ($srcLen === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($strictPadding) {
|
||||
if (($srcLen & 3) === 0) {
|
||||
if ($src[$srcLen - 1] === '=') {
|
||||
$srcLen--;
|
||||
if ($src[$srcLen - 1] === '=') {
|
||||
$srcLen--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (($srcLen & 3) === 1) {
|
||||
throw new RangeException(
|
||||
'Incorrect padding'
|
||||
);
|
||||
}
|
||||
if ($src[$srcLen - 1] === '=') {
|
||||
throw new RangeException(
|
||||
'Incorrect padding'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$src = rtrim($src, '=');
|
||||
$srcLen = ParagonIE_Sodium_Core_Util::strlen($src);
|
||||
}
|
||||
|
||||
$err = 0;
|
||||
$dest = '';
|
||||
// Main loop (no padding):
|
||||
for ($i = 0; $i + 4 <= $srcLen; $i += 4) {
|
||||
/** @var array<int, int> $chunk */
|
||||
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, 4));
|
||||
$c0 = self::decode6Bits($chunk[1]);
|
||||
$c1 = self::decode6Bits($chunk[2]);
|
||||
$c2 = self::decode6Bits($chunk[3]);
|
||||
$c3 = self::decode6Bits($chunk[4]);
|
||||
|
||||
$dest .= pack(
|
||||
'CCC',
|
||||
((($c0 << 2) | ($c1 >> 4)) & 0xff),
|
||||
((($c1 << 4) | ($c2 >> 2)) & 0xff),
|
||||
((($c2 << 6) | $c3) & 0xff)
|
||||
);
|
||||
$err |= ($c0 | $c1 | $c2 | $c3) >> 8;
|
||||
}
|
||||
// The last chunk, which may have padding:
|
||||
if ($i < $srcLen) {
|
||||
/** @var array<int, int> $chunk */
|
||||
$chunk = unpack('C*', ParagonIE_Sodium_Core_Util::substr($src, $i, $srcLen - $i));
|
||||
$c0 = self::decode6Bits($chunk[1]);
|
||||
|
||||
if ($i + 2 < $srcLen) {
|
||||
$c1 = self::decode6Bits($chunk[2]);
|
||||
$c2 = self::decode6Bits($chunk[3]);
|
||||
$dest .= pack(
|
||||
'CC',
|
||||
((($c0 << 2) | ($c1 >> 4)) & 0xff),
|
||||
((($c1 << 4) | ($c2 >> 2)) & 0xff)
|
||||
);
|
||||
$err |= ($c0 | $c1 | $c2) >> 8;
|
||||
} elseif ($i + 1 < $srcLen) {
|
||||
$c1 = self::decode6Bits($chunk[2]);
|
||||
$dest .= pack(
|
||||
'C',
|
||||
((($c0 << 2) | ($c1 >> 4)) & 0xff)
|
||||
);
|
||||
$err |= ($c0 | $c1) >> 8;
|
||||
} elseif ($i < $srcLen && $strictPadding) {
|
||||
$err |= 1;
|
||||
}
|
||||
}
|
||||
/** @var bool $check */
|
||||
$check = ($err === 0);
|
||||
if (!$check) {
|
||||
throw new RangeException(
|
||||
'Base64::decode() only expects characters in the correct base64 alphabet'
|
||||
);
|
||||
}
|
||||
return $dest;
|
||||
}
|
||||
// COPY ParagonIE_Sodium_Core_Base64_Common ENDING HERE
|
||||
/**
|
||||
* Uses bitwise operators instead of table-lookups to turn 6-bit integers
|
||||
* into 8-bit integers.
|
||||
*
|
||||
* Base64 character set:
|
||||
* [A-Z] [a-z] [0-9] + /
|
||||
* 0x41-0x5a, 0x61-0x7a, 0x30-0x39, 0x2b, 0x2f
|
||||
*
|
||||
* @param int $src
|
||||
* @return int
|
||||
*/
|
||||
protected static function decode6Bits($src)
|
||||
{
|
||||
$ret = -1;
|
||||
|
||||
// if ($src > 0x40 && $src < 0x5b) $ret += $src - 0x41 + 1; // -64
|
||||
$ret += (((0x40 - $src) & ($src - 0x5b)) >> 8) & ($src - 64);
|
||||
|
||||
// if ($src > 0x60 && $src < 0x7b) $ret += $src - 0x61 + 26 + 1; // -70
|
||||
$ret += (((0x60 - $src) & ($src - 0x7b)) >> 8) & ($src - 70);
|
||||
|
||||
// if ($src > 0x2f && $src < 0x3a) $ret += $src - 0x30 + 52 + 1; // 5
|
||||
$ret += (((0x2f - $src) & ($src - 0x3a)) >> 8) & ($src + 5);
|
||||
|
||||
// if ($src == 0x2c) $ret += 62 + 1;
|
||||
$ret += (((0x2c - $src) & ($src - 0x2e)) >> 8) & 63;
|
||||
|
||||
// if ($src == 0x5f) ret += 63 + 1;
|
||||
$ret += (((0x5e - $src) & ($src - 0x60)) >> 8) & 64;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses bitwise operators instead of table-lookups to turn 8-bit integers
|
||||
* into 6-bit integers.
|
||||
*
|
||||
* @param int $src
|
||||
* @return string
|
||||
*/
|
||||
protected static function encode6Bits($src)
|
||||
{
|
||||
$diff = 0x41;
|
||||
|
||||
// if ($src > 25) $diff += 0x61 - 0x41 - 26; // 6
|
||||
$diff += ((25 - $src) >> 8) & 6;
|
||||
|
||||
// if ($src > 51) $diff += 0x30 - 0x61 - 26; // -75
|
||||
$diff -= ((51 - $src) >> 8) & 75;
|
||||
|
||||
// if ($src > 61) $diff += 0x2d - 0x30 - 10; // -13
|
||||
$diff -= ((61 - $src) >> 8) & 13;
|
||||
|
||||
// if ($src > 62) $diff += 0x5f - 0x2b - 1; // 3
|
||||
$diff += ((62 - $src) >> 8) & 49;
|
||||
|
||||
return pack('C', $src + $diff);
|
||||
}
|
||||
}
|
|
@ -276,7 +276,7 @@ abstract class ParagonIE_Sodium_Core_Ed25519 extends ParagonIE_Sodium_Core_Curve
|
|||
if (self::strlen($sig) < 64) {
|
||||
throw new SodiumException('Signature is too short');
|
||||
}
|
||||
if (self::check_S_lt_L(self::substr($sig, 32, 32))) {
|
||||
if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) {
|
||||
throw new SodiumException('S < L - Invalid signature');
|
||||
}
|
||||
if (self::small_order($sig)) {
|
||||
|
|
|
@ -79,6 +79,29 @@ class ParagonIE_Sodium_Core_Poly1305_State extends ParagonIE_Sodium_Core_Util
|
|||
$this->final = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zero internal buffer upon destruction
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->r[0] ^= $this->r[0];
|
||||
$this->r[1] ^= $this->r[1];
|
||||
$this->r[2] ^= $this->r[2];
|
||||
$this->r[3] ^= $this->r[3];
|
||||
$this->r[4] ^= $this->r[4];
|
||||
$this->h[0] ^= $this->h[0];
|
||||
$this->h[1] ^= $this->h[1];
|
||||
$this->h[2] ^= $this->h[2];
|
||||
$this->h[3] ^= $this->h[3];
|
||||
$this->h[4] ^= $this->h[4];
|
||||
$this->pad[0] ^= $this->pad[0];
|
||||
$this->pad[1] ^= $this->pad[1];
|
||||
$this->pad[2] ^= $this->pad[2];
|
||||
$this->pad[3] ^= $this->pad[3];
|
||||
$this->leftover = 0;
|
||||
$this->final = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal You should not use this directly from another application
|
||||
*
|
||||
|
@ -90,6 +113,9 @@ class ParagonIE_Sodium_Core_Poly1305_State extends ParagonIE_Sodium_Core_Util
|
|||
public function update($message = '')
|
||||
{
|
||||
$bytes = self::strlen($message);
|
||||
if ($bytes < 1) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/* handle leftover */
|
||||
if ($this->leftover) {
|
||||
|
@ -111,7 +137,7 @@ class ParagonIE_Sodium_Core_Poly1305_State extends ParagonIE_Sodium_Core_Util
|
|||
}
|
||||
|
||||
$this->blocks(
|
||||
static::intArrayToString($this->buffer),
|
||||
self::intArrayToString($this->buffer),
|
||||
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
|
||||
);
|
||||
$this->leftover = 0;
|
||||
|
@ -296,7 +322,7 @@ class ParagonIE_Sodium_Core_Poly1305_State extends ParagonIE_Sodium_Core_Util
|
|||
$this->final = true;
|
||||
$this->blocks(
|
||||
self::substr(
|
||||
static::intArrayToString($this->buffer),
|
||||
self::intArrayToString($this->buffer),
|
||||
0,
|
||||
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
|
||||
),
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class ParagonIE_Sodium_Core_SecretStream_State
|
||||
*/
|
||||
class ParagonIE_Sodium_Core_SecretStream_State
|
||||
{
|
||||
/** @var string $key */
|
||||
protected $key;
|
||||
|
||||
/** @var int $counter */
|
||||
protected $counter;
|
||||
|
||||
/** @var string $nonce */
|
||||
protected $nonce;
|
||||
|
||||
/** @var string $_pad */
|
||||
protected $_pad;
|
||||
|
||||
/**
|
||||
* ParagonIE_Sodium_Core_SecretStream_State constructor.
|
||||
* @param string $key
|
||||
* @param string|null $nonce
|
||||
*/
|
||||
public function __construct($key, $nonce = null)
|
||||
{
|
||||
$this->key = $key;
|
||||
$this->counter = 1;
|
||||
if (is_null($nonce)) {
|
||||
$nonce = str_repeat("\0", 12);
|
||||
}
|
||||
$this->nonce = str_pad($nonce, 12, "\0", STR_PAD_RIGHT);;
|
||||
$this->_pad = str_repeat("\0", 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
public function counterReset()
|
||||
{
|
||||
$this->counter = 1;
|
||||
$this->_pad = str_repeat("\0", 4);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCounter()
|
||||
{
|
||||
return ParagonIE_Sodium_Core_Util::store32_le($this->counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getNonce()
|
||||
{
|
||||
if (!is_string($this->nonce)) {
|
||||
$this->nonce = str_repeat("\0", 12);
|
||||
}
|
||||
if (ParagonIE_Sodium_Core_Util::strlen($this->nonce) !== 12) {
|
||||
$this->nonce = str_pad($this->nonce, 12, "\0", STR_PAD_RIGHT);
|
||||
}
|
||||
return $this->nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCombinedNonce()
|
||||
{
|
||||
return $this->getCounter() .
|
||||
ParagonIE_Sodium_Core_Util::substr($this->getNonce(), 0, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
public function incrementCounter()
|
||||
{
|
||||
++$this->counter;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function needsRekey()
|
||||
{
|
||||
return ($this->counter & 0xffff) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $newKeyAndNonce
|
||||
* @return self
|
||||
*/
|
||||
public function rekey($newKeyAndNonce)
|
||||
{
|
||||
$this->key = ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 0, 32);
|
||||
$this->nonce = str_pad(
|
||||
ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 32),
|
||||
12,
|
||||
"\0",
|
||||
STR_PAD_RIGHT
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @return self
|
||||
*/
|
||||
public function xorNonce($str)
|
||||
{
|
||||
$this->nonce = ParagonIE_Sodium_Core_Util::xorStrings(
|
||||
$this->getNonce(),
|
||||
str_pad(
|
||||
ParagonIE_Sodium_Core_Util::substr($str, 0, 8),
|
||||
12,
|
||||
"\0",
|
||||
STR_PAD_RIGHT
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @return self
|
||||
*/
|
||||
public static function fromString($string)
|
||||
{
|
||||
$state = new ParagonIE_Sodium_Core_SecretStream_State(
|
||||
ParagonIE_Sodium_Core_Util::substr($string, 0, 32)
|
||||
);
|
||||
$state->counter = ParagonIE_Sodium_Core_Util::load_4(
|
||||
ParagonIE_Sodium_Core_Util::substr($string, 32, 4)
|
||||
);
|
||||
$state->nonce = ParagonIE_Sodium_Core_Util::substr($string, 36, 12);
|
||||
$state->_pad = ParagonIE_Sodium_Core_Util::substr($string, 48, 8);
|
||||
return $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return $this->key .
|
||||
$this->getCounter() .
|
||||
$this->nonce .
|
||||
$this->_pad;
|
||||
}
|
||||
}
|
|
@ -36,6 +36,33 @@ class ParagonIE_Sodium_Core_XChaCha20 extends ParagonIE_Sodium_Core_HChaCha20
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal You should not use this directly from another application
|
||||
*
|
||||
* @param int $len
|
||||
* @param string $nonce
|
||||
* @param string $key
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
* @throws TypeError
|
||||
*/
|
||||
public static function ietfStream($len = 64, $nonce = '', $key = '')
|
||||
{
|
||||
if (self::strlen($nonce) !== 24) {
|
||||
throw new SodiumException('Nonce must be 24 bytes long');
|
||||
}
|
||||
return self::encryptBytes(
|
||||
new ParagonIE_Sodium_Core_ChaCha20_IetfCtx(
|
||||
self::hChaCha20(
|
||||
self::substr($nonce, 0, 16),
|
||||
$key
|
||||
),
|
||||
"\x00\x00\x00\x00" . self::substr($nonce, 16, 8)
|
||||
),
|
||||
str_repeat("\x00", $len)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal You should not use this directly from another application
|
||||
*
|
||||
|
@ -61,4 +88,30 @@ class ParagonIE_Sodium_Core_XChaCha20 extends ParagonIE_Sodium_Core_HChaCha20
|
|||
$message
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal You should not use this directly from another application
|
||||
*
|
||||
* @param string $message
|
||||
* @param string $nonce
|
||||
* @param string $key
|
||||
* @param string $ic
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
* @throws TypeError
|
||||
*/
|
||||
public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '')
|
||||
{
|
||||
if (self::strlen($nonce) !== 24) {
|
||||
throw new SodiumException('Nonce must be 24 bytes long');
|
||||
}
|
||||
return self::encryptBytes(
|
||||
new ParagonIE_Sodium_Core_ChaCha20_IetfCtx(
|
||||
self::hChaCha20(self::substr($nonce, 0, 16), $key),
|
||||
"\x00\x00\x00\x00" . self::substr($nonce, 16, 8),
|
||||
$ic
|
||||
),
|
||||
$message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -223,12 +223,13 @@ abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Uti
|
|||
*/
|
||||
protected static function context()
|
||||
{
|
||||
$ctx = new SplFixedArray(5);
|
||||
$ctx = new SplFixedArray(6);
|
||||
$ctx[0] = new SplFixedArray(8); // h
|
||||
$ctx[1] = new SplFixedArray(2); // t
|
||||
$ctx[2] = new SplFixedArray(2); // f
|
||||
$ctx[3] = new SplFixedArray(256); // buf
|
||||
$ctx[4] = 0; // buflen
|
||||
$ctx[5] = 0; // last_node (uint8_t)
|
||||
|
||||
for ($i = 8; $i--;) {
|
||||
$ctx[0][$i] = self::$iv[$i];
|
||||
|
@ -482,6 +483,8 @@ abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Uti
|
|||
*
|
||||
* @param SplFixedArray|null $key
|
||||
* @param int $outlen
|
||||
* @param SplFixedArray|null $salt
|
||||
* @param SplFixedArray|null $personal
|
||||
* @return SplFixedArray
|
||||
* @throws SodiumException
|
||||
* @throws TypeError
|
||||
|
@ -491,8 +494,12 @@ abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Uti
|
|||
* @psalm-suppress MixedArrayAssignment
|
||||
* @psalm-suppress MixedMethodCall
|
||||
*/
|
||||
public static function init($key = null, $outlen = 64)
|
||||
{
|
||||
public static function init(
|
||||
$key = null,
|
||||
$outlen = 64,
|
||||
$salt = null,
|
||||
$personal = null
|
||||
) {
|
||||
self::pseudoConstructor();
|
||||
$klen = 0;
|
||||
|
||||
|
@ -510,6 +517,7 @@ abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Uti
|
|||
$ctx = self::context();
|
||||
|
||||
$p = new SplFixedArray(64);
|
||||
// Zero our param buffer...
|
||||
for ($i = 64; --$i;) {
|
||||
$p[$i] = 0;
|
||||
}
|
||||
|
@ -519,11 +527,34 @@ abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Uti
|
|||
$p[2] = 1; // fanout
|
||||
$p[3] = 1; // depth
|
||||
|
||||
if ($salt instanceof SplFixedArray) {
|
||||
// salt: [32] through [47]
|
||||
for ($i = 0; $i < 16; ++$i) {
|
||||
$p[32 + $i] = (int) $salt[$i];
|
||||
}
|
||||
}
|
||||
if ($personal instanceof SplFixedArray) {
|
||||
// personal: [48] through [63]
|
||||
for ($i = 0; $i < 16; ++$i) {
|
||||
$p[48 + $i] = (int) $personal[$i];
|
||||
}
|
||||
}
|
||||
|
||||
$ctx[0][0] = self::xor64(
|
||||
$ctx[0][0],
|
||||
self::load64($p, 0)
|
||||
);
|
||||
|
||||
if ($salt instanceof SplFixedArray || $personal instanceof SplFixedArray) {
|
||||
// We need to do what blake2b_init_param() does:
|
||||
for ($i = 1; $i < 8; ++$i) {
|
||||
$ctx[0][$i] = self::xor64(
|
||||
$ctx[0][$i],
|
||||
self::load64($p, $i << 3)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($klen > 0 && $key instanceof SplFixedArray) {
|
||||
$block = new SplFixedArray(128);
|
||||
for ($i = 128; $i--;) {
|
||||
|
@ -533,6 +564,7 @@ abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Uti
|
|||
$block[$i] = $key[$i];
|
||||
}
|
||||
self::update($ctx, $block, 128);
|
||||
$ctx[4] = 128;
|
||||
}
|
||||
|
||||
return $ctx;
|
||||
|
@ -595,7 +627,7 @@ abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Uti
|
|||
}
|
||||
/** @var ParagonIE_Sodium_Core32_Int64 $ctxAi */
|
||||
$ctxAi = $ctxA[$i];
|
||||
$str .= $ctxAi->toString();
|
||||
$str .= $ctxAi->toReverseString();
|
||||
}
|
||||
|
||||
# uint64_t t[2];
|
||||
|
@ -608,8 +640,8 @@ abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Uti
|
|||
/** @var ParagonIE_Sodium_Core32_Int64 $ctxA2 */
|
||||
$ctxA2 = $ctxA[1];
|
||||
|
||||
$str .= $ctxA1->toString();
|
||||
$str .= $ctxA2->toString();
|
||||
$str .= $ctxA1->toReverseString();
|
||||
$str .= $ctxA2->toReverseString();
|
||||
}
|
||||
|
||||
# uint8_t buf[2 * 128];
|
||||
|
@ -624,13 +656,16 @@ abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Uti
|
|||
self::intToChr(($ctx4 >> 8) & 0xff),
|
||||
self::intToChr(($ctx4 >> 16) & 0xff),
|
||||
self::intToChr(($ctx4 >> 24) & 0xff),
|
||||
"\x00\x00\x00\x00"
|
||||
/*
|
||||
self::intToChr(($ctx4 >> 32) & 0xff),
|
||||
self::intToChr(($ctx4 >> 40) & 0xff),
|
||||
self::intToChr(($ctx4 >> 48) & 0xff),
|
||||
self::intToChr(($ctx4 >> 56) & 0xff)
|
||||
*/
|
||||
));
|
||||
# uint8_t last_node;
|
||||
return $str . "\x00";
|
||||
return $str . self::intToChr($ctx[5]) . str_repeat("\x00", 23);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -652,7 +687,7 @@ abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Uti
|
|||
|
||||
# uint64_t h[8];
|
||||
for ($i = 0; $i < 8; ++$i) {
|
||||
$ctx[0][$i] = ParagonIE_Sodium_Core32_Int64::fromString(
|
||||
$ctx[0][$i] = ParagonIE_Sodium_Core32_Int64::fromReverseString(
|
||||
self::substr($string, (($i << 3) + 0), 8)
|
||||
);
|
||||
}
|
||||
|
@ -660,10 +695,10 @@ abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Uti
|
|||
# uint64_t t[2];
|
||||
# uint64_t f[2];
|
||||
for ($i = 1; $i < 3; ++$i) {
|
||||
$ctx[$i][1] = ParagonIE_Sodium_Core32_Int64::fromString(
|
||||
$ctx[$i][1] = ParagonIE_Sodium_Core32_Int64::fromReverseString(
|
||||
self::substr($string, 72 + (($i - 1) << 4), 8)
|
||||
);
|
||||
$ctx[$i][0] = ParagonIE_Sodium_Core32_Int64::fromString(
|
||||
$ctx[$i][0] = ParagonIE_Sodium_Core32_Int64::fromReverseString(
|
||||
self::substr($string, 64 + (($i - 1) << 4), 8)
|
||||
);
|
||||
}
|
||||
|
@ -671,7 +706,6 @@ abstract class ParagonIE_Sodium_Core32_BLAKE2b extends ParagonIE_Sodium_Core_Uti
|
|||
# uint8_t buf[2 * 128];
|
||||
$ctx[3] = self::stringToSplFixedArray(self::substr($string, 96, 256));
|
||||
|
||||
|
||||
# uint8_t buf[2 * 128];
|
||||
$int = 0;
|
||||
for ($i = 0; $i < 8; ++$i) {
|
||||
|
|
|
@ -278,7 +278,7 @@ abstract class ParagonIE_Sodium_Core32_Ed25519 extends ParagonIE_Sodium_Core32_C
|
|||
if (self::strlen($sig) < 64) {
|
||||
throw new SodiumException('Signature is too short');
|
||||
}
|
||||
if (self::check_S_lt_L(self::substr($sig, 32, 32))) {
|
||||
if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) {
|
||||
throw new SodiumException('S < L - Invalid signature');
|
||||
}
|
||||
if (self::small_order($sig)) {
|
||||
|
|
|
@ -142,7 +142,7 @@ class ParagonIE_Sodium_Core32_Poly1305_State extends ParagonIE_Sodium_Core32_Uti
|
|||
}
|
||||
|
||||
$this->blocks(
|
||||
static::intArrayToString($this->buffer),
|
||||
self::intArrayToString($this->buffer),
|
||||
ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE
|
||||
);
|
||||
$this->leftover = 0;
|
||||
|
@ -346,7 +346,7 @@ class ParagonIE_Sodium_Core32_Poly1305_State extends ParagonIE_Sodium_Core32_Uti
|
|||
$this->final = true;
|
||||
$this->blocks(
|
||||
self::substr(
|
||||
static::intArrayToString($this->buffer),
|
||||
self::intArrayToString($this->buffer),
|
||||
0,
|
||||
ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE
|
||||
),
|
||||
|
|
|
@ -0,0 +1,163 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class ParagonIE_Sodium_Core32_SecretStream_State
|
||||
*/
|
||||
class ParagonIE_Sodium_Core32_SecretStream_State
|
||||
{
|
||||
/** @var string $key */
|
||||
protected $key;
|
||||
|
||||
/** @var int $counter */
|
||||
protected $counter;
|
||||
|
||||
/** @var string $nonce */
|
||||
protected $nonce;
|
||||
|
||||
/** @var string $_pad */
|
||||
protected $_pad;
|
||||
|
||||
/**
|
||||
* ParagonIE_Sodium_Core32_SecretStream_State constructor.
|
||||
* @param string $key
|
||||
* @param string|null $nonce
|
||||
*/
|
||||
public function __construct($key, $nonce = null)
|
||||
{
|
||||
$this->key = $key;
|
||||
$this->counter = 1;
|
||||
if (is_null($nonce)) {
|
||||
$nonce = str_repeat("\0", 12);
|
||||
}
|
||||
$this->nonce = str_pad($nonce, 12, "\0", STR_PAD_RIGHT);;
|
||||
$this->_pad = str_repeat("\0", 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
public function counterReset()
|
||||
{
|
||||
$this->counter = 1;
|
||||
$this->_pad = str_repeat("\0", 4);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCounter()
|
||||
{
|
||||
return ParagonIE_Sodium_Core32_Util::store32_le($this->counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getNonce()
|
||||
{
|
||||
if (!is_string($this->nonce)) {
|
||||
$this->nonce = str_repeat("\0", 12);
|
||||
}
|
||||
if (ParagonIE_Sodium_Core32_Util::strlen($this->nonce) !== 12) {
|
||||
$this->nonce = str_pad($this->nonce, 12, "\0", STR_PAD_RIGHT);
|
||||
}
|
||||
return $this->nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCombinedNonce()
|
||||
{
|
||||
return $this->getCounter() .
|
||||
ParagonIE_Sodium_Core32_Util::substr($this->getNonce(), 0, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
public function incrementCounter()
|
||||
{
|
||||
++$this->counter;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function needsRekey()
|
||||
{
|
||||
return ($this->counter & 0xffff) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $newKeyAndNonce
|
||||
* @return self
|
||||
*/
|
||||
public function rekey($newKeyAndNonce)
|
||||
{
|
||||
$this->key = ParagonIE_Sodium_Core32_Util::substr($newKeyAndNonce, 0, 32);
|
||||
$this->nonce = str_pad(
|
||||
ParagonIE_Sodium_Core32_Util::substr($newKeyAndNonce, 32),
|
||||
12,
|
||||
"\0",
|
||||
STR_PAD_RIGHT
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @return self
|
||||
*/
|
||||
public function xorNonce($str)
|
||||
{
|
||||
$this->nonce = ParagonIE_Sodium_Core32_Util::xorStrings(
|
||||
$this->getNonce(),
|
||||
str_pad(
|
||||
ParagonIE_Sodium_Core32_Util::substr($str, 0, 8),
|
||||
12,
|
||||
"\0",
|
||||
STR_PAD_RIGHT
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @return self
|
||||
*/
|
||||
public static function fromString($string)
|
||||
{
|
||||
$state = new ParagonIE_Sodium_Core32_SecretStream_State(
|
||||
ParagonIE_Sodium_Core32_Util::substr($string, 0, 32)
|
||||
);
|
||||
$state->counter = ParagonIE_Sodium_Core32_Util::load_4(
|
||||
ParagonIE_Sodium_Core32_Util::substr($string, 32, 4)
|
||||
);
|
||||
$state->nonce = ParagonIE_Sodium_Core32_Util::substr($string, 36, 12);
|
||||
$state->_pad = ParagonIE_Sodium_Core32_Util::substr($string, 48, 8);
|
||||
return $state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function toString()
|
||||
{
|
||||
return $this->key .
|
||||
$this->getCounter() .
|
||||
$this->nonce .
|
||||
$this->_pad;
|
||||
}
|
||||
}
|
|
@ -151,8 +151,9 @@ abstract class ParagonIE_Sodium_Core32_X25519 extends ParagonIE_Sodium_Core32_Cu
|
|||
for ($i = 0; $i < 10; ++$i) {
|
||||
$h[$i] = $h[$i]->toInt32();
|
||||
}
|
||||
/** @var array<int, ParagonIE_Sodium_Core32_Int32> $h */
|
||||
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($h);
|
||||
/** @var array<int, ParagonIE_Sodium_Core32_Int32> $h2 */
|
||||
$h2 = $h;
|
||||
return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($h2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -777,6 +777,53 @@ abstract class ParagonIE_Sodium_Crypto
|
|||
return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a hashing context for BLAKE2b.
|
||||
*
|
||||
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
|
||||
*
|
||||
* @param string $key
|
||||
* @param int $outputLength
|
||||
* @param string $salt
|
||||
* @param string $personal
|
||||
* @return string
|
||||
* @throws RangeException
|
||||
* @throws SodiumException
|
||||
* @throws TypeError
|
||||
*/
|
||||
public static function generichash_init_salt_personal(
|
||||
$key = '',
|
||||
$outputLength = 32,
|
||||
$salt = '',
|
||||
$personal = ''
|
||||
) {
|
||||
// This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized
|
||||
ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
|
||||
|
||||
$k = null;
|
||||
if (!empty($key)) {
|
||||
$k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key);
|
||||
if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) {
|
||||
throw new RangeException('Invalid key size');
|
||||
}
|
||||
}
|
||||
if (!empty($salt)) {
|
||||
$s = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($salt);
|
||||
} else {
|
||||
$s = null;
|
||||
}
|
||||
if (!empty($salt)) {
|
||||
$p = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($personal);
|
||||
} else {
|
||||
$p = null;
|
||||
}
|
||||
|
||||
/** @var SplFixedArray $ctx */
|
||||
$ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength, $s, $p);
|
||||
|
||||
return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a hashing context for BLAKE2b with $message
|
||||
*
|
||||
|
@ -1185,6 +1232,362 @@ abstract class ParagonIE_Sodium_Crypto
|
|||
return $m;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return array<int, string> Returns a state and a header.
|
||||
* @throws Exception
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function secretstream_xchacha20poly1305_init_push($key)
|
||||
{
|
||||
# randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES);
|
||||
$out = random_bytes(24);
|
||||
|
||||
# crypto_core_hchacha20(state->k, out, k, NULL);
|
||||
$subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20($out, $key);
|
||||
$state = new ParagonIE_Sodium_Core_SecretStream_State(
|
||||
$subkey,
|
||||
ParagonIE_Sodium_Core_Util::substr($out, 16, 8) . str_repeat("\0", 4)
|
||||
);
|
||||
|
||||
# _crypto_secretstream_xchacha20poly1305_counter_reset(state);
|
||||
$state->counterReset();
|
||||
|
||||
# memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES,
|
||||
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
|
||||
# memset(state->_pad, 0, sizeof state->_pad);
|
||||
return array(
|
||||
$state->toString(),
|
||||
$out
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param string $header
|
||||
* @return string Returns a state.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function secretstream_xchacha20poly1305_init_pull($key, $header)
|
||||
{
|
||||
# crypto_core_hchacha20(state->k, in, k, NULL);
|
||||
$subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
|
||||
ParagonIE_Sodium_Core_Util::substr($header, 0, 16),
|
||||
$key
|
||||
);
|
||||
$state = new ParagonIE_Sodium_Core_SecretStream_State(
|
||||
$subkey,
|
||||
ParagonIE_Sodium_Core_Util::substr($header, 16)
|
||||
);
|
||||
$state->counterReset();
|
||||
# memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES,
|
||||
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
|
||||
# memset(state->_pad, 0, sizeof state->_pad);
|
||||
# return 0;
|
||||
return $state->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
* @param string $msg
|
||||
* @param string $aad
|
||||
* @param int $tag
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
|
||||
{
|
||||
$st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
|
||||
# crypto_onetimeauth_poly1305_state poly1305_state;
|
||||
# unsigned char block[64U];
|
||||
# unsigned char slen[8U];
|
||||
# unsigned char *c;
|
||||
# unsigned char *mac;
|
||||
|
||||
$msglen = ParagonIE_Sodium_Core_Util::strlen($msg);
|
||||
$aadlen = ParagonIE_Sodium_Core_Util::strlen($aad);
|
||||
|
||||
if ((($msglen + 63) >> 6) > 0xfffffffe) {
|
||||
throw new SodiumException(
|
||||
'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
|
||||
);
|
||||
}
|
||||
|
||||
# if (outlen_p != NULL) {
|
||||
# *outlen_p = 0U;
|
||||
# }
|
||||
# if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
|
||||
# sodium_misuse();
|
||||
# }
|
||||
|
||||
# crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
|
||||
# crypto_onetimeauth_poly1305_init(&poly1305_state, block);
|
||||
# sodium_memzero(block, sizeof block);
|
||||
$auth = new ParagonIE_Sodium_Core_Poly1305_State(
|
||||
ParagonIE_Sodium_Core_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
|
||||
);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
|
||||
$auth->update($aad);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
|
||||
# (0x10 - adlen) & 0xf);
|
||||
$auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
|
||||
|
||||
# memset(block, 0, sizeof block);
|
||||
# block[0] = tag;
|
||||
# crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
|
||||
# state->nonce, 1U, state->k);
|
||||
$block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
|
||||
ParagonIE_Sodium_Core_Util::intToChr($tag) . str_repeat("\0", 63),
|
||||
$st->getCombinedNonce(),
|
||||
$st->getKey(),
|
||||
ParagonIE_Sodium_Core_Util::store64_le(1)
|
||||
);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
|
||||
$auth->update($block);
|
||||
|
||||
# out[0] = block[0];
|
||||
$out = $block[0];
|
||||
# c = out + (sizeof tag);
|
||||
# crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k);
|
||||
$cipher = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
|
||||
$msg,
|
||||
$st->getCombinedNonce(),
|
||||
$st->getKey(),
|
||||
ParagonIE_Sodium_Core_Util::store64_le(2)
|
||||
);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
|
||||
$auth->update($cipher);
|
||||
|
||||
$out .= $cipher;
|
||||
unset($cipher);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update
|
||||
# (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
|
||||
$auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
|
||||
|
||||
# STORE64_LE(slen, (uint64_t) adlen);
|
||||
$slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
$auth->update($slen);
|
||||
|
||||
# STORE64_LE(slen, (sizeof block) + mlen);
|
||||
$slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
$auth->update($slen);
|
||||
|
||||
# mac = c + mlen;
|
||||
# crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
|
||||
$mac = $auth->finish();
|
||||
$out .= $mac;
|
||||
|
||||
# sodium_memzero(&poly1305_state, sizeof poly1305_state);
|
||||
unset($auth);
|
||||
|
||||
|
||||
# XOR_BUF(STATE_INONCE(state), mac,
|
||||
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
|
||||
$st->xorNonce($mac);
|
||||
|
||||
# sodium_increment(STATE_COUNTER(state),
|
||||
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
|
||||
$st->incrementCounter();
|
||||
// Overwrite by reference:
|
||||
$state = $st->toString();
|
||||
|
||||
/** @var bool $rekey */
|
||||
$rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
|
||||
# if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
|
||||
# sodium_is_zero(STATE_COUNTER(state),
|
||||
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
|
||||
# crypto_secretstream_xchacha20poly1305_rekey(state);
|
||||
# }
|
||||
if ($rekey || $st->needsRekey()) {
|
||||
// DO REKEY
|
||||
self::secretstream_xchacha20poly1305_rekey($state);
|
||||
}
|
||||
# if (outlen_p != NULL) {
|
||||
# *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen;
|
||||
# }
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
* @param string $cipher
|
||||
* @param string $aad
|
||||
* @return bool|array{0: string, 1: int}
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '')
|
||||
{
|
||||
$st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
|
||||
|
||||
$cipherlen = ParagonIE_Sodium_Core_Util::strlen($cipher);
|
||||
# mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
|
||||
$msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
|
||||
$aadlen = ParagonIE_Sodium_Core_Util::strlen($aad);
|
||||
|
||||
# if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
|
||||
# sodium_misuse();
|
||||
# }
|
||||
if ((($msglen + 63) >> 6) > 0xfffffffe) {
|
||||
throw new SodiumException(
|
||||
'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
|
||||
);
|
||||
}
|
||||
|
||||
# crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
|
||||
# crypto_onetimeauth_poly1305_init(&poly1305_state, block);
|
||||
# sodium_memzero(block, sizeof block);
|
||||
$auth = new ParagonIE_Sodium_Core_Poly1305_State(
|
||||
ParagonIE_Sodium_Core_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
|
||||
);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
|
||||
$auth->update($aad);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
|
||||
# (0x10 - adlen) & 0xf);
|
||||
$auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
|
||||
|
||||
|
||||
# memset(block, 0, sizeof block);
|
||||
# block[0] = in[0];
|
||||
# crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
|
||||
# state->nonce, 1U, state->k);
|
||||
$block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
|
||||
$cipher[0] . str_repeat("\0", 63),
|
||||
$st->getCombinedNonce(),
|
||||
$st->getKey(),
|
||||
ParagonIE_Sodium_Core_Util::store64_le(1)
|
||||
);
|
||||
# tag = block[0];
|
||||
# block[0] = in[0];
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
|
||||
$tag = ParagonIE_Sodium_Core_Util::chrToInt($block[0]);
|
||||
$block[0] = $cipher[0];
|
||||
$auth->update($block);
|
||||
|
||||
|
||||
# c = in + (sizeof tag);
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
|
||||
$auth->update(ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen));
|
||||
|
||||
# crypto_onetimeauth_poly1305_update
|
||||
# (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
|
||||
$auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
|
||||
|
||||
# STORE64_LE(slen, (uint64_t) adlen);
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
$slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen);
|
||||
$auth->update($slen);
|
||||
|
||||
# STORE64_LE(slen, (sizeof block) + mlen);
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
$slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen);
|
||||
$auth->update($slen);
|
||||
|
||||
# crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
|
||||
# sodium_memzero(&poly1305_state, sizeof poly1305_state);
|
||||
$mac = $auth->finish();
|
||||
|
||||
# stored_mac = c + mlen;
|
||||
# if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
|
||||
# sodium_memzero(mac, sizeof mac);
|
||||
# return -1;
|
||||
# }
|
||||
|
||||
$stored = ParagonIE_Sodium_Core_Util::substr($cipher, $msglen + 1, 16);
|
||||
if (!ParagonIE_Sodium_Core_Util::hashEquals($mac, $stored)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
# crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k);
|
||||
$out = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
|
||||
ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen),
|
||||
$st->getCombinedNonce(),
|
||||
$st->getKey(),
|
||||
ParagonIE_Sodium_Core_Util::store64_le(2)
|
||||
);
|
||||
|
||||
# XOR_BUF(STATE_INONCE(state), mac,
|
||||
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
|
||||
$st->xorNonce($mac);
|
||||
|
||||
# sodium_increment(STATE_COUNTER(state),
|
||||
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
|
||||
$st->incrementCounter();
|
||||
|
||||
# if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
|
||||
# sodium_is_zero(STATE_COUNTER(state),
|
||||
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
|
||||
# crypto_secretstream_xchacha20poly1305_rekey(state);
|
||||
# }
|
||||
|
||||
// Overwrite by reference:
|
||||
$state = $st->toString();
|
||||
|
||||
/** @var bool $rekey */
|
||||
$rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
|
||||
if ($rekey || $st->needsRekey()) {
|
||||
// DO REKEY
|
||||
self::secretstream_xchacha20poly1305_rekey($state);
|
||||
}
|
||||
return array($out, $tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
* @return void
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function secretstream_xchacha20poly1305_rekey(&$state)
|
||||
{
|
||||
$st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
|
||||
# unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES +
|
||||
# crypto_secretstream_xchacha20poly1305_INONCEBYTES];
|
||||
# size_t i;
|
||||
# for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
|
||||
# new_key_and_inonce[i] = state->k[i];
|
||||
# }
|
||||
$new_key_and_inonce = $st->getKey();
|
||||
|
||||
# for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
|
||||
# new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] =
|
||||
# STATE_INONCE(state)[i];
|
||||
# }
|
||||
$new_key_and_inonce .= ParagonIE_Sodium_Core_Util::substR($st->getNonce(), 0, 8);
|
||||
|
||||
# crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce,
|
||||
# sizeof new_key_and_inonce,
|
||||
# state->nonce, state->k);
|
||||
|
||||
$st->rekey(ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
|
||||
$new_key_and_inonce,
|
||||
$st->getCombinedNonce(),
|
||||
$st->getKey(),
|
||||
ParagonIE_Sodium_Core_Util::store64_le(0)
|
||||
));
|
||||
|
||||
# for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
|
||||
# state->k[i] = new_key_and_inonce[i];
|
||||
# }
|
||||
# for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
|
||||
# STATE_INONCE(state)[i] =
|
||||
# new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i];
|
||||
# }
|
||||
# _crypto_secretstream_xchacha20poly1305_counter_reset(state);
|
||||
$st->counterReset();
|
||||
|
||||
$state = $st->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detached Ed25519 signature.
|
||||
*
|
||||
|
|
|
@ -776,6 +776,53 @@ abstract class ParagonIE_Sodium_Crypto32
|
|||
return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a hashing context for BLAKE2b.
|
||||
*
|
||||
* @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
|
||||
*
|
||||
* @param string $key
|
||||
* @param int $outputLength
|
||||
* @param string $salt
|
||||
* @param string $personal
|
||||
* @return string
|
||||
* @throws RangeException
|
||||
* @throws SodiumException
|
||||
* @throws TypeError
|
||||
*/
|
||||
public static function generichash_init_salt_personal(
|
||||
$key = '',
|
||||
$outputLength = 32,
|
||||
$salt = '',
|
||||
$personal = ''
|
||||
) {
|
||||
// This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
|
||||
ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
|
||||
|
||||
$k = null;
|
||||
if (!empty($key)) {
|
||||
$k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
|
||||
if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
|
||||
throw new RangeException('Invalid key size');
|
||||
}
|
||||
}
|
||||
if (!empty($salt)) {
|
||||
$s = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($salt);
|
||||
} else {
|
||||
$s = null;
|
||||
}
|
||||
if (!empty($salt)) {
|
||||
$p = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($personal);
|
||||
} else {
|
||||
$p = null;
|
||||
}
|
||||
|
||||
/** @var SplFixedArray $ctx */
|
||||
$ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength, $s, $p);
|
||||
|
||||
return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a hashing context for BLAKE2b with $message
|
||||
*
|
||||
|
@ -1184,6 +1231,362 @@ abstract class ParagonIE_Sodium_Crypto32
|
|||
return $m;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return array<int, string> Returns a state and a header.
|
||||
* @throws Exception
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function secretstream_xchacha20poly1305_init_push($key)
|
||||
{
|
||||
# randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES);
|
||||
$out = random_bytes(24);
|
||||
|
||||
# crypto_core_hchacha20(state->k, out, k, NULL);
|
||||
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20($out, $key);
|
||||
$state = new ParagonIE_Sodium_Core32_SecretStream_State(
|
||||
$subkey,
|
||||
ParagonIE_Sodium_Core32_Util::substr($out, 16, 8) . str_repeat("\0", 4)
|
||||
);
|
||||
|
||||
# _crypto_secretstream_xchacha20poly1305_counter_reset(state);
|
||||
$state->counterReset();
|
||||
|
||||
# memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES,
|
||||
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
|
||||
# memset(state->_pad, 0, sizeof state->_pad);
|
||||
return array(
|
||||
$state->toString(),
|
||||
$out
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param string $header
|
||||
* @return string Returns a state.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function secretstream_xchacha20poly1305_init_pull($key, $header)
|
||||
{
|
||||
# crypto_core_hchacha20(state->k, in, k, NULL);
|
||||
$subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
|
||||
ParagonIE_Sodium_Core32_Util::substr($header, 0, 16),
|
||||
$key
|
||||
);
|
||||
$state = new ParagonIE_Sodium_Core32_SecretStream_State(
|
||||
$subkey,
|
||||
ParagonIE_Sodium_Core32_Util::substr($header, 16)
|
||||
);
|
||||
$state->counterReset();
|
||||
# memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES,
|
||||
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
|
||||
# memset(state->_pad, 0, sizeof state->_pad);
|
||||
# return 0;
|
||||
return $state->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
* @param string $msg
|
||||
* @param string $aad
|
||||
* @param int $tag
|
||||
* @return string
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
|
||||
{
|
||||
$st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
|
||||
# crypto_onetimeauth_poly1305_state poly1305_state;
|
||||
# unsigned char block[64U];
|
||||
# unsigned char slen[8U];
|
||||
# unsigned char *c;
|
||||
# unsigned char *mac;
|
||||
|
||||
$msglen = ParagonIE_Sodium_Core32_Util::strlen($msg);
|
||||
$aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad);
|
||||
|
||||
if ((($msglen + 63) >> 6) > 0xfffffffe) {
|
||||
throw new SodiumException(
|
||||
'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
|
||||
);
|
||||
}
|
||||
|
||||
# if (outlen_p != NULL) {
|
||||
# *outlen_p = 0U;
|
||||
# }
|
||||
# if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
|
||||
# sodium_misuse();
|
||||
# }
|
||||
|
||||
# crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
|
||||
# crypto_onetimeauth_poly1305_init(&poly1305_state, block);
|
||||
# sodium_memzero(block, sizeof block);
|
||||
$auth = new ParagonIE_Sodium_Core32_Poly1305_State(
|
||||
ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
|
||||
);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
|
||||
$auth->update($aad);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
|
||||
# (0x10 - adlen) & 0xf);
|
||||
$auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
|
||||
|
||||
# memset(block, 0, sizeof block);
|
||||
# block[0] = tag;
|
||||
# crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
|
||||
# state->nonce, 1U, state->k);
|
||||
$block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
|
||||
ParagonIE_Sodium_Core32_Util::intToChr($tag) . str_repeat("\0", 63),
|
||||
$st->getCombinedNonce(),
|
||||
$st->getKey(),
|
||||
ParagonIE_Sodium_Core32_Util::store64_le(1)
|
||||
);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
|
||||
$auth->update($block);
|
||||
|
||||
# out[0] = block[0];
|
||||
$out = $block[0];
|
||||
# c = out + (sizeof tag);
|
||||
# crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k);
|
||||
$cipher = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
|
||||
$msg,
|
||||
$st->getCombinedNonce(),
|
||||
$st->getKey(),
|
||||
ParagonIE_Sodium_Core32_Util::store64_le(2)
|
||||
);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
|
||||
$auth->update($cipher);
|
||||
|
||||
$out .= $cipher;
|
||||
unset($cipher);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update
|
||||
# (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
|
||||
$auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
|
||||
|
||||
# STORE64_LE(slen, (uint64_t) adlen);
|
||||
$slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
$auth->update($slen);
|
||||
|
||||
# STORE64_LE(slen, (sizeof block) + mlen);
|
||||
$slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
$auth->update($slen);
|
||||
|
||||
# mac = c + mlen;
|
||||
# crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
|
||||
$mac = $auth->finish();
|
||||
$out .= $mac;
|
||||
|
||||
# sodium_memzero(&poly1305_state, sizeof poly1305_state);
|
||||
unset($auth);
|
||||
|
||||
|
||||
# XOR_BUF(STATE_INONCE(state), mac,
|
||||
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
|
||||
$st->xorNonce($mac);
|
||||
|
||||
# sodium_increment(STATE_COUNTER(state),
|
||||
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
|
||||
$st->incrementCounter();
|
||||
// Overwrite by reference:
|
||||
$state = $st->toString();
|
||||
|
||||
/** @var bool $rekey */
|
||||
$rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
|
||||
# if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
|
||||
# sodium_is_zero(STATE_COUNTER(state),
|
||||
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
|
||||
# crypto_secretstream_xchacha20poly1305_rekey(state);
|
||||
# }
|
||||
if ($rekey || $st->needsRekey()) {
|
||||
// DO REKEY
|
||||
self::secretstream_xchacha20poly1305_rekey($state);
|
||||
}
|
||||
# if (outlen_p != NULL) {
|
||||
# *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen;
|
||||
# }
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
* @param string $cipher
|
||||
* @param string $aad
|
||||
* @return bool|array{0: string, 1: int}
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '')
|
||||
{
|
||||
$st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
|
||||
|
||||
$cipherlen = ParagonIE_Sodium_Core32_Util::strlen($cipher);
|
||||
# mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
|
||||
$msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
|
||||
$aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad);
|
||||
|
||||
# if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
|
||||
# sodium_misuse();
|
||||
# }
|
||||
if ((($msglen + 63) >> 6) > 0xfffffffe) {
|
||||
throw new SodiumException(
|
||||
'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
|
||||
);
|
||||
}
|
||||
|
||||
# crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
|
||||
# crypto_onetimeauth_poly1305_init(&poly1305_state, block);
|
||||
# sodium_memzero(block, sizeof block);
|
||||
$auth = new ParagonIE_Sodium_Core32_Poly1305_State(
|
||||
ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
|
||||
);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
|
||||
$auth->update($aad);
|
||||
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
|
||||
# (0x10 - adlen) & 0xf);
|
||||
$auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
|
||||
|
||||
|
||||
# memset(block, 0, sizeof block);
|
||||
# block[0] = in[0];
|
||||
# crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
|
||||
# state->nonce, 1U, state->k);
|
||||
$block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
|
||||
$cipher[0] . str_repeat("\0", 63),
|
||||
$st->getCombinedNonce(),
|
||||
$st->getKey(),
|
||||
ParagonIE_Sodium_Core32_Util::store64_le(1)
|
||||
);
|
||||
# tag = block[0];
|
||||
# block[0] = in[0];
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
|
||||
$tag = ParagonIE_Sodium_Core32_Util::chrToInt($block[0]);
|
||||
$block[0] = $cipher[0];
|
||||
$auth->update($block);
|
||||
|
||||
|
||||
# c = in + (sizeof tag);
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
|
||||
$auth->update(ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen));
|
||||
|
||||
# crypto_onetimeauth_poly1305_update
|
||||
# (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
|
||||
$auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
|
||||
|
||||
# STORE64_LE(slen, (uint64_t) adlen);
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
$slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen);
|
||||
$auth->update($slen);
|
||||
|
||||
# STORE64_LE(slen, (sizeof block) + mlen);
|
||||
# crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
|
||||
$slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen);
|
||||
$auth->update($slen);
|
||||
|
||||
# crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
|
||||
# sodium_memzero(&poly1305_state, sizeof poly1305_state);
|
||||
$mac = $auth->finish();
|
||||
|
||||
# stored_mac = c + mlen;
|
||||
# if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
|
||||
# sodium_memzero(mac, sizeof mac);
|
||||
# return -1;
|
||||
# }
|
||||
|
||||
$stored = ParagonIE_Sodium_Core32_Util::substr($cipher, $msglen + 1, 16);
|
||||
if (!ParagonIE_Sodium_Core32_Util::hashEquals($mac, $stored)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
# crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k);
|
||||
$out = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
|
||||
ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen),
|
||||
$st->getCombinedNonce(),
|
||||
$st->getKey(),
|
||||
ParagonIE_Sodium_Core32_Util::store64_le(2)
|
||||
);
|
||||
|
||||
# XOR_BUF(STATE_INONCE(state), mac,
|
||||
# crypto_secretstream_xchacha20poly1305_INONCEBYTES);
|
||||
$st->xorNonce($mac);
|
||||
|
||||
# sodium_increment(STATE_COUNTER(state),
|
||||
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
|
||||
$st->incrementCounter();
|
||||
|
||||
# if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
|
||||
# sodium_is_zero(STATE_COUNTER(state),
|
||||
# crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
|
||||
# crypto_secretstream_xchacha20poly1305_rekey(state);
|
||||
# }
|
||||
|
||||
// Overwrite by reference:
|
||||
$state = $st->toString();
|
||||
|
||||
/** @var bool $rekey */
|
||||
$rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
|
||||
if ($rekey || $st->needsRekey()) {
|
||||
// DO REKEY
|
||||
self::secretstream_xchacha20poly1305_rekey($state);
|
||||
}
|
||||
return array($out, $tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
* @return void
|
||||
* @throws SodiumException
|
||||
*/
|
||||
public static function secretstream_xchacha20poly1305_rekey(&$state)
|
||||
{
|
||||
$st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
|
||||
# unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES +
|
||||
# crypto_secretstream_xchacha20poly1305_INONCEBYTES];
|
||||
# size_t i;
|
||||
# for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
|
||||
# new_key_and_inonce[i] = state->k[i];
|
||||
# }
|
||||
$new_key_and_inonce = $st->getKey();
|
||||
|
||||
# for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
|
||||
# new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] =
|
||||
# STATE_INONCE(state)[i];
|
||||
# }
|
||||
$new_key_and_inonce .= ParagonIE_Sodium_Core32_Util::substR($st->getNonce(), 0, 8);
|
||||
|
||||
# crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce,
|
||||
# sizeof new_key_and_inonce,
|
||||
# state->nonce, state->k);
|
||||
|
||||
$st->rekey(ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
|
||||
$new_key_and_inonce,
|
||||
$st->getCombinedNonce(),
|
||||
$st->getKey(),
|
||||
ParagonIE_Sodium_Core32_Util::store64_le(0)
|
||||
));
|
||||
|
||||
# for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
|
||||
# state->k[i] = new_key_and_inonce[i];
|
||||
# }
|
||||
# for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
|
||||
# STATE_INONCE(state)[i] =
|
||||
# new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i];
|
||||
# }
|
||||
# _crypto_secretstream_xchacha20poly1305_counter_reset(state);
|
||||
$st->counterReset();
|
||||
|
||||
$state = $st->toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detached Ed25519 signature.
|
||||
*
|
||||
|
|
|
@ -679,7 +679,11 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util
|
|||
}
|
||||
|
||||
/* Security checks */
|
||||
if (ParagonIE_Sodium_Core_Ed25519::check_S_lt_L(self::substr($sig, 32, 32))) {
|
||||
if (
|
||||
(ParagonIE_Sodium_Core_Ed25519::chrToInt($sig[63]) & 240)
|
||||
&&
|
||||
ParagonIE_Sodium_Core_Ed25519::check_S_lt_L(self::substr($sig, 32, 32))
|
||||
) {
|
||||
throw new SodiumException('S < L - Invalid signature');
|
||||
}
|
||||
if (ParagonIE_Sodium_Core_Ed25519::small_order($sig)) {
|
||||
|
@ -841,7 +845,7 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util
|
|||
if (!is_string($plaintext)) {
|
||||
throw new SodiumException('Could not read input file');
|
||||
}
|
||||
$first32 = ftell($ifp);
|
||||
$first32 = self::ftell($ifp);
|
||||
|
||||
/** @var string $subkey */
|
||||
$subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key);
|
||||
|
@ -875,7 +879,7 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util
|
|||
);
|
||||
|
||||
// Pre-write 16 blank bytes for the Poly1305 tag
|
||||
$start = ftell($ofp);
|
||||
$start = self::ftell($ofp);
|
||||
fwrite($ofp, str_repeat("\x00", 16));
|
||||
|
||||
/** @var string $c */
|
||||
|
@ -926,7 +930,7 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util
|
|||
$block0 = null;
|
||||
$subkey = null;
|
||||
}
|
||||
$end = ftell($ofp);
|
||||
$end = self::ftell($ofp);
|
||||
|
||||
/*
|
||||
* Write the Poly1305 authentication tag that provides integrity
|
||||
|
@ -1043,7 +1047,7 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util
|
|||
$mlen = 0
|
||||
) {
|
||||
/** @var int $pos */
|
||||
$pos = ftell($ifp);
|
||||
$pos = self::ftell($ifp);
|
||||
|
||||
/** @var int $iter */
|
||||
$iter = 1;
|
||||
|
@ -1106,7 +1110,7 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util
|
|||
}
|
||||
|
||||
/** @var int $originalPosition */
|
||||
$originalPosition = ftell($fp);
|
||||
$originalPosition = self::ftell($fp);
|
||||
|
||||
// Move file pointer to beginning of file
|
||||
fseek($fp, 0, SEEK_SET);
|
||||
|
@ -1314,7 +1318,7 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util
|
|||
if (!is_string($plaintext)) {
|
||||
throw new SodiumException('Could not read input file');
|
||||
}
|
||||
$first32 = ftell($ifp);
|
||||
$first32 = self::ftell($ifp);
|
||||
|
||||
/** @var string $subkey */
|
||||
$subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
|
||||
|
@ -1348,7 +1352,7 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util
|
|||
);
|
||||
|
||||
// Pre-write 16 blank bytes for the Poly1305 tag
|
||||
$start = ftell($ofp);
|
||||
$start = self::ftell($ofp);
|
||||
fwrite($ofp, str_repeat("\x00", 16));
|
||||
|
||||
/** @var string $c */
|
||||
|
@ -1399,7 +1403,7 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util
|
|||
$block0 = null;
|
||||
$subkey = null;
|
||||
}
|
||||
$end = ftell($ofp);
|
||||
$end = self::ftell($ofp);
|
||||
|
||||
/*
|
||||
* Write the Poly1305 authentication tag that provides integrity
|
||||
|
@ -1515,7 +1519,7 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util
|
|||
$mlen = 0
|
||||
) {
|
||||
/** @var int $pos */
|
||||
$pos = ftell($ifp);
|
||||
$pos = self::ftell($ifp);
|
||||
|
||||
/** @var int $iter */
|
||||
$iter = 1;
|
||||
|
@ -1540,4 +1544,18 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util
|
|||
fseek($ifp, $pos, SEEK_SET);
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resource $resource
|
||||
* @return int
|
||||
* @throws SodiumException
|
||||
*/
|
||||
private static function ftell($resource)
|
||||
{
|
||||
$return = ftell($resource);
|
||||
if (!is_int($return)) {
|
||||
throw new SodiumException('ftell() returned false');
|
||||
}
|
||||
return (int) $return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
<?php
|
||||
|
||||
if (class_exists('SplFixedArray')) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The SplFixedArray class provides the main functionalities of array. The
|
||||
* main differences between a SplFixedArray and a normal PHP array is that
|
||||
* the SplFixedArray is of fixed length and allows only integers within
|
||||
* the range as indexes. The advantage is that it allows a faster array
|
||||
* implementation.
|
||||
*/
|
||||
class SplFixedArray implements Iterator, ArrayAccess, Countable
|
||||
{
|
||||
/** @var array<int, mixed> */
|
||||
private $internalArray = array();
|
||||
|
||||
/** @var int $size */
|
||||
private $size = 0;
|
||||
|
||||
/**
|
||||
* SplFixedArray constructor.
|
||||
* @param int $size
|
||||
*/
|
||||
public function __construct($size = 0)
|
||||
{
|
||||
$this->size = $size;
|
||||
$this->internalArray = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->internalArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
ksort($this->internalArray);
|
||||
return (array) $this->internalArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
* @param bool $save_indexes
|
||||
* @return SplFixedArray
|
||||
* @psalm-suppress MixedAssignment
|
||||
*/
|
||||
public static function fromArray(array $array, $save_indexes = true)
|
||||
{
|
||||
$self = new SplFixedArray(count($array));
|
||||
if($save_indexes) {
|
||||
foreach($array as $key => $value) {
|
||||
$self[(int) $key] = $value;
|
||||
}
|
||||
} else {
|
||||
$i = 0;
|
||||
foreach (array_values($array) as $value) {
|
||||
$self[$i] = $value;
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
return $self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $size
|
||||
* @return bool
|
||||
*/
|
||||
public function setSize($size)
|
||||
{
|
||||
$this->size = $size;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int $index
|
||||
* @return bool
|
||||
*/
|
||||
public function offsetExists($index)
|
||||
{
|
||||
return array_key_exists((int) $index, $this->internalArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int $index
|
||||
* @return mixed
|
||||
*/
|
||||
public function offsetGet($index)
|
||||
{
|
||||
return $this->internalArray[(int) $index];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int $index
|
||||
* @param mixed $newval
|
||||
* @psalm-suppress MixedAssignment
|
||||
*/
|
||||
public function offsetSet($index, $newval)
|
||||
{
|
||||
$this->internalArray[(int) $index] = $newval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int $index
|
||||
*/
|
||||
public function offsetUnset($index)
|
||||
{
|
||||
unset($this->internalArray[(int) $index]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewind iterator back to the start
|
||||
* @link https://php.net/manual/en/splfixedarray.rewind.php
|
||||
* @return void
|
||||
* @since 5.3.0
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
reset($this->internalArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return current array entry
|
||||
* @link https://php.net/manual/en/splfixedarray.current.php
|
||||
* @return mixed The current element value.
|
||||
* @since 5.3.0
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return current($this->internalArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return current array index
|
||||
* @return int The current array index.
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return key($this->internalArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
next($this->internalArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the array contains more elements
|
||||
* @link https://php.net/manual/en/splfixedarray.valid.php
|
||||
* @return bool true if the array contains any more elements, false otherwise.
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
if (empty($this->internalArray)) {
|
||||
return false;
|
||||
}
|
||||
$result = next($this->internalArray) !== false;
|
||||
prev($this->internalArray);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing.
|
||||
*/
|
||||
public function __wakeup()
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
*
|
||||
* @global string $wp_version
|
||||
*/
|
||||
$wp_version = '5.4-alpha-46856';
|
||||
$wp_version = '5.4-alpha-46858';
|
||||
|
||||
/**
|
||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||
|
|
Loading…
Reference in New Issue