tipo: modificación del cpanel y gitignore de la carpeta vendor

This commit is contained in:
2026-07-07 11:35:09 -06:00
parent a0c91dc567
commit 676ef0d506
8510 changed files with 1132803 additions and 4 deletions
+74
View File
@@ -0,0 +1,74 @@
# Contributing Guidelines
Thank you for your interest in contributing to sodium_compat. This document should help you get up and running.
## Branches
This project maintains two main branches:
* `master`: This is the active development branch for the latest major version of `sodium_compat`.
It only supports PHP 8.1 and newer..
* `v1.x`: This branch supports a wider range of PHP versions, from 5.2.x up to the latest. Many projects that need to
support older version of PHP, such as WordPress, depend on the releases cut from the v1.x branch.
## Code Quality and Security
This is a cryptography library, so security is of the utmost importance.
We follow the principles of [Cryptographically Secure PHP Development](https://paragonie.com/blog/2017/02/cryptographically-secure-php-development).
Before contributing, please read the linked blog post.
## Scope of Contributions
This library is a polyfill for [libsodium](https://github.com/jedisct1/libsodium). Therefore, we will only consider
contributions that implement features already present in libsodium proper.
### Reporting Security Vulnerabilities
Please email `security at paragonie dot com` to disclose a security issue with sodium_compat. If you are reporting a
cryptographic weakness that also applies to libsodium, please disclose it upstream to libsodium first.
## Testing
### Unit Testing
Before submitting a pull request, please ensure that all unit tests pass.
You can run the tests using Composer:
```terminal
composer test
```
If you want to go the extra mile (at the cost of a longer test runtime), run the pedantic tests too:
```terminal
vendor/bin/phpunit --bootstrap=autoload-pedantic.php
```
Paragon Initiative Enterprises runs the pedantic tests before every release is cut.
### Mutation Testing
We use [Infection](https://infection.github.io) for mutation testing.
```bash
composer mutation-test
```
Please be aware that this command can take a long time to complete, and will generate some false positives.
### Fuzz Testing
We use [Nikita Popov's PHP-Fuzzer](https://github.com/nikic/PHP-Fuzzer) for fuzz testing. To run the fuzz tests, use the
following command:
```bash
composer fuzz-test
```
This command runs for a long time. To limit the fuzzer to 1000 runs:
```bash
vendor/bin/php-fuzzer --max-runs 1000 fuzz fuzzing/FuzzSodiumCompat.php
```
+16
View File
@@ -0,0 +1,16 @@
ISC License
Copyright (c) 2016-2024, Paragon Initiative Enterprises <security at paragonie dot com>
Copyright (c) 2013-2019, Frank Denis <j at pureftpd dot org>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+368
View File
@@ -0,0 +1,368 @@
# Sodium Compat
[![Build Status](https://github.com/paragonie/sodium_compat/actions/workflows/ci.yml/badge.svg)](https://github.com/paragonie/sodium_compat/actions)
[![Psalm Status](https://github.com/paragonie/sodium_compat/actions/workflows/psalm.yml/badge.svg)](https://github.com/paragonie/sodium_compat/actions)
[![Latest Stable Version](https://poser.pugx.org/paragonie/sodium_compat/v/stable)](https://packagist.org/packages/paragonie/sodium_compat)
[![Latest Unstable Version](https://poser.pugx.org/paragonie/sodium_compat/v/unstable)](https://packagist.org/packages/paragonie/sodium_compat)
[![License](https://poser.pugx.org/paragonie/sodium_compat/license)](https://packagist.org/packages/paragonie/sodium_compat)
[![Downloads](https://img.shields.io/packagist/dt/paragonie/sodium_compat.svg)](https://packagist.org/packages/paragonie/sodium_compat)
Sodium Compat is a pure PHP polyfill for the Sodium cryptography library
(libsodium), a core extension in PHP 7.2.0+ and otherwise [available in PECL](https://pecl.php.net/package/libsodium).
If you have the PHP extension installed, Sodium Compat will opportunistically
and transparently use the PHP extension instead of our implementation.
## Major Versions and Branches
sodium_compat v1.21.0 was the last v1.x release from the master branch. From now
on, all future releases that support PHP 5.2 - 8.0 and 32-bit integers will be
[in the `v1.x` branch](https://github.com/paragonie/sodium_compat/tree/v1.x).
Newer versions of sodium_compat (i.e., v2.0.0) will continue to live in the master
branch, unless a new major version is needed. The goal of this work is to improve
code readability and performance, while reducing boilerplate code.
When in doubt, refer to the README file in [the master branch](https://github.com/paragonie/sodium_compat/blob/master/README.md)
for the latest in version information.
### Which version should I use?
| sodium_compat version | PHP versions supported | 32-bit support? | Branch |
|-----------------------|------------------------|-----------------|---------------------------------------------------------------|
| `v1.x.y` | 5.2.4 - LATEST | YES | [v1.x](https://github.com/paragonie/sodium_compat/tree/v1.x) |
| `v2.x.y` | 8.1 - LATEST | NO | **master** |
If you need 32-bit PHP support (`PHP_INT_SIZE == 4`), continue using sodium_compat v1.x.
If you want improved performance and smaller dependencies, use v2.x.
We recommend libraries and frameworks set a Composer version constraint as follows:
```javascript
{
"require": {
/* ... */
"paragonie/sodium_compat": ">= 1"
/* ... */
}
}
```
Applications should, conversely, specify the actual version that matters to them
and their deployments.
## IMPORTANT!
This cryptography library has not been formally audited by an independent third
party that specializes in cryptography or cryptanalysis.
If you require such an audit before you can use sodium_compat in your projects
and have the funds for such an audit, please open an issue or contact
`security at paragonie dot com` so we can help get the ball rolling.
However, sodium_compat has been adopted by high profile open source projects,
such as [Joomla!](https://github.com/joomla/joomla-cms/blob/459d74686d2a638ec51149d7c44ddab8075852be/composer.json#L40)
and [Magento](https://github.com/magento/magento2/blob/8fd89cfdf52c561ac0ca7bc20fd38ef688e201b0/composer.json#L44).
Furthermore, sodium_compat was developed by Paragon Initiative Enterprises, a
company that *specializes* in secure PHP development and PHP cryptography, and
has been informally reviewed by many other security experts who also specialize
in PHP.
If you'd like to learn more about the defensive security measures we've taken
to prevent sodium_compat from being a source of vulnerability in your systems,
please read [*Cryptographically Secure PHP Development*](https://paragonie.com/blog/2017/02/cryptographically-secure-php-development).
# Installing Sodium Compat
If you're using Composer:
```bash
composer require paragonie/sodium_compat
```
### Install From Source
If you're not using Composer, download a [release tarball](https://github.com/paragonie/sodium_compat/releases)
(which should be signed with [our GnuPG public key](https://paragonie.com/static/gpg-public-key.txt)), extract
its contents, then include our `autoload.php` script in your project.
```php
<?php
require_once "/path/to/sodium_compat/autoload.php";
```
### PHP Archives (Phar) Releases
Since version 1.3.0, [sodium_compat releases](https://github.com/paragonie/sodium_compat/releases) include a
PHP Archive (.phar file) and associated GPG signature. First, download both files and verify them with our
GPG public key, like so:
```bash
# Getting our public key from the keyserver:
gpg --fingerprint 7F52D5C61D1255C731362E826B97A1C2826404DA
if [ $? -ne 0 ]; then
echo -e "\033[33mDownloading PGP Public Key...\033[0m"
gpg --keyserver pgp.mit.edu --recv-keys 7F52D5C61D1255C731362E826B97A1C2826404DA
# Security <security@paragonie.com>
gpg --fingerprint 7F52D5C61D1255C731362E826B97A1C2826404DA
if [ $? -ne 0 ]; then
echo -e "\033[31mCould not download PGP public key for verification\033[0m"
exit 1
fi
fi
# Verifying the PHP Archive
gpg --verify sodium-compat.phar.sig sodium-compat.phar
```
Now, simply include this .phar file in your application.
```php
<?php
require_once "/path/to/sodium-compat.phar";
```
# Support
[Commercial support for libsodium](https://download.libsodium.org/doc/commercial_support/) is available
from multiple vendors. If you need help using sodium_compat in one of your projects, [contact Paragon Initiative Enterprises](https://paragonie.com/contact).
Non-commercial report will be facilitated through [Github issues](https://github.com/paragonie/sodium_compat/issues).
We offer no guarantees of our availability to resolve questions about integrating sodium_compat into third-party
software for free, but will strive to fix any bugs (security-related or otherwise) in our library.
## Support Contracts
If your company uses this library in their products or services, you may be
interested in [purchasing a support contract from Paragon Initiative Enterprises](https://paragonie.com/enterprise).
# Using Sodium Compat
## True Polyfill
As per the [second vote on the libsodium RFC](https://wiki.php.net/rfc/libsodium#proposed_voting_choices),
PHP 7.2 uses `sodium_*` instead of `\Sodium\*`.
```php
<?php
require_once "/path/to/sodium_compat/autoload.php";
$alice_kp = sodium_crypto_sign_keypair();
$alice_sk = sodium_crypto_sign_secretkey($alice_kp);
$alice_pk = sodium_crypto_sign_publickey($alice_kp);
$message = 'This is a test message.';
$signature = sodium_crypto_sign_detached($message, $alice_sk);
if (sodium_crypto_sign_verify_detached($signature, $message, $alice_pk)) {
echo 'OK', PHP_EOL;
} else {
throw new Exception('Invalid signature');
}
```
## General-Use Polyfill
If your users are on PHP < 5.3, or you want to write code that will work
whether or not the PECL extension is available, you'll want to use the
**`ParagonIE_Sodium_Compat`** class for most of your libsodium needs.
The above example, written for general use:
```php
<?php
require_once "/path/to/sodium_compat/autoload.php";
$alice_kp = ParagonIE_Sodium_Compat::crypto_sign_keypair();
$alice_sk = ParagonIE_Sodium_Compat::crypto_sign_secretkey($alice_kp);
$alice_pk = ParagonIE_Sodium_Compat::crypto_sign_publickey($alice_kp);
$message = 'This is a test message.';
$signature = ParagonIE_Sodium_Compat::crypto_sign_detached($message, $alice_sk);
if (ParagonIE_Sodium_Compat::crypto_sign_verify_detached($signature, $message, $alice_pk)) {
echo 'OK', PHP_EOL;
} else {
throw new Exception('Invalid signature');
}
```
Generally: If you replace `sodium_` with `ParagonIE_Sodium_Compat::`, any
code already written for the libsodium PHP extension should work with our
polyfill without additional code changes.
Since this doesn't require a namespace, this API *is* exposed on PHP 5.2.
Since version 0.7.0, we have our own namespaced API (`ParagonIE\Sodium\*`) to allow brevity
in software that uses PHP 5.3+. This is useful if you want to use our file cryptography
features without writing `ParagonIE_Sodium_File` every time. This is not exposed on PHP < 5.3,
so if your project supports PHP < 5.3, use the underscore method instead.
To learn how to use Libsodium, read [*Using Libsodium in PHP Projects*](https://paragonie.com/book/pecl-libsodium).
## Help, Sodium_Compat is Slow! How can I make it fast?
There are three ways to make it fast:
1. Use a newer version of PHP (at least 7.2).
2. [Install the libsodium PHP extension from PECL](https://paragonie.com/book/pecl-libsodium/read/00-intro.md#installing-libsodium).
3. Only if the previous two options are not available for you:
1. Verify that [the processor you're using actually implements constant-time multiplication](https://bearssl.org/ctmul.html).
Sodium_compat does, but it must trade some speed in order to attain cross-platform security.
2. Only if you are 100% certain that your processor is safe, you can set `ParagonIE_Sodium_Compat::$fastMult = true;`
without harming the security of your cryptography keys. If your processor *isn't* safe, then decide whether you
want speed or security because you can't have both.
### How can I tell if sodium_compat will be slow, at runtime?
Since version 1.8, you can use the `polyfill_is_fast()` static method to
determine if sodium_compat will be slow at runtime.
```php
<?php
if (ParagonIE_Sodium_Compat::polyfill_is_fast()) {
// Use libsodium now
$process->execute();
} else {
// Defer to a cron job or other sort of asynchronous process
$process->enqueue();
}
```
## Documentation
First, you'll want to read the [Libsodium Quick Reference](https://paragonie.com/blog/2017/06/libsodium-quick-reference-quick-comparison-similar-functions-and-which-one-use).
It aims to answer, "Which function should I use for [common problem]?".
If you don't find the answers in the Quick Reference page, check out
[*Using Libsodium in PHP Projects*](https://paragonie.com/book/pecl-libsodium).
Finally, the [official libsodium documentation](https://download.libsodium.org/doc/)
(which was written for the C library, not the PHP library) also contains a lot of
insightful technical information you may find helpful.
## API Coverage
**Recommended reading:** [Libsodium Quick Reference](https://paragonie.com/blog/2017/06/libsodium-quick-reference-quick-comparison-similar-functions-and-which-one-use)
* Mainline NaCl Features
* `crypto_auth()`
* `crypto_auth_verify()`
* `crypto_box()`
* `crypto_box_open()`
* `crypto_scalarmult()`
* `crypto_secretbox()`
* `crypto_secretbox_open()`
* `crypto_sign()`
* `crypto_sign_open()`
* PECL Libsodium Features
* `crypto_aead_aegis128l_encrypt()`
* `crypto_aead_aegis128l_decrypt()`
* `crypto_aead_aegis256_encrypt()`
* `crypto_aead_aegis256_decrypt()`
* `crypto_aead_aes256gcm_encrypt()`
* `crypto_aead_aes256gcm_decrypt()`
* `crypto_aead_chacha20poly1305_encrypt()`
* `crypto_aead_chacha20poly1305_decrypt()`
* `crypto_aead_chacha20poly1305_ietf_encrypt()`
* `crypto_aead_chacha20poly1305_ietf_decrypt()`
* `crypto_aead_xchacha20poly1305_ietf_encrypt()`
* `crypto_aead_xchacha20poly1305_ietf_decrypt()`
* `crypto_box_xchacha20poly1305()`
* `crypto_box_xchacha20poly1305_open()`
* `crypto_box_seal()`
* `crypto_box_seal_open()`
* `crypto_generichash()`
* `crypto_generichash_init()`
* `crypto_generichash_update()`
* `crypto_generichash_final()`
* `crypto_kx()`
* `crypto_secretbox_xchacha20poly1305()`
* `crypto_secretbox_xchacha20poly1305_open()`
* `crypto_shorthash()`
* `crypto_sign_detached()`
* `crypto_sign_ed25519_pk_to_curve25519()`
* `crypto_sign_ed25519_sk_to_curve25519()`
* `crypto_sign_verify_detached()`
* For advanced users only:
* `crypto_core_ristretto255_add()`
* `crypto_core_ristretto255_from_hash()`
* `crypto_core_ristretto255_is_valid_point()`
* `crypto_core_ristretto255_random()`
* `crypto_core_ristretto255_scalar_add()`
* `crypto_core_ristretto255_scalar_complement()`
* `crypto_core_ristretto255_scalar_invert()`
* `crypto_core_ristretto255_scalar_mul()`
* `crypto_core_ristretto255_scalar_negate()`
* `crypto_core_ristretto255_scalar_random()`
* `crypto_core_ristretto255_scalar_reduce()`
* `crypto_core_ristretto255_scalar_sub()`
* `crypto_core_ristretto255_sub()`
* `crypto_scalarmult_ristretto255_base()`
* `crypto_scalarmult_ristretto255()`
* `crypto_stream()`
* `crypto_stream_keygen()`
* `crypto_stream_xor()`
* `crypto_stream_xchacha20()`
* `crypto_stream_xchacha20_keygen()`
* `crypto_stream_xchacha20_xor()`
* `crypto_stream_xchacha20_xor_ic()`
* Other utilities (e.g. `crypto_*_keypair()`)
* `add()`
* `base642bin()`
* `bin2base64()`
* `bin2hex()`
* `hex2bin()`
* `crypto_kdf_derive_from_key()`
* `crypto_kx_client_session_keys()`
* `crypto_kx_server_session_keys()`
* `crypto_secretstream_xchacha20poly1305_init_push()`
* `crypto_secretstream_xchacha20poly1305_push()`
* `crypto_secretstream_xchacha20poly1305_init_pull()`
* `crypto_secretstream_xchacha20poly1305_pull()`
* `crypto_secretstream_xchacha20poly1305_rekey()`
* `pad()`
* `unpad()`
### Cryptography Primitives Provided
* **X25519** - Elliptic Curve Diffie Hellman over Curve25519
* **Ed25519** - Edwards curve Digital Signature Algorithm over Curve25519
* **Xsalsa20** - Extended-nonce Salsa20 stream cipher
* **ChaCha20** - Stream cipher
* **Xchacha20** - Extended-nonce ChaCha20 stream cipher
* **Poly1305** - Polynomial Evaluation Message Authentication Code modulo 2^130 - 5
* **BLAKE2b** - Cryptographic Hash Function
* **SipHash-2-4** - Fast hash, but not collision-resistant; ideal for hash tables.
### Features Excluded from this Polyfill
* `sodium_memzero()` - Although we expose this API endpoint, we can't reliably
zero buffers from PHP.
If you have the PHP extension installed, sodium_compat
will use the native implementation to zero out the string provided. Otherwise
it will throw a `SodiumException`.
* `sodium_crypto_pwhash()` - It's not feasible to polyfill scrypt or Argon2
into PHP and get reasonable performance. Users would feel motivated to select
parameters that downgrade security to avoid denial of service (DoS) attacks.
The only winning move is not to play.
If ext/sodium or ext/libsodium is installed, these API methods will fallthrough
to the extension. Otherwise, our polyfill library will throw a `SodiumException`.
To detect support for Argon2i at runtime, use
`ParagonIE_Sodium_Compat::crypto_pwhash_is_available()`, which returns a
boolean value (`TRUE` or `FALSE`).
* Libsodium's HKDF API (`crypto_kdf_hkdf_*()`) is not included because PHP has
its own [HMAC features](https://php.met/hash_hmac) amd it was not deemed necessary.
### PHPCompatibility Ruleset
For sodium_compat users and that utilize [`PHPCompatibility`](https://github.com/PHPCompatibility/PHPCompatibility)
in their CI process, there is now a custom ruleset available which can be used
to prevent false positives being thrown by `PHPCompatibility` for the native
PHP functionality being polyfilled by this repo.
You can find the repo for the `PHPCompatibilityParagonieSodiumCompat` ruleset
here [on Github](https://github.com/PHPCompatibility/PHPCompatibilityParagonie)
and [on Packagist](https://packagist.org/packages/phpcompatibility/phpcompatibility-paragonie).
+57
View File
@@ -0,0 +1,57 @@
<?php
spl_autoload_register(function ($class) {
$namespace = 'ParagonIE_Sodium_';
// Does the class use the namespace prefix?
$len = strlen($namespace);
if (strncmp($namespace, $class, $len) !== 0) {
// no, move to the next registered autoloader
return false;
}
// Get the relative class name
$relative_class = substr($class, $len);
// Replace the namespace prefix with the base directory, replace namespace
// separators with directory separators in the relative class name, append
// with .php
$file = dirname(__FILE__) . '/src/' . str_replace('_', '/', $relative_class) . '.php';
// if the file exists, require it
if (file_exists($file)) {
require_once $file;
return true;
}
return false;
});
/* Explicitly, always load the Compat class: */
if (!class_exists('ParagonIE_Sodium_Compat', false)) {
require_once dirname(__FILE__) . '/src/Compat.php';
}
if (!class_exists('ParagonIE_Sodium_File', false)) {
require_once dirname(__FILE__) . '/src/File.php';
}
if (!class_exists('SodiumException', false)) {
require_once dirname(__FILE__) . '/src/SodiumException.php';
}
if (!defined('SODIUM_CRYPTO_AEAD_AEGIS128L_KEYBYTES')) {
require_once dirname(__FILE__) . '/lib/php84compat_const.php';
}
if (!extension_loaded('sodium')) {
if (!defined('SODIUM_CRYPTO_SCALARMULT_BYTES')) {
require_once dirname(__FILE__) . '/lib/php72compat_const.php';
}
assert(class_exists('ParagonIE_Sodium_Compat'), 'Possible filesystem/autoloader bug?');
require_once(dirname(__FILE__) . '/lib/php72compat.php');
} elseif (!function_exists('sodium_crypto_stream_xchacha20_xor')) {
// Older versions of {PHP, ext/sodium} will not define these
require_once(dirname(__FILE__) . '/lib/php72compat.php');
}
if (PHP_VERSION_ID < 80400 || !extension_loaded('sodium')) {
require_once dirname(__FILE__) . '/lib/php84compat.php';
}
require_once(dirname(__FILE__) . '/lib/stream-xchacha20.php');
require_once(dirname(__FILE__) . '/lib/ristretto255.php');
+93
View File
@@ -0,0 +1,93 @@
{
"name": "paragonie/sodium_compat",
"description": "Pure PHP implementation of libsodium; uses the PHP extension if it exists",
"keywords": [
"PHP",
"cryptography",
"elliptic curve",
"elliptic curve cryptography",
"Pure-PHP cryptography",
"side-channel resistant",
"Curve25519",
"X25519",
"ECDH",
"Elliptic Curve Diffie-Hellman",
"Ed25519",
"RFC 7748",
"RFC 8032",
"EdDSA",
"Edwards-curve Digital Signature Algorithm",
"ChaCha20",
"Salsa20",
"Xchacha20",
"Xsalsa20",
"Poly1305",
"BLAKE2b",
"public-key cryptography",
"secret-key cryptography",
"AEAD",
"Chapoly",
"Salpoly",
"ChaCha20-Poly1305",
"XSalsa20-Poly1305",
"XChaCha20-Poly1305",
"encryption",
"authentication",
"libsodium"
],
"license": "ISC",
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com"
},
{
"name": "Frank Denis",
"email": "jedisct1@pureftpd.org"
}
],
"autoload": {
"files": ["autoload.php"],
"psr-4": {
"ParagonIE\\Sodium\\": "namespaced/"
}
},
"autoload-dev": {
"classmap": [
"tests/compat/",
"tests/unit/",
"tests/unit/Core/",
"tests/unit/KAT/"
]
},
"require": {
"php": "^8.1",
"php-64bit": "*"
},
"require-dev": {
"phpunit/phpunit": "^7|^8|^9|^10|^11",
"infection/infection": "^0",
"nikic/php-fuzzer": "^0",
"vimeo/psalm": "^4|^5|^6"
},
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"scripts": {
"test": "phpunit",
"static-analysis": "psalm",
"fuzz-test": "vendor/bin/php-fuzzer fuzz fuzzing/FuzzSodiumCompat.php",
"mutation-test": "infection"
},
"suggest": {
"ext-sodium": "Better performance, password hashing (Argon2i), secure memory management (memzero), and better security."
},
"config": {
"process-timeout": 0,
"allow-plugins": {
"infection/extension-installer": true
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
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;
const SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES = 32;
const SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES = 24;
+131
View File
@@ -0,0 +1,131 @@
<?php
declare(strict_types=1);
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.
*
* Thus, the functions or constants just proxy to the appropriate
* ParagonIE_Sodium_Compat method or class constant, respectively.
*/
foreach (array(
'CRYPTO_AEAD_AESGIS128L_KEYBYTES',
'CRYPTO_AEAD_AESGIS128L_NSECBYTES',
'CRYPTO_AEAD_AESGIS128L_NPUBBYTES',
'CRYPTO_AEAD_AESGIS128L_ABYTES',
'CRYPTO_AEAD_AESGIS256_KEYBYTES',
'CRYPTO_AEAD_AESGIS256_NSECBYTES',
'CRYPTO_AEAD_AESGIS256_NPUBBYTES',
'CRYPTO_AEAD_AESGIS256_ABYTES',
) as $constant
) {
if (!defined("SODIUM_$constant") && defined("ParagonIE_Sodium_Compat::$constant")) {
define("SODIUM_$constant", constant("ParagonIE_Sodium_Compat::$constant"));
}
}
if (!is_callable('sodium_crypto_aead_aegis128l_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis128l_decrypt()
* @param string $ciphertext
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string|bool
* @throws SodiumException
*/
function sodium_crypto_aead_aegis128l_decrypt(
string $ciphertext,
string $additional_data,
string $nonce,
#[\SensitiveParameter]
string $key
): string|bool {
return ParagonIE_Sodium_Compat::crypto_aead_aegis128l_decrypt(
$ciphertext,
$additional_data,
$nonce,
$key
);
}
}
if (!is_callable('sodium_crypto_aead_aegis128l_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis128l_encrypt()
* @param string $message
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_aead_aegis128l_encrypt(
#[\SensitiveParameter]
string $message,
string $additional_data,
string $nonce,
#[\SensitiveParameter]
string $key
): string {
return ParagonIE_Sodium_Compat::crypto_aead_aegis128l_encrypt(
$message,
$additional_data,
$nonce,
$key
);
}
}
if (!is_callable('sodium_crypto_aead_aegis256_decrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis256_encrypt()
* @param string $ciphertext
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string|bool
* @throws SodiumException
*/
function sodium_crypto_aead_aegis256_decrypt(
string $ciphertext,
string $additional_data,
string $nonce,
#[\SensitiveParameter]
string $key
): string|bool {
return ParagonIE_Sodium_Compat::crypto_aead_aegis256_decrypt(
$ciphertext,
$additional_data,
$nonce,
$key
);
}
}
if (!is_callable('sodium_crypto_aead_aegis256_encrypt')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_aead_aegis256_encrypt()
* @param string $message
* @param string $additional_data
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_aead_aegis256_encrypt(
#[\SensitiveParameter]
string $message,
string $additional_data,
string $nonce,
#[\SensitiveParameter]
string $key
): string {
return ParagonIE_Sodium_Compat::crypto_aead_aegis256_encrypt(
$message,
$additional_data,
$nonce,
$key
);
}
}
@@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
const SODIUM_CRYPTO_AEAD_AEGIS128L_KEYBYTES = 16;
const SODIUM_CRYPTO_AEAD_AEGIS128L_NSECBYTES = 0;
const SODIUM_CRYPTO_AEAD_AEGIS128L_NPUBBYTES = 32;
const SODIUM_CRYPTO_AEAD_AEGIS128L_ABYTES = 32;
const SODIUM_CRYPTO_AEAD_AEGIS256_KEYBYTES = 32;
const SODIUM_CRYPTO_AEAD_AEGIS256_NSECBYTES = 0;
const SODIUM_CRYPTO_AEAD_AEGIS256_NPUBBYTES = 32;
const SODIUM_CRYPTO_AEAD_AEGIS256_ABYTES = 32;
+278
View File
@@ -0,0 +1,278 @@
<?php
declare(strict_types=1);
if (!defined('SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES')) {
define(
'SODIUM_CRYPTO_CORE_RISTRETTO255_BYTES',
ParagonIE_Sodium_Compat::CRYPTO_CORE_RISTRETTO255_BYTES
);
define('SODIUM_COMPAT_POLYFILLED_RISTRETTO255', true);
}
if (!defined('SODIUM_CRYPTO_CORE_RISTRETTO255_HASHBYTES')) {
define(
'SODIUM_CRYPTO_CORE_RISTRETTO255_HASHBYTES',
ParagonIE_Sodium_Compat::CRYPTO_CORE_RISTRETTO255_HASHBYTES
);
}
if (!defined('SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES')) {
define(
'SODIUM_CRYPTO_CORE_RISTRETTO255_SCALARBYTES',
ParagonIE_Sodium_Compat::CRYPTO_CORE_RISTRETTO255_SCALARBYTES
);
}
if (!defined('SODIUM_CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES')) {
define(
'SODIUM_CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES',
ParagonIE_Sodium_Compat::CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES
);
}
if (!defined('SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES')) {
define(
'SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES',
ParagonIE_Sodium_Compat::CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES
);
}
if (!defined('SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_BYTES')) {
define(
'SODIUM_CRYPTO_SCALARMULT_RISTRETTO255_BYTES',
ParagonIE_Sodium_Compat::CRYPTO_SCALARMULT_RISTRETTO255_BYTES
);
}
if (!is_callable('sodium_crypto_core_ristretto255_add')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_add()
*
* @param string $p
* @param string $q
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_add(
#[\SensitiveParameter]
string $p,
#[\SensitiveParameter]
string $q
): string {
return ParagonIE_Sodium_Compat::ristretto255_add($p, $q, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_from_hash')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_from_hash()
*
* @param string $s
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_from_hash(
#[\SensitiveParameter]
string $s
): string {
return ParagonIE_Sodium_Compat::ristretto255_from_hash($s, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_is_valid_point')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_is_valid_point()
*
* @param string $s
* @return bool
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_is_valid_point(
#[\SensitiveParameter]
string $s
): bool {
return ParagonIE_Sodium_Compat::ristretto255_is_valid_point($s, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_random')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_random()
*
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_random(): string
{
return ParagonIE_Sodium_Compat::ristretto255_random(true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_add')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_add()
*
* @param string $x
* @param string $y
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_add(
#[\SensitiveParameter]
string $x,
#[\SensitiveParameter]
string $y
): string {
return ParagonIE_Sodium_Compat::ristretto255_scalar_add($x, $y, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_complement')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_complement()
*
* @param string $s
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_complement(
#[\SensitiveParameter]
string $s
): string {
return ParagonIE_Sodium_Compat::ristretto255_scalar_complement($s, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_invert')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_invert()
*
* @param string $p
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_invert(
#[\SensitiveParameter]
string $p
): string {
return ParagonIE_Sodium_Compat::ristretto255_scalar_invert($p, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_mul')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_mul()
*
* @param string $x
* @param string $y
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_mul(
#[\SensitiveParameter]
string $x,
#[\SensitiveParameter]
string $y
): string {
return ParagonIE_Sodium_Compat::ristretto255_scalar_mul($x, $y, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_negate')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_negate()
*
* @param string $s
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_negate(
#[\SensitiveParameter]
string $s
): string {
return ParagonIE_Sodium_Compat::ristretto255_scalar_negate($s, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_random')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_random()
*
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_random(): string
{
return ParagonIE_Sodium_Compat::ristretto255_scalar_random(true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_reduce')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_reduce()
*
* @param string $s
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_reduce(
#[\SensitiveParameter]
string $s
): string {
return ParagonIE_Sodium_Compat::ristretto255_scalar_reduce($s, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_scalar_sub')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_scalar_sub()
*
* @param string $x
* @param string $y
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_scalar_sub(
#[\SensitiveParameter]
string $x,
#[\SensitiveParameter]
string $y
): string {
return ParagonIE_Sodium_Compat::ristretto255_scalar_sub($x, $y, true);
}
}
if (!is_callable('sodium_crypto_core_ristretto255_sub')) {
/**
* @see ParagonIE_Sodium_Compat::ristretto255_sub()
*
* @param string $p
* @param string $q
* @return string
* @throws SodiumException
*/
function sodium_crypto_core_ristretto255_sub(
#[\SensitiveParameter]
string $p,
#[\SensitiveParameter]
string $q
): string {
return ParagonIE_Sodium_Compat::ristretto255_sub($p, $q, true);
}
}
if (!is_callable('sodium_crypto_scalarmult_ristretto255')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_scalarmult_ristretto255()
* @param string $n
* @param string $p
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_scalarmult_ristretto255(
#[\SensitiveParameter]
string $n,
#[\SensitiveParameter]
string $p
): string {
return ParagonIE_Sodium_Compat::scalarmult_ristretto255($n, $p, true);
}
}
if (!is_callable('sodium_crypto_scalarmult_ristretto255_base')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_scalarmult_ristretto255_base()
* @param string $n
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_scalarmult_ristretto255_base(
#[\SensitiveParameter]
string $n
): string {
return ParagonIE_Sodium_Compat::scalarmult_ristretto255_base($n, true);
}
}
+75
View File
@@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
if (!is_callable('sodium_crypto_stream_xchacha20')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream_xchacha20()
* @param int $len
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_stream_xchacha20(
int $len,
string $nonce,
#[\SensitiveParameter]
string $key
): string {
return ParagonIE_Sodium_Compat::crypto_stream_xchacha20($len, $nonce, $key, true);
}
}
if (!is_callable('sodium_crypto_stream_xchacha20_keygen')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream_xchacha20_keygen()
* @return string
* @throws Exception
*/
function sodium_crypto_stream_xchacha20_keygen(): string
{
return ParagonIE_Sodium_Compat::crypto_stream_xchacha20_keygen();
}
}
if (!is_callable('sodium_crypto_stream_xchacha20_xor')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream_xchacha20_xor()
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_stream_xchacha20_xor(
#[\SensitiveParameter]
string $message,
string $nonce,
#[\SensitiveParameter]
string $key
): string {
return ParagonIE_Sodium_Compat::crypto_stream_xchacha20_xor($message, $nonce, $key, true);
}
}
if (!is_callable('sodium_crypto_stream_xchacha20_xor_ic')) {
/**
* @see ParagonIE_Sodium_Compat::crypto_stream_xchacha20_xor_ic()
* @param string $message
* @param string $nonce
* @param int $counter
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
function sodium_crypto_stream_xchacha20_xor_ic(
#[\SensitiveParameter]
string $message,
string $nonce,
int $counter,
#[\SensitiveParameter]
string $key
): string {
return ParagonIE_Sodium_Compat::crypto_stream_xchacha20_xor_ic($message, $nonce, $counter, $key, true);
}
}
+7
View File
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium;
class Compat extends \ParagonIE_Sodium_Compat
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core;
class BLAKE2b extends \ParagonIE_Sodium_Core_BLAKE2b
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core;
class ChaCha20 extends \ParagonIE_Sodium_Core_ChaCha20
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core\ChaCha20;
class Ctx extends \ParagonIE_Sodium_Core_ChaCha20_Ctx
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core\ChaCha20;
class IetfCtx extends \ParagonIE_Sodium_Core_ChaCha20_IetfCtx
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core;
class Curve25519 extends \ParagonIE_Sodium_Core_Curve25519
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core\Curve25519;
class Fe extends \ParagonIE_Sodium_Core_Curve25519_Fe
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class Cached extends \ParagonIE_Sodium_Core_Curve25519_Ge_Cached
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class P1p1 extends \ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class P2 extends \ParagonIE_Sodium_Core_Curve25519_Ge_P2
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class P3 extends \ParagonIE_Sodium_Core_Curve25519_Ge_P3
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core\Curve25519\Ge;
class Precomp extends \ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core\Curve25519;
class H extends \ParagonIE_Sodium_Core_Curve25519_H
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core;
class Ed25519 extends \ParagonIE_Sodium_Core_Ed25519
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core;
class HChaCha20 extends \ParagonIE_Sodium_Core_HChaCha20
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core;
class HSalsa20 extends \ParagonIE_Sodium_Core_HSalsa20
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core;
class Poly1305 extends \ParagonIE_Sodium_Core_Poly1305
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core\Poly1305;
class State extends \ParagonIE_Sodium_Core_Poly1305_State
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core;
class Salsa20 extends \ParagonIE_Sodium_Core_Salsa20
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core;
class SipHash extends \ParagonIE_Sodium_Core_SipHash
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core;
class Util extends \ParagonIE_Sodium_Core_Util
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core;
class X25519 extends \ParagonIE_Sodium_Core_X25519
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core;
class XChaCha20 extends \ParagonIE_Sodium_Core_XChaCha20
{
}
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium\Core;
class Xsalsa20 extends \ParagonIE_Sodium_Core_XSalsa20
{
}
+7
View File
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium;
class Crypto extends \ParagonIE_Sodium_Crypto
{
}
+7
View File
@@ -0,0 +1,7 @@
<?php
namespace ParagonIE\Sodium;
class File extends \ParagonIE_Sodium_File
{
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,295 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_AEGIS_State128L', false)) {
return;
}
if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
}
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
}
class ParagonIE_Sodium_Core_AEGIS_State128L
{
/** @var array<int, string> $state */
protected array $state;
public function __construct()
{
$this->state = array_fill(0, 8, '');
}
/**
* @internal Only use this for unit tests!
* @return string[]
*/
public function getState(): array
{
return array_values($this->state);
}
/**
* @param array $input
* @return self
* @throws SodiumException
*
* @internal Only for unit tests
*/
public static function initForUnitTests(array $input): self
{
if (count($input) < 8) {
throw new SodiumException('invalid input');
}
$state = new self();
for ($i = 0; $i < 8; ++$i) {
$state->state[$i] = $input[$i];
}
return $state;
}
/**
* @param string $key
* @param string $nonce
* @return self
*/
public static function init(
#[SensitiveParameter]
string $key,
string $nonce
): self {
$state = new self();
// S0 = key ^ nonce
$state->state[0] = $key ^ $nonce;
// S1 = C1
$state->state[1] = SODIUM_COMPAT_AEGIS_C1;
// S2 = C0
$state->state[2] = SODIUM_COMPAT_AEGIS_C0;
// S3 = C1
$state->state[3] = SODIUM_COMPAT_AEGIS_C1;
// S4 = key ^ nonce
$state->state[4] = $key ^ $nonce;
// S5 = key ^ C0
$state->state[5] = $key ^ SODIUM_COMPAT_AEGIS_C0;
// S6 = key ^ C1
$state->state[6] = $key ^ SODIUM_COMPAT_AEGIS_C1;
// S7 = key ^ C0
$state->state[7] = $key ^ SODIUM_COMPAT_AEGIS_C0;
// Repeat(10, Update(nonce, key))
for ($i = 0; $i < 10; ++$i) {
$state->update($nonce, $key);
}
return $state;
}
/**
* @param string $ai
* @return static
*
* @throws SodiumException
*/
public function absorb(string $ai): static
{
if (ParagonIE_Sodium_Core_Util::strlen($ai) !== 32) {
throw new SodiumException('Input must be two AES blocks in size');
}
$t0 = ParagonIE_Sodium_Core_Util::substr($ai, 0, 16);
$t1 = ParagonIE_Sodium_Core_Util::substr($ai, 16, 16);
return $this->update($t0, $t1);
}
/**
* @param string $ci
* @return string
* @throws SodiumException
*/
public function dec(string $ci): string
{
if (ParagonIE_Sodium_Core_Util::strlen($ci) !== 32) {
throw new SodiumException('Input must be two AES blocks in size');
}
// z0 = S6 ^ S1 ^ (S2 & S3)
$z0 = $this->state[6]
^ $this->state[1]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
// z1 = S2 ^ S5 ^ (S6 & S7)
$z1 = $this->state[2]
^ $this->state[5]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);
// t0, t1 = Split(xi, 128)
$t0 = ParagonIE_Sodium_Core_Util::substr($ci, 0, 16);
$t1 = ParagonIE_Sodium_Core_Util::substr($ci, 16, 16);
// out0 = t0 ^ z0
// out1 = t1 ^ z1
$out0 = $t0 ^ $z0;
$out1 = $t1 ^ $z1;
// Update(out0, out1)
// xi = out0 || out1
$this->update($out0, $out1);
return $out0 . $out1;
}
/**
* @param string $cn
* @return string
*
* @throws SodiumException
*/
public function decPartial(string $cn): string
{
$len = ParagonIE_Sodium_Core_Util::strlen($cn);
// z0 = S6 ^ S1 ^ (S2 & S3)
$z0 = $this->state[6]
^ $this->state[1]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
// z1 = S2 ^ S5 ^ (S6 & S7)
$z1 = $this->state[2]
^ $this->state[5]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);
// t0, t1 = Split(ZeroPad(cn, 256), 128)
$cn = str_pad($cn, 32, "\0");
$t0 = ParagonIE_Sodium_Core_Util::substr($cn, 0, 16);
$t1 = ParagonIE_Sodium_Core_Util::substr($cn, 16, 16);
// out0 = t0 ^ z0
// out1 = t1 ^ z1
$out0 = $t0 ^ $z0;
$out1 = $t1 ^ $z1;
// xn = Truncate(out0 || out1, |cn|)
$xn = ParagonIE_Sodium_Core_Util::substr($out0 . $out1, 0, $len);
// v0, v1 = Split(ZeroPad(xn, 256), 128)
$padded = str_pad($xn, 32, "\0");
$v0 = ParagonIE_Sodium_Core_Util::substr($padded, 0, 16);
$v1 = ParagonIE_Sodium_Core_Util::substr($padded, 16, 16);
// Update(v0, v1)
$this->update($v0, $v1);
// return xn
return $xn;
}
/**
* @param string $xi
* @return string
* @throws SodiumException
*/
public function enc(
#[SensitiveParameter]
string $xi
): string {
if (ParagonIE_Sodium_Core_Util::strlen($xi) !== 32) {
throw new SodiumException('Input must be two AES blocks in size');
}
// z0 = S6 ^ S1 ^ (S2 & S3)
$z0 = $this->state[6]
^ $this->state[1]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
// z1 = S2 ^ S5 ^ (S6 & S7)
$z1 = $this->state[2]
^ $this->state[5]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[6], $this->state[7]);
// t0, t1 = Split(xi, 128)
$t0 = ParagonIE_Sodium_Core_Util::substr($xi, 0, 16);
$t1 = ParagonIE_Sodium_Core_Util::substr($xi, 16, 16);
// out0 = t0 ^ z0
// out1 = t1 ^ z1
$out0 = $t0 ^ $z0;
$out1 = $t1 ^ $z1;
// Update(t0, t1)
// ci = out0 || out1
$this->update($t0, $t1);
// return ci
return $out0 . $out1;
}
/**
* @param int $ad_len_bits
* @param int $msg_len_bits
* @return string
*/
public function finalize(int $ad_len_bits, int $msg_len_bits): string
{
$encoded = ParagonIE_Sodium_Core_Util::store64_le($ad_len_bits) .
ParagonIE_Sodium_Core_Util::store64_le($msg_len_bits);
$t = $this->state[2] ^ $encoded;
for ($i = 0; $i < 7; ++$i) {
$this->update($t, $t);
}
return ($this->state[0] ^ $this->state[1] ^ $this->state[2] ^ $this->state[3]) .
($this->state[4] ^ $this->state[5] ^ $this->state[6] ^ $this->state[7]);
}
/**
* @param string $m0
* @param string $m1
* @return static
*/
public function update(string $m0, string $m1): static
{
/*
S'0 = AESRound(S7, S0 ^ M0)
S'1 = AESRound(S0, S1)
S'2 = AESRound(S1, S2)
S'3 = AESRound(S2, S3)
S'4 = AESRound(S3, S4 ^ M1)
S'5 = AESRound(S4, S5)
S'6 = AESRound(S5, S6)
S'7 = AESRound(S6, S7)
*/
list($s_0, $s_1) = ParagonIE_Sodium_Core_AES::doubleRound(
$this->state[7], $this->state[0] ^ $m0,
$this->state[0], $this->state[1]
);
list($s_2, $s_3) = ParagonIE_Sodium_Core_AES::doubleRound(
$this->state[1], $this->state[2],
$this->state[2], $this->state[3]
);
list($s_4, $s_5) = ParagonIE_Sodium_Core_AES::doubleRound(
$this->state[3], $this->state[4] ^ $m1,
$this->state[4], $this->state[5]
);
list($s_6, $s_7) = ParagonIE_Sodium_Core_AES::doubleRound(
$this->state[5], $this->state[6],
$this->state[6], $this->state[7]
);
/*
S0 = S'0
S1 = S'1
S2 = S'2
S3 = S'3
S4 = S'4
S5 = S'5
S6 = S'6
S7 = S'7
*/
$this->state[0] = $s_0;
$this->state[1] = $s_1;
$this->state[2] = $s_2;
$this->state[3] = $s_3;
$this->state[4] = $s_4;
$this->state[5] = $s_5;
$this->state[6] = $s_6;
$this->state[7] = $s_7;
return $this;
}
}
@@ -0,0 +1,251 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_AEGIS_State256', false)) {
return;
}
if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
}
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
}
class ParagonIE_Sodium_Core_AEGIS_State256
{
/** @var array<int, string> $state */
protected array $state;
public function __construct()
{
$this->state = array_fill(0, 6, '');
}
/**
* @internal Only use this for unit tests!
* @return string[]
*/
public function getState(): array
{
return array_values($this->state);
}
/**
* @param array $input
* @return self
* @throws SodiumException
*
* @internal Only for unit tests
*/
public static function initForUnitTests(array $input): self
{
if (count($input) < 6) {
throw new SodiumException('invalid input');
}
$state = new self();
for ($i = 0; $i < 6; ++$i) {
$state->state[$i] = $input[$i];
}
return $state;
}
/**
* @param string $key
* @param string $nonce
* @return self
*/
public static function init(
#[SensitiveParameter]
string $key,
string $nonce
): self {
$state = new self();
$k0 = ParagonIE_Sodium_Core_Util::substr($key, 0, 16);
$k1 = ParagonIE_Sodium_Core_Util::substr($key, 16, 16);
$n0 = ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16);
$n1 = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 16);
// S0 = k0 ^ n0
// S1 = k1 ^ n1
// S2 = C1
// S3 = C0
// S4 = k0 ^ C0
// S5 = k1 ^ C1
$k0_n0 = $k0 ^ $n0;
$k1_n1 = $k1 ^ $n1;
$state->state[0] = $k0_n0;
$state->state[1] = $k1_n1;
$state->state[2] = SODIUM_COMPAT_AEGIS_C1;
$state->state[3] = SODIUM_COMPAT_AEGIS_C0;
$state->state[4] = $k0 ^ SODIUM_COMPAT_AEGIS_C0;
$state->state[5] = $k1 ^ SODIUM_COMPAT_AEGIS_C1;
// Repeat(4,
// Update(k0)
// Update(k1)
// Update(k0 ^ n0)
// Update(k1 ^ n1)
// )
for ($i = 0; $i < 4; ++$i) {
$state->update($k0);
$state->update($k1);
$state->update($k0 ^ $n0);
$state->update($k1 ^ $n1);
}
return $state;
}
/**
* @param string $ai
* @return static
* @throws SodiumException
*/
public function absorb(string $ai): static
{
if (ParagonIE_Sodium_Core_Util::strlen($ai) !== 16) {
throw new SodiumException('Input must be an AES block in size');
}
return $this->update($ai);
}
/**
* @param string $ci
* @return string
* @throws SodiumException
*/
public function dec(string $ci): string
{
if (ParagonIE_Sodium_Core_Util::strlen($ci) !== 16) {
throw new SodiumException('Input must be an AES block in size');
}
// z = S1 ^ S4 ^ S5 ^ (S2 & S3)
$z = $this->state[1]
^ $this->state[4]
^ $this->state[5]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
$xi = $ci ^ $z;
$this->update($xi);
return $xi;
}
/**
* @param string $cn
* @return string
*
* @throws SodiumException
*/
public function decPartial(string $cn): string
{
$len = ParagonIE_Sodium_Core_Util::strlen($cn);
// z = S1 ^ S4 ^ S5 ^ (S2 & S3)
$z = $this->state[1]
^ $this->state[4]
^ $this->state[5]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
// t = ZeroPad(cn, 128)
$t = str_pad($cn, 16, "\0");
// out = t ^ z
$out = $t ^ $z;
// xn = Truncate(out, |cn|)
$xn = ParagonIE_Sodium_Core_Util::substr($out, 0, $len);
// v = ZeroPad(xn, 128)
$v = str_pad($xn, 16, "\0");
// Update(v)
$this->update($v);
// return xn
return $xn;
}
/**
* @param string $xi
* @return string
* @throws SodiumException
*/
public function enc(
#[SensitiveParameter]
string $xi
): string {
if (ParagonIE_Sodium_Core_Util::strlen($xi) !== 16) {
throw new SodiumException('Input must be an AES block in size');
}
// z = S1 ^ S4 ^ S5 ^ (S2 & S3)
$z = $this->state[1]
^ $this->state[4]
^ $this->state[5]
^ ParagonIE_Sodium_Core_Util::andStrings($this->state[2], $this->state[3]);
$this->update($xi);
return $xi ^ $z;
}
/**
* @param int $ad_len_bits
* @param int $msg_len_bits
* @return string
*/
public function finalize(
int $ad_len_bits,
int $msg_len_bits
): string {
$encoded = ParagonIE_Sodium_Core_Util::store64_le($ad_len_bits) .
ParagonIE_Sodium_Core_Util::store64_le($msg_len_bits);
$t = $this->state[3] ^ $encoded;
for ($i = 0; $i < 7; ++$i) {
$this->update($t);
}
return ($this->state[0] ^ $this->state[1] ^ $this->state[2]) .
($this->state[3] ^ $this->state[4] ^ $this->state[5]);
}
/**
* @param string $m
* @return static
*/
public function update(string $m): static
{
/*
S'0 = AESRound(S5, S0 ^ M)
S'1 = AESRound(S0, S1)
S'2 = AESRound(S1, S2)
S'3 = AESRound(S2, S3)
S'4 = AESRound(S3, S4)
S'5 = AESRound(S4, S5)
*/
list($s_0, $s_1) = ParagonIE_Sodium_Core_AES::doubleRound(
$this->state[5],$this->state[0] ^ $m,
$this->state[0], $this->state[1]
);
list($s_2, $s_3) = ParagonIE_Sodium_Core_AES::doubleRound(
$this->state[1], $this->state[2],
$this->state[2], $this->state[3]
);
list($s_4, $s_5) = ParagonIE_Sodium_Core_AES::doubleRound(
$this->state[3], $this->state[4],
$this->state[4], $this->state[5]
);
/*
S0 = S'0
S1 = S'1
S2 = S'2
S3 = S'3
S4 = S'4
S5 = S'5
*/
$this->state[0] = $s_0;
$this->state[1] = $s_1;
$this->state[2] = $s_2;
$this->state[3] = $s_3;
$this->state[4] = $s_4;
$this->state[5] = $s_5;
return $this;
}
}
+132
View File
@@ -0,0 +1,132 @@
<?php
declare(strict_types=1);
if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
}
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
}
class ParagonIE_Sodium_Core_AEGIS128L extends ParagonIE_Sodium_Core_AES
{
/**
* @param string $ct
* @param string $tag
* @param string $ad
* @param string $key
* @param string $nonce
* @return string
* @throws SodiumException
*/
public static function decrypt(
string $ct,
string $tag,
string $ad,
#[SensitiveParameter]
string $key,
string $nonce
): string {
$state = self::init($key, $nonce);
$ad_blocks = (self::strlen($ad) + 31) >> 5;
for ($i = 0; $i < $ad_blocks; ++$i) {
$ai = self::substr($ad, $i << 5, 32);
if (self::strlen($ai) < 32) {
$ai = str_pad($ai, 32, "\0");
}
$state->absorb($ai);
}
$msg = '';
$cn = self::strlen($ct) & 31;
$ct_blocks = self::strlen($ct) >> 5;
for ($i = 0; $i < $ct_blocks; ++$i) {
$msg .= $state->dec(self::substr($ct, $i << 5, 32));
}
if ($cn) {
$start = $ct_blocks << 5;
$msg .= $state->decPartial(self::substr($ct, $start, $cn));
}
$expected_tag = $state->finalize(
self::strlen($ad) << 3,
self::strlen($msg) << 3
);
if (!self::hashEquals($expected_tag, $tag)) {
try {
// The RFC says to erase msg, so we shall try:
ParagonIE_Sodium_Compat::memzero($msg);
} catch (SodiumException) {
// Do nothing if we cannot memzero
}
throw new SodiumException('verification failed');
}
return $msg;
}
/**
* @param string $msg
* @param string $ad
* @param string $key
* @param string $nonce
* @return array
*
* @throws SodiumException
*/
public static function encrypt(
#[SensitiveParameter]
string $msg,
string $ad,
#[SensitiveParameter]
string $key,
string $nonce
): array {
$state = self::init($key, $nonce);
// ad_blocks = Split(ZeroPad(ad, 256), 256)
// for ai in ad_blocks:
// Absorb(ai)
$ad_len = self::strlen($ad);
$msg_len = self::strlen($msg);
$ad_blocks = ($ad_len + 31) >> 5;
for ($i = 0; $i < $ad_blocks; ++$i) {
$ai = self::substr($ad, $i << 5, 32);
if (self::strlen($ai) < 32) {
$ai = str_pad($ai, 32, "\0");
}
$state->absorb($ai);
}
// msg_blocks = Split(ZeroPad(msg, 256), 256)
// for xi in msg_blocks:
// ct = ct || Enc(xi)
$ct = '';
$msg_blocks = ($msg_len + 31) >> 5;
for ($i = 0; $i < $msg_blocks; ++$i) {
$xi = self::substr($msg, $i << 5, 32);
if (self::strlen($xi) < 32) {
$xi = str_pad($xi, 32, "\0");
}
$ct .= $state->enc($xi);
}
// tag = Finalize(|ad|, |msg|)
// ct = Truncate(ct, |msg|)
$tag = $state->finalize(
$ad_len << 3,
$msg_len << 3
);
// return ct and tag
return array(
self::substr($ct, 0, $msg_len),
$tag
);
}
/**
* @param string $key
* @param string $nonce
* @return ParagonIE_Sodium_Core_AEGIS_State128L
*/
public static function init(string $key, string $nonce): ParagonIE_Sodium_Core_AEGIS_State128L
{
return ParagonIE_Sodium_Core_AEGIS_State128L::init($key, $nonce);
}
}
+134
View File
@@ -0,0 +1,134 @@
<?php
declare(strict_types=1);
if (!defined('SODIUM_COMPAT_AEGIS_C0')) {
define('SODIUM_COMPAT_AEGIS_C0', "\x00\x01\x01\x02\x03\x05\x08\x0d\x15\x22\x37\x59\x90\xe9\x79\x62");
}
if (!defined('SODIUM_COMPAT_AEGIS_C1')) {
define('SODIUM_COMPAT_AEGIS_C1', "\xdb\x3d\x18\x55\x6d\xc2\x2f\xf1\x20\x11\x31\x42\x73\xb5\x28\xdd");
}
class ParagonIE_Sodium_Core_AEGIS256 extends ParagonIE_Sodium_Core_AES
{
/**
* @param string $ct
* @param string $tag
* @param string $ad
* @param string $key
* @param string $nonce
* @return string
* @throws SodiumException
*/
public static function decrypt(
string $ct,
string $tag,
string $ad,
#[SensitiveParameter]
string $key,
string $nonce
): string {
$state = self::init($key, $nonce);
// ad_blocks = Split(ZeroPad(ad, 128), 128)
$ad_blocks = (self::strlen($ad) + 15) >> 4;
// for ai in ad_blocks:
// Absorb(ai)
for ($i = 0; $i < $ad_blocks; ++$i) {
$ai = self::substr($ad, $i << 4, 16);
if (self::strlen($ai) < 16) {
$ai = str_pad($ai, 16, "\0");
}
$state->absorb($ai);
}
$msg = '';
$cn = self::strlen($ct) & 15;
$ct_blocks = self::strlen($ct) >> 4;
// ct_blocks = Split(ZeroPad(ct, 128), 128)
// cn = Tail(ct, |ct| mod 128)
for ($i = 0; $i < $ct_blocks; ++$i) {
$msg .= $state->dec(self::substr($ct, $i << 4, 16));
}
// if cn is not empty:
// msg = msg || DecPartial(cn)
if ($cn) {
$start = $ct_blocks << 4;
$msg .= $state->decPartial(self::substr($ct, $start, $cn));
}
$expected_tag = $state->finalize(
self::strlen($ad) << 3,
self::strlen($msg) << 3
);
if (!self::hashEquals($expected_tag, $tag)) {
try {
// The RFC says to erase msg, so we shall try:
ParagonIE_Sodium_Compat::memzero($msg);
} catch (SodiumException) {
// Do nothing if we cannot memzero
}
throw new SodiumException('verification failed');
}
return $msg;
}
/**
* @param string $msg
* @param string $ad
* @param string $key
* @param string $nonce
* @return array
* @throws SodiumException
*/
public static function encrypt(
#[SensitiveParameter]
string $msg,
string $ad,
#[SensitiveParameter]
string $key,
string $nonce
): array {
$state = self::init($key, $nonce);
$ad_len = self::strlen($ad);
$msg_len = self::strlen($msg);
$ad_blocks = ($ad_len + 15) >> 4;
for ($i = 0; $i < $ad_blocks; ++$i) {
$ai = self::substr($ad, $i << 4, 16);
if (self::strlen($ai) < 16) {
$ai = str_pad($ai, 16, "\0");
}
$state->absorb($ai);
}
$ct = '';
$msg_blocks = ($msg_len + 15) >> 4;
for ($i = 0; $i < $msg_blocks; ++$i) {
$xi = self::substr($msg, $i << 4, 16);
if (self::strlen($xi) < 16) {
$xi = str_pad($xi, 16, "\0");
}
$ct .= $state->enc($xi);
}
$tag = $state->finalize(
$ad_len << 3,
$msg_len << 3
);
return array(
self::substr($ct, 0, $msg_len),
$tag
);
}
/**
* @param string $key
* @param string $nonce
* @return ParagonIE_Sodium_Core_AEGIS_State256
*/
public static function init(
#[SensitiveParameter]
string $key,
string $nonce
): ParagonIE_Sodium_Core_AEGIS_State256 {
return ParagonIE_Sodium_Core_AEGIS_State256::init($key, $nonce);
}
}
+532
View File
@@ -0,0 +1,532 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_AES', false)) {
return;
}
/**
* Bitsliced implementation of the AES block cipher.
*
* Based on the implementation provided by BearSSL.
*
* @internal This should only be used by sodium_compat
*/
class ParagonIE_Sodium_Core_AES extends ParagonIE_Sodium_Core_Util
{
/**
* @var int[] AES round constants
*/
private const Rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36];
/**
* Mutates the values of $q!
*
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
public static function sbox(ParagonIE_Sodium_Core_AES_Block $q): void
{
/**
* @var int $x0
* @var int $x1
* @var int $x2
* @var int $x3
* @var int $x4
* @var int $x5
* @var int $x6
* @var int $x7
*/
$x0 = $q[7] & self::U32_MAX;
$x1 = $q[6] & self::U32_MAX;
$x2 = $q[5] & self::U32_MAX;
$x3 = $q[4] & self::U32_MAX;
$x4 = $q[3] & self::U32_MAX;
$x5 = $q[2] & self::U32_MAX;
$x6 = $q[1] & self::U32_MAX;
$x7 = $q[0] & self::U32_MAX;
$y14 = $x3 ^ $x5;
$y13 = $x0 ^ $x6;
$y9 = $x0 ^ $x3;
$y8 = $x0 ^ $x5;
$t0 = $x1 ^ $x2;
$y1 = $t0 ^ $x7;
$y4 = $y1 ^ $x3;
$y12 = $y13 ^ $y14;
$y2 = $y1 ^ $x0;
$y5 = $y1 ^ $x6;
$y3 = $y5 ^ $y8;
$t1 = $x4 ^ $y12;
$y15 = $t1 ^ $x5;
$y20 = $t1 ^ $x1;
$y6 = $y15 ^ $x7;
$y10 = $y15 ^ $t0;
$y11 = $y20 ^ $y9;
$y7 = $x7 ^ $y11;
$y17 = $y10 ^ $y11;
$y19 = $y10 ^ $y8;
$y16 = $t0 ^ $y11;
$y21 = $y13 ^ $y16;
$y18 = $x0 ^ $y16;
/*
* Non-linear section.
*/
$t2 = $y12 & $y15;
$t3 = $y3 & $y6;
$t4 = $t3 ^ $t2;
$t5 = $y4 & $x7;
$t6 = $t5 ^ $t2;
$t7 = $y13 & $y16;
$t8 = $y5 & $y1;
$t9 = $t8 ^ $t7;
$t10 = $y2 & $y7;
$t11 = $t10 ^ $t7;
$t12 = $y9 & $y11;
$t13 = $y14 & $y17;
$t14 = $t13 ^ $t12;
$t15 = $y8 & $y10;
$t16 = $t15 ^ $t12;
$t17 = $t4 ^ $t14;
$t18 = $t6 ^ $t16;
$t19 = $t9 ^ $t14;
$t20 = $t11 ^ $t16;
$t21 = $t17 ^ $y20;
$t22 = $t18 ^ $y19;
$t23 = $t19 ^ $y21;
$t24 = $t20 ^ $y18;
$t25 = $t21 ^ $t22;
$t26 = $t21 & $t23;
$t27 = $t24 ^ $t26;
$t28 = $t25 & $t27;
$t29 = $t28 ^ $t22;
$t30 = $t23 ^ $t24;
$t31 = $t22 ^ $t26;
$t32 = $t31 & $t30;
$t33 = $t32 ^ $t24;
$t34 = $t23 ^ $t33;
$t35 = $t27 ^ $t33;
$t36 = $t24 & $t35;
$t37 = $t36 ^ $t34;
$t38 = $t27 ^ $t36;
$t39 = $t29 & $t38;
$t40 = $t25 ^ $t39;
$t41 = $t40 ^ $t37;
$t42 = $t29 ^ $t33;
$t43 = $t29 ^ $t40;
$t44 = $t33 ^ $t37;
$t45 = $t42 ^ $t41;
$z0 = $t44 & $y15;
$z1 = $t37 & $y6;
$z2 = $t33 & $x7;
$z3 = $t43 & $y16;
$z4 = $t40 & $y1;
$z5 = $t29 & $y7;
$z6 = $t42 & $y11;
$z7 = $t45 & $y17;
$z8 = $t41 & $y10;
$z9 = $t44 & $y12;
$z10 = $t37 & $y3;
$z11 = $t33 & $y4;
$z12 = $t43 & $y13;
$z13 = $t40 & $y5;
$z14 = $t29 & $y2;
$z15 = $t42 & $y9;
$z16 = $t45 & $y14;
$z17 = $t41 & $y8;
/*
* Bottom linear transformation.
*/
$t46 = $z15 ^ $z16;
$t47 = $z10 ^ $z11;
$t48 = $z5 ^ $z13;
$t49 = $z9 ^ $z10;
$t50 = $z2 ^ $z12;
$t51 = $z2 ^ $z5;
$t52 = $z7 ^ $z8;
$t53 = $z0 ^ $z3;
$t54 = $z6 ^ $z7;
$t55 = $z16 ^ $z17;
$t56 = $z12 ^ $t48;
$t57 = $t50 ^ $t53;
$t58 = $z4 ^ $t46;
$t59 = $z3 ^ $t54;
$t60 = $t46 ^ $t57;
$t61 = $z14 ^ $t57;
$t62 = $t52 ^ $t58;
$t63 = $t49 ^ $t58;
$t64 = $z4 ^ $t59;
$t65 = $t61 ^ $t62;
$t66 = $z1 ^ $t63;
$s0 = $t59 ^ $t63;
$s6 = $t56 ^ ~$t62;
$s7 = $t48 ^ ~$t60;
$t67 = $t64 ^ $t65;
$s3 = $t53 ^ $t66;
$s4 = $t51 ^ $t66;
$s5 = $t47 ^ $t65;
$s1 = $t64 ^ ~$s3;
$s2 = $t55 ^ ~$t67;
$q[7] = $s0 & self::U32_MAX;
$q[6] = $s1 & self::U32_MAX;
$q[5] = $s2 & self::U32_MAX;
$q[4] = $s3 & self::U32_MAX;
$q[3] = $s4 & self::U32_MAX;
$q[2] = $s5 & self::U32_MAX;
$q[1] = $s6 & self::U32_MAX;
$q[0] = $s7 & self::U32_MAX;
}
/**
* Mutates the values of $q!
*
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
public static function invSbox(ParagonIE_Sodium_Core_AES_Block $q): void
{
self::processInversion($q);
self::sbox($q);
self::processInversion($q);
}
/**
* This is some boilerplate code needed to invert an S-box. Rather than repeat the code
* twice, I moved it to a protected method.
*
* Mutates $q
*
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
protected static function processInversion(ParagonIE_Sodium_Core_AES_Block $q): void
{
$q0 = (~$q[0]) & self::U32_MAX;
$q1 = (~$q[1]) & self::U32_MAX;
$q2 = $q[2] & self::U32_MAX;
$q3 = $q[3] & self::U32_MAX;
$q4 = $q[4] & self::U32_MAX;
$q5 = (~$q[5]) & self::U32_MAX;
$q6 = (~$q[6]) & self::U32_MAX;
$q7 = $q[7] & self::U32_MAX;
$q[7] = ($q1 ^ $q4 ^ $q6) & self::U32_MAX;
$q[6] = ($q0 ^ $q3 ^ $q5) & self::U32_MAX;
$q[5] = ($q7 ^ $q2 ^ $q4) & self::U32_MAX;
$q[4] = ($q6 ^ $q1 ^ $q3) & self::U32_MAX;
$q[3] = ($q5 ^ $q0 ^ $q2) & self::U32_MAX;
$q[2] = ($q4 ^ $q7 ^ $q1) & self::U32_MAX;
$q[1] = ($q3 ^ $q6 ^ $q0) & self::U32_MAX;
$q[0] = ($q2 ^ $q5 ^ $q7) & self::U32_MAX;
}
/**
* @param int $x
* @return int
*/
public static function subWord(int $x): int
{
$q = ParagonIE_Sodium_Core_AES_Block::fromArray(
array($x, $x, $x, $x, $x, $x, $x, $x)
);
$q->orthogonalize();
self::sbox($q);
$q->orthogonalize();
return $q[0] & self::U32_MAX;
}
/**
* Calculate the key schedule from a given random key
*
* @param string $key
* @return ParagonIE_Sodium_Core_AES_KeySchedule
* @throws SodiumException
*/
public static function keySchedule(
#[SensitiveParameter]
string $key
): ParagonIE_Sodium_Core_AES_KeySchedule {
$key_len = self::strlen($key);
$num_rounds = match ($key_len) {
16 => 10,
24 => 12,
32 => 14,
default => throw new SodiumException('Invalid key length: ' . $key_len),
};
$skey = array();
$comp_skey = array();
$nk = $key_len >> 2;
$nkf = ($num_rounds + 1) << 2;
$tmp = 0;
for ($i = 0; $i < $nk; ++$i) {
$tmp = self::load_4(self::substr($key, $i << 2, 4));
$skey[($i << 1)] = $tmp;
$skey[($i << 1) + 1] = $tmp;
}
for ($i = $nk, $j = 0, $k = 0; $i < $nkf; ++$i) {
if ($j === 0) {
$tmp = (($tmp & 0xff) << 24) | ($tmp >> 8);
/** @psalm-suppress InvalidArrayOffset */
$tmp = (self::subWord($tmp) ^ self::Rcon[$k]) & self::U32_MAX;
} elseif ($nk > 6 && $j === 4) {
$tmp = self::subWord($tmp);
}
$tmp ^= $skey[($i - $nk) << 1];
$skey[($i << 1)] = $tmp & self::U32_MAX;
$skey[($i << 1) + 1] = $tmp & self::U32_MAX;
if (++$j === $nk) {
/** @psalm-suppress LoopInvalidation */
$j = 0;
++$k;
}
}
for ($i = 0; $i < $nkf; $i += 4) {
$q = ParagonIE_Sodium_Core_AES_Block::fromArray(
array_slice($skey, $i << 1, 8)
);
$q->orthogonalize();
// We have to overwrite $skey since we're not using C pointers like BearSSL did
for ($j = 0; $j < 8; ++$j) {
$skey[($i << 1) + $j] = $q[$j];
}
}
for ($i = 0, $j = 0; $i < $nkf; ++$i, $j += 2) {
$comp_skey[$i] = ($skey[$j] & 0x55555555)
| ($skey[$j + 1] & 0xAAAAAAAA);
}
return new ParagonIE_Sodium_Core_AES_KeySchedule($comp_skey, $num_rounds);
}
/**
* Mutates $q
*
* @param ParagonIE_Sodium_Core_AES_KeySchedule $skey
* @param ParagonIE_Sodium_Core_AES_Block $q
* @param int $offset
* @return void
*/
public static function addRoundKey(
ParagonIE_Sodium_Core_AES_Block $q,
ParagonIE_Sodium_Core_AES_KeySchedule $skey,
int $offset = 0
): void {
$block = $skey->getRoundKey($offset);
for ($j = 0; $j < 8; ++$j) {
$q[$j] = ($q[$j] ^ $block[$j]) & ParagonIE_Sodium_Core_Util::U32_MAX;
}
}
/**
* This mainly exists for testing, as we need the round key features for AEGIS.
*
* @param string $message
* @param string $key
* @return string
* @throws SodiumException
*/
public static function decryptBlockECB(
string $message,
#[SensitiveParameter]
string $key
): string {
if (self::strlen($message) !== 16) {
throw new SodiumException('decryptBlockECB() expects a 16 byte message');
}
$skey = self::keySchedule($key)->expand();
$q = ParagonIE_Sodium_Core_AES_Block::init();
$q[0] = self::load_4(self::substr($message, 0, 4));
$q[2] = self::load_4(self::substr($message, 4, 4));
$q[4] = self::load_4(self::substr($message, 8, 4));
$q[6] = self::load_4(self::substr($message, 12, 4));
$q->orthogonalize();
self::bitsliceDecryptBlock($skey, $q);
$q->orthogonalize();
return self::store32_le($q[0]) .
self::store32_le($q[2]) .
self::store32_le($q[4]) .
self::store32_le($q[6]);
}
/**
* This mainly exists for testing, as we need the round key features for AEGIS.
*
* @param string $message
* @param string $key
* @return string
* @throws SodiumException
*/
public static function encryptBlockECB(
#[SensitiveParameter]
string $message,
#[SensitiveParameter]
string $key
): string {
if (self::strlen($message) !== 16) {
throw new SodiumException('encryptBlockECB() expects a 16 byte message');
}
$comp_skey = self::keySchedule($key);
$skey = $comp_skey->expand();
$q = ParagonIE_Sodium_Core_AES_Block::init();
$q[0] = self::load_4(self::substr($message, 0, 4));
$q[2] = self::load_4(self::substr($message, 4, 4));
$q[4] = self::load_4(self::substr($message, 8, 4));
$q[6] = self::load_4(self::substr($message, 12, 4));
$q->orthogonalize();
self::bitsliceEncryptBlock($skey, $q);
$q->orthogonalize();
return self::store32_le($q[0]) .
self::store32_le($q[2]) .
self::store32_le($q[4]) .
self::store32_le($q[6]);
}
/**
* Mutates $q
*
* @param ParagonIE_Sodium_Core_AES_Expanded $skey
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
public static function bitsliceEncryptBlock(
ParagonIE_Sodium_Core_AES_Expanded $skey,
ParagonIE_Sodium_Core_AES_Block $q
): void {
self::addRoundKey($q, $skey);
for ($u = 1; $u < $skey->getNumRounds(); ++$u) {
self::sbox($q);
$q->shiftRows();
$q->mixColumns();
self::addRoundKey($q, $skey, ($u << 3));
}
self::sbox($q);
$q->shiftRows();
self::addRoundKey($q, $skey, ($skey->getNumRounds() << 3));
}
/**
* @param string $x
* @param string $y
* @return string
*/
public static function aesRound(
#[SensitiveParameter]
string $x,
#[SensitiveParameter]
string $y
): string {
$q = ParagonIE_Sodium_Core_AES_Block::init();
$q[0] = self::load_4(self::substr($x, 0, 4));
$q[2] = self::load_4(self::substr($x, 4, 4));
$q[4] = self::load_4(self::substr($x, 8, 4));
$q[6] = self::load_4(self::substr($x, 12, 4));
$rk = ParagonIE_Sodium_Core_AES_Block::init();
$rk[0] = $rk[1] = self::load_4(self::substr($y, 0, 4));
$rk[2] = $rk[3] = self::load_4(self::substr($y, 4, 4));
$rk[4] = $rk[5] = self::load_4(self::substr($y, 8, 4));
$rk[6] = $rk[7] = self::load_4(self::substr($y, 12, 4));
$q->orthogonalize();
self::sbox($q);
$q->shiftRows();
$q->mixColumns();
$q->orthogonalize();
// add round key without key schedule:
for ($i = 0; $i < 8; ++$i) {
$q[$i] ^= $rk[$i];
}
return self::store32_le($q[0]) .
self::store32_le($q[2]) .
self::store32_le($q[4]) .
self::store32_le($q[6]);
}
/**
* Process two AES blocks in one shot.
*
* @param string $b0 First AES block
* @param string $rk0 First round key
* @param string $b1 Second AES block
* @param string $rk1 Second round key
* @return string[]
*/
public static function doubleRound(
#[SensitiveParameter]
string $b0,
#[SensitiveParameter]
string $rk0,
#[SensitiveParameter]
string $b1,
#[SensitiveParameter]
string $rk1
): array {
$q = ParagonIE_Sodium_Core_AES_Block::init();
// First block
$q[0] = self::load_4(self::substr($b0, 0, 4));
$q[2] = self::load_4(self::substr($b0, 4, 4));
$q[4] = self::load_4(self::substr($b0, 8, 4));
$q[6] = self::load_4(self::substr($b0, 12, 4));
// Second block
$q[1] = self::load_4(self::substr($b1, 0, 4));
$q[3] = self::load_4(self::substr($b1, 4, 4));
$q[5] = self::load_4(self::substr($b1, 8, 4));
$q[7] = self::load_4(self::substr($b1, 12, 4));
$rk = ParagonIE_Sodium_Core_AES_Block::init();
// First round key
$rk[0] = self::load_4(self::substr($rk0, 0, 4));
$rk[2] = self::load_4(self::substr($rk0, 4, 4));
$rk[4] = self::load_4(self::substr($rk0, 8, 4));
$rk[6] = self::load_4(self::substr($rk0, 12, 4));
// Second round key
$rk[1] = self::load_4(self::substr($rk1, 0, 4));
$rk[3] = self::load_4(self::substr($rk1, 4, 4));
$rk[5] = self::load_4(self::substr($rk1, 8, 4));
$rk[7] = self::load_4(self::substr($rk1, 12, 4));
$q->orthogonalize();
self::sbox($q);
$q->shiftRows();
$q->mixColumns();
$q->orthogonalize();
// add round key without key schedule:
for ($i = 0; $i < 8; ++$i) {
$q[$i] ^= $rk[$i];
}
return array(
self::store32_le($q[0]) . self::store32_le($q[2]) . self::store32_le($q[4]) . self::store32_le($q[6]),
self::store32_le($q[1]) . self::store32_le($q[3]) . self::store32_le($q[5]) . self::store32_le($q[7]),
);
}
/**
* @param ParagonIE_Sodium_Core_AES_Expanded $skey
* @param ParagonIE_Sodium_Core_AES_Block $q
* @return void
*/
public static function bitsliceDecryptBlock(
ParagonIE_Sodium_Core_AES_Expanded $skey,
ParagonIE_Sodium_Core_AES_Block $q
): void {
self::addRoundKey($q, $skey, ($skey->getNumRounds() << 3));
for ($u = $skey->getNumRounds() - 1; $u > 0; --$u) {
$q->inverseShiftRows();
self::invSbox($q);
self::addRoundKey($q, $skey, ($u << 3));
$q->inverseMixColumns();
}
$q->inverseShiftRows();
self::invSbox($q);
self::addRoundKey($q, $skey, ($u << 3));
}
}
+362
View File
@@ -0,0 +1,362 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_AES_Block', false)) {
return;
}
/**
* @internal This should only be used by sodium_compat
*
* @psalm-suppress MissingTemplateParam
*/
class ParagonIE_Sodium_Core_AES_Block extends SplFixedArray
{
/**
* @var array<int, int>
*/
protected array $values = array();
/**
* @var int
*/
protected int $size;
/**
* @param int $size
*/
public function __construct(int $size = 8)
{
parent::__construct($size);
$this->size = $size;
$this->values = array_fill(0, $size, 0);
}
/**
* @return self
*/
public static function init(): self
{
return new self(8);
}
/**
* @internal You should not use this directly from another application
*
* @param array<int, int> $array
* @param bool $save_indexes
* @return self
*
* @psalm-suppress MethodSignatureMismatch
*/
#[ReturnTypeWillChange]
public static function fromArray($array, ?bool $save_indexes = null)
{
$count = count($array);
if ($save_indexes) {
$keys = array_keys($array);
} else {
$keys = range(0, $count - 1);
}
$array = array_values($array);
/** @var array<int, int> $keys */
$obj = new ParagonIE_Sodium_Core_AES_Block();
if ($save_indexes) {
for ($i = 0; $i < $count; ++$i) {
$obj->offsetSet($keys[$i], $array[$i]);
}
} else {
for ($i = 0; $i < $count; ++$i) {
$obj->offsetSet($i, $array[$i]);
}
}
return $obj;
}
/**
* @internal You should not use this directly from another application
*
* @param int|null $offset
* @param int $value
* @return void
*
* @psalm-suppress MethodSignatureMismatch
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetSet($offset, $value): void
{
if (is_null($offset)) {
$this->values[] = $value;
} else {
$this->values[$offset] = $value;
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return bool
*
* @psalm-suppress MethodSignatureMismatch
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->values[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return void
*
* @psalm-suppress MethodSignatureMismatch
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetUnset($offset): void
{
unset($this->values[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return int
*
* @psalm-suppress MethodSignatureMismatch
* @psalm-suppress MixedArrayOffset
*/
#[ReturnTypeWillChange]
public function offsetGet($offset)
{
if (!isset($this->values[$offset])) {
$this->values[$offset] = 0;
}
return $this->values[$offset];
}
/**
* @internal You should not use this directly from another application
*
* @return array
*/
public function __debugInfo()
{
$out = array();
foreach ($this->values as $v) {
$out[] = str_pad(dechex($v), 8, '0', STR_PAD_LEFT);
}
return array(implode(', ', $out));
/*
return array(implode(', ', $this->values));
*/
}
/**
* @return array<int, int>
*/
public function toArray(): array
{
return $this->values;
}
/**
* @param int $cl low bit mask
* @param int $ch high bit mask
* @param int $s shift
* @param int $x index 1
* @param int $y index 2
* @return static
*/
public function swapN(
int $cl,
int $ch,
int $s,
int $x,
int $y
): static {
static $u32mask = ParagonIE_Sodium_Core_Util::U32_MAX;
$a = $this->values[$x] & $u32mask;
$b = $this->values[$y] & $u32mask;
// (x) = (a & cl) | ((b & cl) << (s));
$this->values[$x] = ($a & $cl) | ((($b & $cl) << $s) & $u32mask);
// (y) = ((a & ch) >> (s)) | (b & ch);
$this->values[$y] = ((($a & $ch) & $u32mask) >> $s) | ($b & $ch);
return $this;
}
/**
* @param int $x index 1
* @param int $y index 2
* @return static
*/
public function swap2(
int $x,
int $y
): static {
return $this->swapN(0x55555555, 0xAAAAAAAA, 1, $x, $y);
}
/**
* @param int $x index 1
* @param int $y index 2
* @return static
*/
public function swap4(
int $x,
int $y
): static {
return $this->swapN(0x33333333, 0xCCCCCCCC, 2, $x, $y);
}
/**
* @param int $x index 1
* @param int $y index 2
* @return static
*/
public function swap8(
int $x,
int $y
): static {
return $this->swapN(0x0F0F0F0F, 0xF0F0F0F0, 4, $x, $y);
}
/**
* @return static
*/
public function orthogonalize(): static
{
return $this
->swap2(0, 1)
->swap2(2, 3)
->swap2(4, 5)
->swap2(6, 7)
->swap4(0, 2)
->swap4(1, 3)
->swap4(4, 6)
->swap4(5, 7)
->swap8(0, 4)
->swap8(1, 5)
->swap8(2, 6)
->swap8(3, 7);
}
/**
* @return static
*/
public function shiftRows(): static
{
for ($i = 0; $i < 8; ++$i) {
$x = $this->values[$i] & ParagonIE_Sodium_Core_Util::U32_MAX;
$this->values[$i] = (
($x & 0x000000FF)
| (($x & 0x0000FC00) >> 2) | (($x & 0x00000300) << 6)
| (($x & 0x00F00000) >> 4) | (($x & 0x000F0000) << 4)
| (($x & 0xC0000000) >> 6) | (($x & 0x3F000000) << 2)
) & ParagonIE_Sodium_Core_Util::U32_MAX;
}
return $this;
}
/**
* @param int $x
* @return int
*/
public static function rotr16(int $x): int
{
return (($x << 16) & ParagonIE_Sodium_Core_Util::U32_MAX) | ($x >> 16);
}
/**
* @return static
*/
public function mixColumns(): static
{
$q0 = $this->values[0];
$q1 = $this->values[1];
$q2 = $this->values[2];
$q3 = $this->values[3];
$q4 = $this->values[4];
$q5 = $this->values[5];
$q6 = $this->values[6];
$q7 = $this->values[7];
$r0 = (($q0 >> 8) | ($q0 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r1 = (($q1 >> 8) | ($q1 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r2 = (($q2 >> 8) | ($q2 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r3 = (($q3 >> 8) | ($q3 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r4 = (($q4 >> 8) | ($q4 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r5 = (($q5 >> 8) | ($q5 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r6 = (($q6 >> 8) | ($q6 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r7 = (($q7 >> 8) | ($q7 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$this->values[0] = $q7 ^ $r7 ^ $r0 ^ self::rotr16($q0 ^ $r0);
$this->values[1] = $q0 ^ $r0 ^ $q7 ^ $r7 ^ $r1 ^ self::rotr16($q1 ^ $r1);
$this->values[2] = $q1 ^ $r1 ^ $r2 ^ self::rotr16($q2 ^ $r2);
$this->values[3] = $q2 ^ $r2 ^ $q7 ^ $r7 ^ $r3 ^ self::rotr16($q3 ^ $r3);
$this->values[4] = $q3 ^ $r3 ^ $q7 ^ $r7 ^ $r4 ^ self::rotr16($q4 ^ $r4);
$this->values[5] = $q4 ^ $r4 ^ $r5 ^ self::rotr16($q5 ^ $r5);
$this->values[6] = $q5 ^ $r5 ^ $r6 ^ self::rotr16($q6 ^ $r6);
$this->values[7] = $q6 ^ $r6 ^ $r7 ^ self::rotr16($q7 ^ $r7);
return $this;
}
/**
* @return static
*/
public function inverseMixColumns(): static
{
$q0 = $this->values[0];
$q1 = $this->values[1];
$q2 = $this->values[2];
$q3 = $this->values[3];
$q4 = $this->values[4];
$q5 = $this->values[5];
$q6 = $this->values[6];
$q7 = $this->values[7];
$r0 = (($q0 >> 8) | ($q0 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r1 = (($q1 >> 8) | ($q1 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r2 = (($q2 >> 8) | ($q2 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r3 = (($q3 >> 8) | ($q3 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r4 = (($q4 >> 8) | ($q4 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r5 = (($q5 >> 8) | ($q5 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r6 = (($q6 >> 8) | ($q6 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$r7 = (($q7 >> 8) | ($q7 << 24)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$this->values[0] = $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r5 ^ $r7 ^ self::rotr16($q0 ^ $q5 ^ $q6 ^ $r0 ^ $r5);
$this->values[1] = $q0 ^ $q5 ^ $r0 ^ $r1 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q5 ^ $q7 ^ $r1 ^ $r5 ^ $r6);
$this->values[2] = $q0 ^ $q1 ^ $q6 ^ $r1 ^ $r2 ^ $r6 ^ $r7 ^ self::rotr16($q0 ^ $q2 ^ $q6 ^ $r2 ^ $r6 ^ $r7);
$this->values[3] = $q0 ^ $q1 ^ $q2 ^ $q5 ^ $q6 ^ $r0 ^ $r2 ^ $r3 ^ $r5 ^ self::rotr16($q0 ^ $q1 ^ $q3 ^ $q5 ^ $q6 ^ $q7 ^ $r0 ^ $r3 ^ $r5 ^ $r7);
$this->values[4] = $q1 ^ $q2 ^ $q3 ^ $q5 ^ $r1 ^ $r3 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q1 ^ $q2 ^ $q4 ^ $q5 ^ $q7 ^ $r1 ^ $r4 ^ $r5 ^ $r6);
$this->values[5] = $q2 ^ $q3 ^ $q4 ^ $q6 ^ $r2 ^ $r4 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q2 ^ $q3 ^ $q5 ^ $q6 ^ $r2 ^ $r5 ^ $r6 ^ $r7);
$this->values[6] = $q3 ^ $q4 ^ $q5 ^ $q7 ^ $r3 ^ $r5 ^ $r6 ^ $r7 ^ self::rotr16($q3 ^ $q4 ^ $q6 ^ $q7 ^ $r3 ^ $r6 ^ $r7);
$this->values[7] = $q4 ^ $q5 ^ $q6 ^ $r4 ^ $r6 ^ $r7 ^ self::rotr16($q4 ^ $q5 ^ $q7 ^ $r4 ^ $r7);
return $this;
}
/**
* @return static
*/
public function inverseShiftRows(): static
{
for ($i = 0; $i < 8; ++$i) {
$x = $this->values[$i];
$this->values[$i] = ParagonIE_Sodium_Core_Util::U32_MAX & (
($x & 0x000000FF)
| (($x & 0x00003F00) << 2) | (($x & 0x0000C000) >> 6)
| (($x & 0x000F0000) << 4) | (($x & 0x00F00000) >> 4)
| (($x & 0x03000000) << 6) | (($x & 0xFC000000) >> 2)
);
}
return $this;
}
}
@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_AES_Expanded', false)) {
return;
}
/**
* @internal This should only be used by sodium_compat
*/
class ParagonIE_Sodium_Core_AES_Expanded extends ParagonIE_Sodium_Core_AES_KeySchedule
{}
@@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_AES_KeySchedule', false)) {
return;
}
/**
* @internal This should only be used by sodium_compat
*/
class ParagonIE_Sodium_Core_AES_KeySchedule
{
/** @var array<int, int> $skey -- has size 120 */
protected array $skey;
/** @var bool $expanded */
protected bool $expanded = false;
/** @var int $numRounds */
private int $numRounds;
/**
* @param array $skey
* @param int $numRounds
*/
public function __construct(array $skey, int $numRounds = 10)
{
$this->skey = $skey;
$this->numRounds = $numRounds;
}
/**
* Get a value at an arbitrary index. Mostly used for unit testing.
*
* @param int $i
* @return int
*/
public function get(int $i): int
{
return $this->skey[$i];
}
/**
* @return int
*/
public function getNumRounds(): int
{
return $this->numRounds;
}
/**
* @param int $offset
* @return ParagonIE_Sodium_Core_AES_Block
*/
public function getRoundKey(int $offset): ParagonIE_Sodium_Core_AES_Block
{
return ParagonIE_Sodium_Core_AES_Block::fromArray(
array_slice($this->skey, $offset, 8)
);
}
/**
* Return an expanded key schedule
*
* @return ParagonIE_Sodium_Core_AES_Expanded
*/
public function expand(): ParagonIE_Sodium_Core_AES_Expanded
{
$exp = new ParagonIE_Sodium_Core_AES_Expanded(
array_fill(0, 120, 0),
$this->numRounds
);
$n = ($exp->numRounds + 1) << 2;
for ($u = 0, $v = 0; $u < $n; ++$u, $v += 2) {
$x = $y = $this->skey[$u];
$x &= 0x55555555;
$exp->skey[$v] = ($x | ($x << 1)) & ParagonIE_Sodium_Core_Util::U32_MAX;
$y &= 0xAAAAAAAA;
$exp->skey[$v + 1] = ($y | ($y >> 1)) & ParagonIE_Sodium_Core_Util::U32_MAX;
}
return $exp;
}
}
+755
View File
@@ -0,0 +1,755 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_BLAKE2b', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_BLAKE2b
*
* Based on the work of Devi Mandiri in devi/salt.
*/
abstract class ParagonIE_Sodium_Core_BLAKE2b extends ParagonIE_Sodium_Core_Util
{
/**
* @var SplFixedArray
*/
protected static SplFixedArray $iv;
/**
* @var array<int, array<int, int>>
*/
protected const SIGMA = [
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
[ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
[ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
[ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
[ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
[ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
[ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
[ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
[ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0],
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3]
];
const KEYBYTES = 64;
/**
* Turn two 32-bit integers into a fixed array representing a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int $high
* @param int $low
* @return SplFixedArray
*/
public static function new64(int $high, int $low): SplFixedArray
{
$i64 = new SplFixedArray(2);
$i64[0] = $high & 0xffffffff;
$i64[1] = $low & 0xffffffff;
return $i64;
}
/**
* Convert an arbitrary number into an SplFixedArray of two 32-bit integers
* that represents a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int $num
* @return SplFixedArray
*/
protected static function to64(int $num): SplFixedArray
{
list($hi, $lo) = self::numericTo64BitInteger($num);
return self::new64($hi, $lo);
}
/**
* Adds two 64-bit integers together, returning their sum as a SplFixedArray
* containing two 32-bit integers (representing a 64-bit integer).
*
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param SplFixedArray $y
* @return SplFixedArray
*/
public static function add64(SplFixedArray $x, SplFixedArray $y): SplFixedArray
{
$l = ($x[1] + $y[1]) & 0xffffffff;
return self::new64(
(int) ($x[0] + $y[0] + (
($l < $x[1]) ? 1 : 0
)),
$l
);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param SplFixedArray $y
* @param SplFixedArray $z
* @return SplFixedArray
* @throws SodiumException
*/
public static function add364(
SplFixedArray $x,
SplFixedArray $y,
SplFixedArray $z
): SplFixedArray {
return self::add64($x, self::add64($y, $z));
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param SplFixedArray $y
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
*/
public static function xor64(SplFixedArray $x, SplFixedArray $y): SplFixedArray
{
if (!is_numeric($x[0])) {
throw new SodiumException('x[0] is not an integer');
}
if (!is_numeric($x[1])) {
throw new SodiumException('x[1] is not an integer');
}
if (!is_numeric($y[0])) {
throw new SodiumException('y[0] is not an integer');
}
if (!is_numeric($y[1])) {
throw new SodiumException('y[1] is not an integer');
}
return self::new64(
(int) (($x[0] ^ $y[0]) & 0xffffffff),
(int) (($x[1] ^ $y[1]) & 0xffffffff)
);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $c
* @return SplFixedArray
*
* @throws SodiumException
*/
public static function rotr64(SplFixedArray $x, int $c): SplFixedArray
{
if ($c >= 64) {
$c %= 64;
}
if ($c >= 32) {
/** @var int $tmp */
$tmp = $x[0];
$x[0] = $x[1];
$x[1] = $tmp;
$c -= 32;
}
if ($c === 0) {
return $x;
}
$l0 = 0;
/** @var int $c */
$c = 64 - $c;
if ($c < 32) {
$h0 = ((int) ($x[0]) << $c) | (
(
(int) ($x[1]) & ((1 << $c) - 1)
<<
(32 - $c)
) >> (32 - $c)
);
$l0 = (int) ($x[1]) << $c;
} else {
$h0 = (int) ($x[1]) << ($c - 32);
}
$h1 = 0;
$c1 = 64 - $c;
if ($c1 < 32) {
$h1 = (int) ($x[0]) >> $c1;
$l1 = ((int) ($x[1]) >> $c1) | ((int) ($x[0]) & ((1 << $c1) - 1)) << (32 - $c1);
} else {
$l1 = (int) ($x[0]) >> ($c1 - 32);
}
return self::new64($h0 | $h1, $l0 | $l1);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @return int
*/
protected static function flatten64(SplFixedArray $x): int
{
return (int) ($x[0] * 4294967296 + $x[1]);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $i
* @return SplFixedArray
*/
protected static function load64(SplFixedArray $x, int $i): SplFixedArray
{
$l = (int) ($x[$i])
| ((int) ($x[$i+1]) << 8)
| ((int) ($x[$i+2]) << 16)
| ((int) ($x[$i+3]) << 24);
$h = (int) ($x[$i+4])
| ((int) ($x[$i+5]) << 8)
| ((int) ($x[$i+6]) << 16)
| ((int) ($x[$i+7]) << 24);
return self::new64($h, $l);
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $x
* @param int $i
* @param SplFixedArray $u
* @return void
*/
protected static function store64(SplFixedArray $x, int $i, SplFixedArray $u): void
{
$maxLength = $x->getSize() - 1;
for ($j = 0; $j < 8; ++$j) {
/*
[0, 1, 2, 3, 4, 5, 6, 7]
... becomes ...
[0, 0, 0, 0, 1, 1, 1, 1]
*/
$uIdx = ((7 - $j) & 4) >> 2;
$x[$i] = ((int) ($u[$uIdx]) & 0xff);
if (++$i > $maxLength) {
return;
}
$u[$uIdx] >>= 8;
}
}
/**
* This just sets the $iv static variable.
*
* @internal You should not use this directly from another application
*
* @return void
*
* @throws SodiumException
*/
public static function pseudoConstructor(): void
{
static $called = false;
if ($called) {
return;
}
self::$iv = new SplFixedArray(8);
self::$iv[0] = self::new64(0x6a09e667, 0xf3bcc908);
self::$iv[1] = self::new64(0xbb67ae85, 0x84caa73b);
self::$iv[2] = self::new64(0x3c6ef372, 0xfe94f82b);
self::$iv[3] = self::new64(0xa54ff53a, 0x5f1d36f1);
self::$iv[4] = self::new64(0x510e527f, 0xade682d1);
self::$iv[5] = self::new64(0x9b05688c, 0x2b3e6c1f);
self::$iv[6] = self::new64(0x1f83d9ab, 0xfb41bd6b);
self::$iv[7] = self::new64(0x5be0cd19, 0x137e2179);
$called = true;
}
/**
* Returns a fresh BLAKE2 context.
*
* @internal You should not use this directly from another application
*
* @return SplFixedArray
*
* @throws SodiumException
*/
protected static function context(): SplFixedArray
{
$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];
}
for ($i = 256; $i--;) {
$ctx[3][$i] = 0;
}
$zero = self::new64(0, 0);
$ctx[1][0] = $zero;
$ctx[1][1] = $zero;
$ctx[2][0] = $zero;
$ctx[2][1] = $zero;
return $ctx;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $buf
* @return void
* @throws SodiumException
* @throws TypeError
*/
protected static function compress(SplFixedArray $ctx, SplFixedArray $buf): void
{
$m = new SplFixedArray(16);
$v = new SplFixedArray(16);
for ($i = 16; $i--;) {
$m[$i] = self::load64($buf, $i << 3);
}
for ($i = 8; $i--;) {
$v[$i] = $ctx[0][$i];
}
$v[ 8] = self::$iv[0];
$v[ 9] = self::$iv[1];
$v[10] = self::$iv[2];
$v[11] = self::$iv[3];
$v[12] = self::xor64($ctx[1][0], self::$iv[4]);
$v[13] = self::xor64($ctx[1][1], self::$iv[5]);
$v[14] = self::xor64($ctx[2][0], self::$iv[6]);
$v[15] = self::xor64($ctx[2][1], self::$iv[7]);
for ($r = 0; $r < 12; ++$r) {
$v = self::G($r, 0, 0, 4, 8, 12, $v, $m);
$v = self::G($r, 1, 1, 5, 9, 13, $v, $m);
$v = self::G($r, 2, 2, 6, 10, 14, $v, $m);
$v = self::G($r, 3, 3, 7, 11, 15, $v, $m);
$v = self::G($r, 4, 0, 5, 10, 15, $v, $m);
$v = self::G($r, 5, 1, 6, 11, 12, $v, $m);
$v = self::G($r, 6, 2, 7, 8, 13, $v, $m);
$v = self::G($r, 7, 3, 4, 9, 14, $v, $m);
}
for ($i = 8; $i--;) {
$ctx[0][$i] = self::xor64(
$ctx[0][$i], self::xor64($v[$i], $v[$i+8])
);
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $r
* @param int $i
* @param int $a
* @param int $b
* @param int $c
* @param int $d
* @param SplFixedArray $v
* @param SplFixedArray $m
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
*/
public static function G(
int $r,
int $i,
int $a,
int $b,
int $c,
int $d,
SplFixedArray $v,
SplFixedArray $m
): SplFixedArray {
$v[$a] = self::add364($v[$a], $v[$b], $m[self::SIGMA[$r][$i << 1]]);
$v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 32);
$v[$c] = self::add64($v[$c], $v[$d]);
$v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 24);
$v[$a] = self::add364($v[$a], $v[$b], $m[self::SIGMA[$r][($i << 1) + 1]]);
$v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 16);
$v[$c] = self::add64($v[$c], $v[$d]);
$v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 63);
return $v;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param int $inc
* @return void
*
* @throws SodiumException
*/
public static function increment_counter(SplFixedArray $ctx, int $inc): void
{
if ($inc < 0) {
throw new SodiumException('Increasing by a negative number makes no sense.');
}
$t = self::to64($inc);
# S->t is $ctx[1] in our implementation
# S->t[0] = ( uint64_t )( t >> 0 );
$ctx[1][0] = self::add64($ctx[1][0], $t);
# S->t[1] += ( S->t[0] < inc );
if (self::flatten64($ctx[1][0]) < $inc) {
$ctx[1][1] = self::add64($ctx[1][1], self::to64(1));
}
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $p
* @param int $plen
* @return void
*
* @throws SodiumException
* @throws TypeError
*/
public static function update(SplFixedArray $ctx, SplFixedArray $p, int $plen): void
{
self::pseudoConstructor();
$offset = 0;
while ($plen > 0) {
$left = $ctx[4];
$fill = 256 - $left;
if ($plen > $fill) {
# memcpy( S->buf + left, in, fill ); /* Fill buffer */
for ($i = $fill; $i--;) {
$ctx[3][$i + $left] = $p[(int) ($i + $offset)];
}
# S->buflen += fill;
$ctx[4] += $fill;
# blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
self::increment_counter($ctx, 128);
# blake2b_compress( S, S->buf ); /* Compress */
self::compress($ctx, $ctx[3]);
# memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); /* Shift buffer left */
for ($i = 128; $i--;) {
$ctx[3][$i] = $ctx[3][$i + 128];
}
# S->buflen -= BLAKE2B_BLOCKBYTES;
$ctx[4] -= 128;
# in += fill;
$offset += $fill;
# inlen -= fill;
$plen -= $fill;
} else {
for ($i = $plen; $i--;) {
$ctx[3][$i + $left] = $p[(int) ($i + $offset)];
}
$ctx[4] += $plen;
$offset += $plen;
$plen -= $plen;
}
}
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @param SplFixedArray $out
* @return SplFixedArray
*
* @throws SodiumException
* @throws TypeError
*/
public static function finish(SplFixedArray $ctx, SplFixedArray $out): SplFixedArray
{
self::pseudoConstructor();
if ($ctx[4] > 128) {
self::increment_counter($ctx, 128);
self::compress($ctx, $ctx[3]);
$ctx[4] -= 128;
if ($ctx[4] > 128) {
throw new SodiumException('Failed to assert that buflen <= 128 bytes');
}
for ($i = $ctx[4]; $i--;) {
$ctx[3][$i] = $ctx[3][$i + 128];
}
}
self::increment_counter($ctx, $ctx[4]);
$ctx[2][0] = self::new64(0xffffffff, 0xffffffff);
for ($i = 256 - $ctx[4]; $i--;) {
$ctx[3][$i+$ctx[4]] = 0;
}
self::compress($ctx, $ctx[3]);
$i = (int) (($out->getSize() - 1) / 8);
for (; $i >= 0; --$i) {
self::store64($out, $i << 3, $ctx[0][$i]);
}
return $out;
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray|null $key
* @param int $outlen
* @param SplFixedArray|null $salt
* @param SplFixedArray|null $personal
* @return SplFixedArray
*
* @throws SodiumException
* @throws TypeError
*/
public static function init(
?SplFixedArray $key = null,
int $outlen = 64,
?SplFixedArray $salt = null,
?SplFixedArray $personal = null
): SplFixedArray {
self::pseudoConstructor();
$klen = 0;
if ($key !== null) {
if (count($key) > 64) {
throw new SodiumException('Invalid key size');
}
$klen = count($key);
}
if ($outlen > 64) {
throw new SodiumException('Invalid output size');
}
$ctx = self::context();
$p = new SplFixedArray(64);
// Zero our param buffer...
for ($i = 64; --$i;) {
$p[$i] = 0;
}
$p[0] = $outlen; // digest_length
$p[1] = $klen; // key_length
$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--;) {
$block[$i] = 0;
}
for ($i = $klen; $i--;) {
$block[$i] = $key[$i];
}
self::update($ctx, $block, 128);
$ctx[4] = 128;
}
return $ctx;
}
/**
* Convert a string into an SplFixedArray of integers
*
* @internal You should not use this directly from another application
*
* @param string $str
* @return SplFixedArray
*/
public static function stringToSplFixedArray(string $str = ''): SplFixedArray
{
$values = unpack('C*', $str);
return SplFixedArray::fromArray(array_values($values));
}
/**
* Convert an SplFixedArray of integers into a string
*
* @internal You should not use this directly from another application
*
* @param SplFixedArray $a
* @return string
* @throws TypeError
*/
public static function SplFixedArrayToString(SplFixedArray $a): string
{
/**
* @var array<int, int|string> $arr
*/
$arr = $a->toArray();
$c = $a->count();
array_unshift($arr, str_repeat('C', $c));
return (string) (call_user_func_array('pack', $arr));
}
/**
* @internal You should not use this directly from another application
*
* @param SplFixedArray $ctx
* @return string
* @throws TypeError
*/
public static function contextToString(SplFixedArray $ctx): string
{
$str = '';
/** @var array<int, array<int, int>> $ctxA */
$ctxA = $ctx[0]->toArray();
# uint64_t h[8];
for ($i = 0; $i < 8; ++$i) {
$str .= self::store32_le($ctxA[$i][1]);
$str .= self::store32_le($ctxA[$i][0]);
}
# uint64_t t[2];
# uint64_t f[2];
for ($i = 1; $i < 3; ++$i) {
$ctxA = $ctx[$i]->toArray();
$str .= self::store32_le($ctxA[0][1]);
$str .= self::store32_le($ctxA[0][0]);
$str .= self::store32_le($ctxA[1][1]);
$str .= self::store32_le($ctxA[1][0]);
}
# uint8_t buf[2 * 128];
$str .= self::SplFixedArrayToString($ctx[3]);
/** @var int $ctx4 */
$ctx4 = (int) $ctx[4];
# size_t buflen;
$str .= implode('', array(
self::intToChr($ctx4 & 0xff),
self::intToChr(($ctx4 >> 8) & 0xff),
self::intToChr(($ctx4 >> 16) & 0xff),
self::intToChr(($ctx4 >> 24) & 0xff),
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 . self::intToChr($ctx[5]) . str_repeat("\x00", 23);
}
/**
* Creates an SplFixedArray containing other SplFixedArray elements, from
* a string (compatible with \Sodium\crypto_generichash_{init, update, final})
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return SplFixedArray
* @throws SodiumException
* @throws TypeError
*/
public static function stringToContext(string $string): SplFixedArray
{
$ctx = self::context();
# uint64_t h[8];
for ($i = 0; $i < 8; ++$i) {
$ctx[0][$i] = SplFixedArray::fromArray(
array(
self::load_4(
self::substr($string, (($i << 3) + 4), 4)
),
self::load_4(
self::substr($string, (($i << 3)), 4)
)
)
);
}
# uint64_t t[2];
# uint64_t f[2];
for ($i = 1; $i < 3; ++$i) {
$ctx[$i][1] = SplFixedArray::fromArray(
array(
self::load_4(self::substr($string, 76 + (($i - 1) << 4), 4)),
self::load_4(self::substr($string, 72 + (($i - 1) << 4), 4))
)
);
$ctx[$i][0] = SplFixedArray::fromArray(
array(
self::load_4(self::substr($string, 68 + (($i - 1) << 4), 4)),
self::load_4(self::substr($string, 64 + (($i - 1) << 4), 4))
)
);
}
# 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) {
$int |= self::chrToInt($string[352 + $i]) << ($i << 3);
}
$ctx[4] = $int;
return $ctx;
}
}
@@ -0,0 +1,214 @@
<?php
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(
#[SensitiveParameter]
string $src
): string {
return static::doEncode($src);
}
/**
* 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(
#[SensitiveParameter]
string $src
): string {
return static::doEncode($src, false);
}
/**
* @param string $src
* @param bool $pad Include = padding?
* @return string
* @throws TypeError
*/
protected static function doEncode(
#[SensitiveParameter]
string $src,
bool $pad = true
): string {
$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 .=
static::encode6Bits( $b0 >> 2 ) .
static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
static::encode6Bits((($b1 << 2) | ($b2 >> 6)) & 63) .
static::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 .=
static::encode6Bits($b0 >> 2) .
static::encode6Bits((($b0 << 4) | ($b1 >> 4)) & 63) .
static::encode6Bits(($b1 << 2) & 63);
if ($pad) {
$dest .= '=';
}
} else {
$dest .=
static::encode6Bits( $b0 >> 2) .
static::encode6Bits(($b0 << 4) & 63);
if ($pad) {
$dest .= '==';
}
}
}
return $dest;
}
/**
* Decode from base64 into binary
*
* @throws RangeException
* @throws TypeError
*/
public static function decode(
#[SensitiveParameter]
string $src,
bool $strictPadding = false
): string {
// 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 = static::decode6Bits($chunk[1]);
$c1 = static::decode6Bits($chunk[2]);
$c2 = static::decode6Bits($chunk[3]);
$c3 = static::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 = static::decode6Bits($chunk[1]);
if ($i + 2 < $srcLen) {
$c1 = static::decode6Bits($chunk[2]);
$c2 = static::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 = static::decode6Bits($chunk[2]);
$dest .= pack(
'C',
((($c0 << 2) | ($c1 >> 4)) & 0xff)
);
$err |= ($c0 | $c1) >> 8;
}
}
$check = ($err === 0);
if (!$check) {
throw new RangeException(
'Base64::decode() only expects characters in the correct base64 alphabet'
);
}
return $dest;
}
public static function decodeNoPadding(
#[SensitiveParameter]
string $encodedString
): string {
$srcLen = strlen($encodedString);
if ($srcLen === 0) {
return '';
}
if (($srcLen & 3) === 0) {
// If $strLen is not zero, and it is divisible by 4, then it's at least 4.
if ($encodedString[$srcLen - 1] === '=' || $encodedString[$srcLen - 2] === '=') {
throw new InvalidArgumentException(
"decodeNoPadding() doesn't tolerate padding"
);
}
}
return static::decode(
$encodedString,
true
);
}
abstract protected static function decode6Bits(
#[SensitiveParameter]
int $src
): int;
abstract protected static function encode6Bits(
#[SensitiveParameter]
int $src
): string;
}
@@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
/**
* 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 extends ParagonIE_Sodium_Core_Base64_Common
{
/**
* 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(
#[SensitiveParameter]
int $src
): int {
$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(
#[SensitiveParameter]
int $src
): string {
$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,73 @@
<?php
declare(strict_types=1);
/**
* 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 extends ParagonIE_Sodium_Core_Base64_Common
{
/**
* 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(
#[SensitiveParameter]
int $src
): int {
$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(
#[SensitiveParameter] int $src
): string {
$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);
}
}
+309
View File
@@ -0,0 +1,309 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_ChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20
*/
class ParagonIE_Sodium_Core_ChaCha20 extends ParagonIE_Sodium_Core_Util
{
/**
* Bitwise left rotation
*
* @internal You should not use this directly from another application
*
* @param int $v
* @param int $n
* @return int
*/
public static function rotate(int $v, int $n): int
{
$v &= 0xffffffff;
$n &= 31;
return (
0xffffffff & (
($v << $n)
|
($v >> (32 - $n))
)
);
}
/**
* The ChaCha20 quarter round function. Works on four 32-bit integers.
*
* @internal You should not use this directly from another application
*
* @param int $a
* @param int $b
* @param int $c
* @param int $d
* @return array<int, int>
*/
protected static function quarterRound(int $a, int $b, int $c, int $d): array
{
# a = PLUS(a,b); d = ROTATE(XOR(d,a),16);
/** @var int $a */
$a = ($a + $b) & 0xffffffff;
$d = self::rotate($d ^ $a, 16);
# c = PLUS(c,d); b = ROTATE(XOR(b,c),12);
/** @var int $c */
$c = ($c + $d) & 0xffffffff;
$b = self::rotate($b ^ $c, 12);
# a = PLUS(a,b); d = ROTATE(XOR(d,a), 8);
/** @var int $a */
$a = ($a + $b) & 0xffffffff;
$d = self::rotate($d ^ $a, 8);
# c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
/** @var int $c */
$c = ($c + $d) & 0xffffffff;
$b = self::rotate($b ^ $c, 7);
return array($a, $b, $c, $d);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx
* @param string $message
*
* @return string
* @throws TypeError
* @throws SodiumException
*/
public static function encryptBytes(
ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx,
#[SensitiveParameter]
string $message = ''
): string {
$bytes = self::strlen($message);
$j0 = (int) $ctx[0];
$j1 = (int) $ctx[1];
$j2 = (int) $ctx[2];
$j3 = (int) $ctx[3];
$j4 = (int) $ctx[4];
$j5 = (int) $ctx[5];
$j6 = (int) $ctx[6];
$j7 = (int) $ctx[7];
$j8 = (int) $ctx[8];
$j9 = (int) $ctx[9];
$j10 = (int) $ctx[10];
$j11 = (int) $ctx[11];
$j12 = (int) $ctx[12];
$j13 = (int) $ctx[13];
$j14 = (int) $ctx[14];
$j15 = (int) $ctx[15];
$c = '';
for (;;) {
if ($bytes < 64) {
$message .= str_repeat("\x00", 64 - $bytes);
}
$x0 = $j0;
$x1 = $j1;
$x2 = $j2;
$x3 = $j3;
$x4 = $j4;
$x5 = $j5;
$x6 = $j6;
$x7 = $j7;
$x8 = $j8;
$x9 = $j9;
$x10 = $j10;
$x11 = $j11;
$x12 = $j12;
$x13 = $j13;
$x14 = $j14;
$x15 = $j15;
# for (i = 20; i > 0; i -= 2) {
for ($i = 20; $i > 0; $i -= 2) {
[$x0, $x4, $x8, $x12] = self::quarterRound($x0, $x4, $x8, $x12);
[$x1, $x5, $x9, $x13] = self::quarterRound($x1, $x5, $x9, $x13);
[$x2, $x6, $x10, $x14] = self::quarterRound($x2, $x6, $x10, $x14);
[$x3, $x7, $x11, $x15] = self::quarterRound($x3, $x7, $x11, $x15);
[$x0, $x5, $x10, $x15] = self::quarterRound($x0, $x5, $x10, $x15);
[$x1, $x6, $x11, $x12] = self::quarterRound($x1, $x6, $x11, $x12);
[$x2, $x7, $x8, $x13] = self::quarterRound($x2, $x7, $x8, $x13);
[$x3, $x4, $x9, $x14] = self::quarterRound($x3, $x4, $x9, $x14);
}
$x0 = ($x0 & 0xffffffff) + $j0;
$x1 = ($x1 & 0xffffffff) + $j1;
$x2 = ($x2 & 0xffffffff) + $j2;
$x3 = ($x3 & 0xffffffff) + $j3;
$x4 = ($x4 & 0xffffffff) + $j4;
$x5 = ($x5 & 0xffffffff) + $j5;
$x6 = ($x6 & 0xffffffff) + $j6;
$x7 = ($x7 & 0xffffffff) + $j7;
$x8 = ($x8 & 0xffffffff) + $j8;
$x9 = ($x9 & 0xffffffff) + $j9;
$x10 = ($x10 & 0xffffffff) + $j10;
$x11 = ($x11 & 0xffffffff) + $j11;
$x12 = ($x12 & 0xffffffff) + $j12;
$x13 = ($x13 & 0xffffffff) + $j13;
$x14 = ($x14 & 0xffffffff) + $j14;
$x15 = ($x15 & 0xffffffff) + $j15;
$x0 ^= self::load_4(self::substr($message, 0, 4));
$x1 ^= self::load_4(self::substr($message, 4, 4));
$x2 ^= self::load_4(self::substr($message, 8, 4));
$x3 ^= self::load_4(self::substr($message, 12, 4));
$x4 ^= self::load_4(self::substr($message, 16, 4));
$x5 ^= self::load_4(self::substr($message, 20, 4));
$x6 ^= self::load_4(self::substr($message, 24, 4));
$x7 ^= self::load_4(self::substr($message, 28, 4));
$x8 ^= self::load_4(self::substr($message, 32, 4));
$x9 ^= self::load_4(self::substr($message, 36, 4));
$x10 ^= self::load_4(self::substr($message, 40, 4));
$x11 ^= self::load_4(self::substr($message, 44, 4));
$x12 ^= self::load_4(self::substr($message, 48, 4));
$x13 ^= self::load_4(self::substr($message, 52, 4));
$x14 ^= self::load_4(self::substr($message, 56, 4));
$x15 ^= self::load_4(self::substr($message, 60, 4));
++$j12;
if ($j12 & 0xf0000000) {
throw new SodiumException('Overflow');
}
$block = self::store32_le(($x0 & 0xffffffff)) .
self::store32_le(($x1 & 0xffffffff)) .
self::store32_le(($x2 & 0xffffffff)) .
self::store32_le(($x3 & 0xffffffff)) .
self::store32_le(($x4 & 0xffffffff)) .
self::store32_le(($x5 & 0xffffffff)) .
self::store32_le(($x6 & 0xffffffff)) .
self::store32_le(($x7 & 0xffffffff)) .
self::store32_le(($x8 & 0xffffffff)) .
self::store32_le(($x9 & 0xffffffff)) .
self::store32_le(($x10 & 0xffffffff)) .
self::store32_le(($x11 & 0xffffffff)) .
self::store32_le(($x12 & 0xffffffff)) .
self::store32_le(($x13 & 0xffffffff)) .
self::store32_le(($x14 & 0xffffffff)) .
self::store32_le(($x15 & 0xffffffff));
/* Partial block */
if ($bytes < 64) {
$c .= self::substr($block, 0, $bytes);
break;
}
/* Full block */
$c .= $block;
$bytes -= 64;
if ($bytes <= 0) {
break;
}
$message = self::substr($message, 64);
}
/* end for(;;) loop */
$ctx[12] = $j12;
$ctx[13] = $j13;
return $c;
}
/**
* @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 stream(
int $len,
string $nonce,
#[SensitiveParameter]
string $key
): string {
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce),
str_repeat("\x00", $len)
);
}
/**
* @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(
int $len,
string $nonce,
#[SensitiveParameter]
string $key
): string {
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce),
str_repeat("\x00", $len)
);
}
/**
* @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(
#[SensitiveParameter]
string $message,
string $nonce,
#[SensitiveParameter]
string $key,
string $ic = ''
): string {
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce, $ic),
$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 streamXorIc(
#[SensitiveParameter]
string $message,
string $nonce,
#[SensitiveParameter]
string $key,
string $ic = ''
): string {
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce, $ic),
$message
);
}
}
+140
View File
@@ -0,0 +1,140 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_ChaCha20_Ctx', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20_Ctx
*
* @template-implements ArrayAccess<int>
* @psalm-suppress MissingTemplateParam
*/
class ParagonIE_Sodium_Core_ChaCha20_Ctx extends ParagonIE_Sodium_Core_Util implements ArrayAccess
{
/**
* @var SplFixedArray internally, <int, int>
*/
protected SplFixedArray $container;
/**
* ParagonIE_Sodium_Core_ChaCha20_Ctx constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key ChaCha20 key.
* @param string $iv Initialization Vector (a.k.a. nonce).
* @param string $counter The initial counter value.
* Defaults to 8 0x00 bytes.
*
* @throws SodiumException
* @throws InvalidArgumentException
* @throws TypeError
*/
public function __construct(
#[SensitiveParameter]
string $key = '',
string $iv = '',
string $counter = ''
) {
if (self::strlen($key) !== 32) {
throw new InvalidArgumentException('ChaCha20 expects a 256-bit key.');
}
if (self::strlen($iv) !== 8) {
throw new InvalidArgumentException('ChaCha20 expects a 64-bit nonce.');
}
$this->container = new SplFixedArray(16);
/* "expand 32-byte k" as per ChaCha20 spec */
$this->container[0] = 0x61707865;
$this->container[1] = 0x3320646e;
$this->container[2] = 0x79622d32;
$this->container[3] = 0x6b206574;
$this->container[4] = self::load_4(self::substr($key, 0, 4));
$this->container[5] = self::load_4(self::substr($key, 4, 4));
$this->container[6] = self::load_4(self::substr($key, 8, 4));
$this->container[7] = self::load_4(self::substr($key, 12, 4));
$this->container[8] = self::load_4(self::substr($key, 16, 4));
$this->container[9] = self::load_4(self::substr($key, 20, 4));
$this->container[10] = self::load_4(self::substr($key, 24, 4));
$this->container[11] = self::load_4(self::substr($key, 28, 4));
$counter = $this->initCounter($counter);
$this->container[12] = self::load_4(self::substr($counter, 0, 4));
$this->container[13] = self::load_4(self::substr($counter, 4, 4));
$this->container[14] = self::load_4(self::substr($iv, 0, 4));
$this->container[15] = self::load_4(self::substr($iv, 4, 4));
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @param int $value
* @return void
*/
#[ReturnTypeWillChange]
public function offsetSet($offset, $value): void
{
$this->container[$offset] = $value;
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return bool
*/
#[ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->container[$offset]);
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return void
*/
#[ReturnTypeWillChange]
public function offsetUnset($offset): void
{
unset($this->container[$offset]);
}
/**
* Initialize (pad) a counter value.
* @throws SodiumException
*/
public function initCounter(#[SensitiveParameter] string $ctr): string
{
$len = self::strlen($ctr);
if ($len === 0) {
return str_repeat("\0", 8);
}
if ($len < 8) {
return $ctr . str_repeat("\0", 8 - $len);
}
if ($len > 8) {
throw new SodiumException("counter cannot be more than 8 bytes");
}
return $ctr;
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return mixed|null
*/
#[ReturnTypeWillChange]
public function offsetGet($offset)
{
return isset($this->container[$offset])
? $this->container[$offset]
: null;
}
}
@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_ChaCha20_IetfCtx', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_ChaCha20_IetfCtx
*/
class ParagonIE_Sodium_Core_ChaCha20_IetfCtx extends ParagonIE_Sodium_Core_ChaCha20_Ctx
{
/**
* ParagonIE_Sodium_Core_ChaCha20_IetfCtx constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key ChaCha20 key.
* @param string $iv Initialization Vector (a.k.a. nonce).
* @param string $counter The initial counter value.
* Defaults to 4 0x00 bytes.
*
* @throws InvalidArgumentException
* @throws SodiumException
* @throws TypeError
*/
public function __construct(
#[SensitiveParameter]
string $key = '',
string $iv = '',
string $counter = ''
) {
if (self::strlen($iv) !== 12) {
throw new InvalidArgumentException('ChaCha20 expects a 96-bit nonce in IETF mode.');
}
$counter = $this->initCounter($counter);
parent::__construct($key, self::substr($iv, 0, 8), $counter);
$this->container[12] = self::load_4(self::substr($counter, 0, 4));
$this->container[13] = self::load_4(self::substr($iv, 0, 4));
$this->container[14] = self::load_4(self::substr($iv, 4, 4));
$this->container[15] = self::load_4(self::substr($iv, 8, 4));
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,199 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Fe', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Fe
*
* This represents a Field Element
*
* @psalm-suppress MissingTemplateParam
*/
class ParagonIE_Sodium_Core_Curve25519_Fe implements ArrayAccess
{
public function __construct(
public int $e0 = 0,
public int $e1 = 0,
public int $e2 = 0,
public int $e3 = 0,
public int $e4 = 0,
public int $e5 = 0,
public int $e6 = 0,
public int $e7 = 0,
public int $e8 = 0,
public int $e9 = 0,
) {}
/**
* @internal You should not use this directly from another application
*
* @param array<int, int> $array
* @return self
* @throws SodiumException
*/
public static function fromArray(array $array): self
{
if (count($array) !== 10) {
throw new SodiumException('Fewer than 10 items received');
}
$values = array_values($array);
return new self(
$values[0],
$values[1],
$values[2],
$values[3],
$values[4],
$values[5],
$values[6],
$values[7],
$values[8],
$values[9],
);
}
/**
* @internal You should not use this directly from another application
*
* @param int|null $offset
* @param int $value
* @return void
*/
#[ReturnTypeWillChange]
public function offsetSet($offset, $value): void
{
switch ($offset) {
case 0:
$this->e0 = $value;
break;
case 1:
$this->e1 = $value;
break;
case 2:
$this->e2 = $value;
break;
case 3:
$this->e3 = $value;
break;
case 4:
$this->e4 = $value;
break;
case 5:
$this->e5 = $value;
break;
case 6:
$this->e6 = $value;
break;
case 7:
$this->e7 = $value;
break;
case 8:
$this->e8 = $value;
break;
case 9:
$this->e9 = $value;
break;
default:
throw new OutOfBoundsException('Invalid offset.');
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return bool
*/
#[ReturnTypeWillChange]
public function offsetExists($offset): bool
{
return $offset >= 0 && $offset < 10;
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return void
*/
#[ReturnTypeWillChange]
public function offsetUnset($offset): void
{
switch ($offset) {
case 0:
$this->e0 = 0;
break;
case 1:
$this->e1 = 0;
break;
case 2:
$this->e2 = 0;
break;
case 3:
$this->e3 = 0;
break;
case 4:
$this->e4 = 0;
break;
case 5:
$this->e5 = 0;
break;
case 6:
$this->e6 = 0;
break;
case 7:
$this->e7 = 0;
break;
case 8:
$this->e8 = 0;
break;
case 9:
$this->e9 = 0;
break;
default:
throw new OutOfBoundsException('Invalid offset.');
}
}
/**
* @internal You should not use this directly from another application
*
* @param int $offset
* @return int
* @psalm-suppress ImplementedReturnTypeMismatch
*/
#[ReturnTypeWillChange]
public function offsetGet($offset): int
{
return match ($offset) {
0 => $this->e0,
1 => $this->e1,
2 => $this->e2,
3 => $this->e3,
4 => $this->e4,
5 => $this->e5,
6 => $this->e6,
7 => $this->e7,
8 => $this->e8,
9 => $this->e9,
default => throw new OutOfBoundsException('Invalid offset.'),
};
}
/**
* @internal You should not use this directly from another application
*
* @return array
*/
public function __debugInfo()
{
return array(
implode(', ', [
$this->e0, $this->e1, $this->e2, $this->e3, $this->e4,
$this->e5, $this->e6, $this->e7, $this->e8, $this->e9
])
);
}
}
@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_Cached', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_Cached
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_Cached
{
public ParagonIE_Sodium_Core_Curve25519_Fe $YplusX;
public ParagonIE_Sodium_Core_Curve25519_Fe $YminusX;
public ParagonIE_Sodium_Core_Curve25519_Fe $Z;
public ParagonIE_Sodium_Core_Curve25519_Fe $T2d;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_Cached constructor.
*
* @internal You should not use this directly from another application
*
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $YplusX
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $YminusX
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $Z
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $T2d
*/
public function __construct(
?ParagonIE_Sodium_Core_Curve25519_Fe $YplusX = null,
?ParagonIE_Sodium_Core_Curve25519_Fe $YminusX = null,
?ParagonIE_Sodium_Core_Curve25519_Fe $Z = null,
?ParagonIE_Sodium_Core_Curve25519_Fe $T2d = null
) {
if ($YplusX === null) {
$YplusX = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->YplusX = $YplusX;
if ($YminusX === null) {
$YminusX = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->YminusX = $YminusX;
if ($Z === null) {
$Z = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->Z = $Z;
if ($T2d === null) {
$T2d = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->T2d = $T2d;
}
}
@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P1p1', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
{
public ParagonIE_Sodium_Core_Curve25519_Fe $X;
public ParagonIE_Sodium_Core_Curve25519_Fe $Y;
public ParagonIE_Sodium_Core_Curve25519_Fe $Z;
public ParagonIE_Sodium_Core_Curve25519_Fe $T;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 constructor.
*
* @internal You should not use this directly from another application
*
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $x
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $y
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $z
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $t
*/
public function __construct(
?ParagonIE_Sodium_Core_Curve25519_Fe $x = null,
?ParagonIE_Sodium_Core_Curve25519_Fe $y = null,
?ParagonIE_Sodium_Core_Curve25519_Fe $z = null,
?ParagonIE_Sodium_Core_Curve25519_Fe $t = null
) {
if ($x === null) {
$x = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->X = $x;
if ($y === null) {
$y = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->Y = $y;
if ($z === null) {
$z = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->Z = $z;
if ($t === null) {
$t = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->T = $t;
}
}
@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P2', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P2
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_P2
{
public ParagonIE_Sodium_Core_Curve25519_Fe $X;
public ParagonIE_Sodium_Core_Curve25519_Fe $Y;
public ParagonIE_Sodium_Core_Curve25519_Fe $Z;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_P2 constructor.
*
* @internal You should not use this directly from another application
*
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $x
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $y
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $z
*/
public function __construct(
?ParagonIE_Sodium_Core_Curve25519_Fe $x = null,
?ParagonIE_Sodium_Core_Curve25519_Fe $y = null,
?ParagonIE_Sodium_Core_Curve25519_Fe $z = null
) {
if ($x === null) {
$x = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->X = $x;
if ($y === null) {
$y = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->Y = $y;
if ($z === null) {
$z = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->Z = $z;
}
}
@@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_P3', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_P3
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_P3
{
public ParagonIE_Sodium_Core_Curve25519_Fe $X;
public ParagonIE_Sodium_Core_Curve25519_Fe $Y;
public ParagonIE_Sodium_Core_Curve25519_Fe $Z;
public ParagonIE_Sodium_Core_Curve25519_Fe $T;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_P3 constructor.
*
* @internal You should not use this directly from another application
*
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $x
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $y
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $z
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $t
*/
public function __construct(
?ParagonIE_Sodium_Core_Curve25519_Fe $x = null,
?ParagonIE_Sodium_Core_Curve25519_Fe $y = null,
?ParagonIE_Sodium_Core_Curve25519_Fe $z = null,
?ParagonIE_Sodium_Core_Curve25519_Fe $t = null
) {
if ($x === null) {
$x = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->X = $x;
if ($y === null) {
$y = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->Y = $y;
if ($z === null) {
$z = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->Z = $z;
if ($t === null) {
$t = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->T = $t;
}
}
@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_Curve25519_Ge_Precomp', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
*/
class ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
{
public ParagonIE_Sodium_Core_Curve25519_Fe $yplusx;
public ParagonIE_Sodium_Core_Curve25519_Fe $yminusx;
public ParagonIE_Sodium_Core_Curve25519_Fe $xy2d;
/**
* ParagonIE_Sodium_Core_Curve25519_Ge_Precomp constructor.
*
* @internal You should not use this directly from another application
*
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $yplusx
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $yminusx
* @param ?ParagonIE_Sodium_Core_Curve25519_Fe $xy2d
*/
public function __construct(
?ParagonIE_Sodium_Core_Curve25519_Fe $yplusx = null,
?ParagonIE_Sodium_Core_Curve25519_Fe $yminusx = null,
?ParagonIE_Sodium_Core_Curve25519_Fe $xy2d = null
) {
if ($yplusx === null) {
$yplusx = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->yplusx = $yplusx;
if ($yminusx === null) {
$yminusx = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->yminusx = $yminusx;
if ($xy2d === null) {
$xy2d = new ParagonIE_Sodium_Core_Curve25519_Fe();
}
$this->xy2d = $xy2d;
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,3 @@
# Curve25519 Data Structures
These are PHP implementation of the [structs used in the ref10 curve25519 code](https://github.com/jedisct1/libsodium/blob/master/src/libsodium/include/sodium/private/curve25519_ref10.h).
+573
View File
@@ -0,0 +1,573 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_Ed25519', false)) {
return;
}
if (!class_exists('ParagonIE_Sodium_Core_Curve25519', false)) {
require_once dirname(__FILE__) . '/Curve25519.php';
}
/**
* Class ParagonIE_Sodium_Core_Ed25519
*/
abstract class ParagonIE_Sodium_Core_Ed25519 extends ParagonIE_Sodium_Core_Curve25519
{
const KEYPAIR_BYTES = 96;
const SEED_BYTES = 32;
const SCALAR_BYTES = 32;
/**
* @internal You should not use this directly from another application
*
* @return string (96 bytes)
* @throws Exception
* @throws SodiumException
* @throws TypeError
*/
public static function keypair(): string
{
$seed = random_bytes(self::SEED_BYTES);
$pk = '';
$sk = '';
self::seed_keypair($pk, $sk, $seed);
return $sk . $pk;
}
/**
* @internal You should not use this directly from another application
*
* @param string $pk
* @param string $sk
* @param string $seed
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function seed_keypair(
string &$pk,
string &$sk,
#[SensitiveParameter]
string $seed
): string {
if (self::strlen($seed) !== self::SEED_BYTES) {
throw new SodiumException('crypto_sign keypair seed must be CRYPTO_SIGN_SEEDBYTES bytes long');
}
$pk = self::publickey_from_secretkey($seed);
$sk = $seed . $pk;
return $sk;
}
/**
* @internal You should not use this directly from another application
*
* @param string $keypair
* @return string
* @throws TypeError
*/
public static function secretkey(
#[SensitiveParameter]
string $keypair
): string {
if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
throw new RangeException('crypto_sign keypair must be 96 bytes long');
}
return self::substr($keypair, 0, 64);
}
/**
* @internal You should not use this directly from another application
*
* @param string $keypair
* @return string
* @throws TypeError
*/
public static function publickey(
#[SensitiveParameter]
string $keypair
): string {
if (self::strlen($keypair) !== self::KEYPAIR_BYTES) {
throw new RangeException('crypto_sign keypair must be 96 bytes long');
}
return self::substr($keypair, 64, 32);
}
/**
* @internal You should not use this directly from another application
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function publickey_from_secretkey(
#[SensitiveParameter]
string $sk
): string {
/** @var string $sk */
$sk = hash('sha512', self::substr($sk, 0, 32), true);
$sk[0] = self::intToChr(
self::chrToInt($sk[0]) & 248
);
$sk[31] = self::intToChr(
(self::chrToInt($sk[31]) & 63) | 64
);
return self::sk_to_pk($sk);
}
/**
* Returns TRUE if $A represents a point on the order of the Edwards25519 prime order subgroup.
* Returns FALSE if $A is on a different subgroup.
*
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
* @return bool
*/
public static function is_on_main_subgroup(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A): bool
{
$p1 = self::ge_mul_l($A);
$t = self::fe_sub($p1->Y, $p1->Z);
return self::fe_isnonzero($p1->X) && self::fe_isnonzero($t);
}
/**
* @param string $pk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function pk_to_curve25519(
string $pk
): string {
if (self::strlen($pk) !== 32) {
throw new SodiumException('Argument 1 must be CRYPTO_SIGN_PUBLICKEYBYTES bytes');
}
if (self::small_order($pk)) {
throw new SodiumException('Public key is on a small order');
}
$A = self::ge_frombytes_negate_vartime(self::substr($pk, 0, 32));
// check that A * L == identity point
if (!self::is_on_main_subgroup($A)) {
throw new SodiumException('Public key is not on a member of the main subgroup');
}
$one_minux_y = self::fe_invert(
self::fe_sub(
self::fe_1(),
$A->Y
)
);
$x = self::fe_mul(
self::fe_add(self::fe_1(), $A->Y),
$one_minux_y
);
return self::fe_tobytes($x);
}
/**
* @internal You should not use this directly from another application
*
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sk_to_pk(
#[SensitiveParameter]
string $sk
): string {
return self::ge_p3_tobytes(
self::ge_scalarmult_base(
self::substr($sk, 0, 32)
)
);
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign(
string $message,
#[SensitiveParameter]
string $sk
): string {
$signature = self::sign_detached($message, $sk);
return $signature . $message;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message A signed message
* @param string $pk Public key
* @return string Message (without signature)
* @throws SodiumException
* @throws TypeError
*/
public static function sign_open(
string $message,
string $pk
): string {
$signature = self::substr($message, 0, 64);
/** @var string $message */
$message = self::substr($message, 64);
if (self::verify_detached($signature, $message, $pk)) {
return $message;
}
throw new SodiumException('Invalid signature');
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $sk
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function sign_detached(
string $message,
#[SensitiveParameter]
string $sk
): string {
if (self::strlen($sk) !== 64) {
throw new SodiumException('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.');
}
$az = hash('sha512', self::substr($sk, 0, 32), true);
$az[0] = self::intToChr(self::chrToInt($az[0]) & 248);
$az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64);
$hs = hash_init('sha512');
hash_update($hs, self::substr($az, 32, 32));
hash_update($hs, $message);
$nonceHash = hash_final($hs, true);
$pk = self::substr($sk, 32, 32);
$nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash, 32);
$sig = self::ge_p3_tobytes(
self::ge_scalarmult_base($nonce)
);
$hs = hash_init('sha512');
hash_update($hs, self::substr($sig, 0, 32));
hash_update($hs, self::substr($pk, 0, 32));
hash_update($hs, $message);
$hramHash = hash_final($hs, true);
$hram = self::sc_reduce($hramHash);
$sigAfter = self::sc_muladd($hram, $az, $nonce);
$sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32);
try {
ParagonIE_Sodium_Compat::memzero($az);
} catch (SodiumException) {
$az = null;
}
return $sig;
}
/**
* @internal You should not use this directly from another application
*
* @param string $sig
* @param string $message
* @param string $pk
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function verify_detached(
string $sig,
string $message,
string $pk
): bool {
if (self::strlen($sig) !== 64) {
throw new SodiumException('Argument 1 must be CRYPTO_SIGN_BYTES long');
}
if (self::strlen($pk) !== 32) {
throw new SodiumException('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES long');
}
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)) {
throw new SodiumException('Signature is on too small of an order');
}
if ((self::chrToInt($sig[63]) & 224) !== 0) {
throw new SodiumException('Invalid signature');
}
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= self::chrToInt($pk[$i]);
}
if ($d === 0) {
throw new SodiumException('All zero public key');
}
/* The original value of ParagonIE_Sodium_Compat::$fastMult */
$orig = ParagonIE_Sodium_Compat::$fastMult;
// Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification.
ParagonIE_Sodium_Compat::$fastMult = true;
$A = self::ge_frombytes_negate_vartime($pk);
if (!self::is_on_main_subgroup($A)) {
throw new SodiumException('Public key is not on main subgroup');
}
$hDigest = hash(
'sha512',
self::substr($sig, 0, 32) .
self::substr($pk, 0, 32) .
$message,
true
);
$h = self::sc_reduce($hDigest) . self::substr($hDigest, 32);
$R = self::ge_double_scalarmult_vartime(
$h,
$A,
self::substr($sig, 32)
);
$rcheck = self::ge_tobytes($R);
// Reset ParagonIE_Sodium_Compat::$fastMult to what it was before.
ParagonIE_Sodium_Compat::$fastMult = $orig;
return self::verify_32($rcheck, self::substr($sig, 0, 32));
}
/**
* @internal You should not use this directly from another application
*
* @param string $S
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function check_S_lt_L(string $S): bool
{
if (self::strlen($S) < 32) {
throw new SodiumException('Signature must be 32 bytes');
}
$L = array(
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10
);
$c = 0;
$n = 1;
$i = 32;
/** @var array<int, int> $L */
do {
--$i;
$x = self::chrToInt($S[$i]);
$c |= (
(($x - $L[$i]) >> 8) & $n
);
$n &= (
(($x ^ $L[$i]) - 1) >> 8
);
} while ($i !== 0);
return $c === 0;
}
/**
* @param string $R
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function small_order(string $R): bool
{
/** @var array<int, array<int, int>> $blocklist */
$blocklist = array(
/* 0 (order 4) */
array(
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
),
/* 1 (order 1) */
array(
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
),
/* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */
array(
0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05
),
/* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */
array(
0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a
),
/* p-1 (order 2) */
array(
0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0,
0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0,
0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39,
0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85
),
/* p (order 4) */
array(
0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f,
0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f,
0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6,
0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa
),
/* p+1 (order 1) */
array(
0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */
array(
0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/* p+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */
array(
0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f
),
/* 2p-1 (order 2) */
array(
0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
),
/* 2p (order 4) */
array(
0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
),
/* 2p+1 (order 1) */
array(
0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
)
);
$countBlocklist = count($blocklist);
for ($i = 0; $i < $countBlocklist; ++$i) {
$c = 0;
for ($j = 0; $j < 32; ++$j) {
$c |= self::chrToInt($R[$j]) ^ $blocklist[$i][$j];
}
if ($c === 0) {
return true;
}
}
return false;
}
/**
* @param string $s
* @return string
* @throws SodiumException
*/
public static function scalar_complement(
#[SensitiveParameter]
string $s
): string {
$t_ = self::L . str_repeat("\x00", 32);
sodium_increment($t_);
$s_ = $s . str_repeat("\x00", 32);
ParagonIE_Sodium_Compat::sub($t_, $s_);
return self::sc_reduce($t_);
}
/**
* @return string
* @throws SodiumException
*/
public static function scalar_random(): string
{
do {
$r = ParagonIE_Sodium_Compat::randombytes_buf(self::SCALAR_BYTES);
$r[self::SCALAR_BYTES - 1] = self::intToChr(
self::chrToInt($r[self::SCALAR_BYTES - 1]) & 0x1f
);
} while (
!self::check_S_lt_L($r) || ParagonIE_Sodium_Compat::is_zero($r)
);
return $r;
}
/**
* @param string $s
* @return string
* @throws SodiumException
*/
public static function scalar_negate(
#[SensitiveParameter]
string $s
): string {
$t_ = self::L . str_repeat("\x00", 32) ;
$s_ = $s . str_repeat("\x00", 32) ;
ParagonIE_Sodium_Compat::sub($t_, $s_);
return self::sc_reduce($t_);
}
/**
* @param string $a
* @param string $b
* @return string
* @throws SodiumException
*/
public static function scalar_add(
#[SensitiveParameter]
string $a,
#[SensitiveParameter]
string $b
): string {
$a_ = $a . str_repeat("\x00", 32);
$b_ = $b . str_repeat("\x00", 32);
ParagonIE_Sodium_Compat::add($a_, $b_);
return self::sc_reduce($a_);
}
/**
* @param string $x
* @param string $y
* @return string
* @throws SodiumException
*/
public static function scalar_sub(
#[SensitiveParameter]
string $x,
#[SensitiveParameter]
string $y
): string {
return self::scalar_add($x, self::scalar_negate($y));
}
}
+106
View File
@@ -0,0 +1,106 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_HChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_HChaCha20
*/
class ParagonIE_Sodium_Core_HChaCha20 extends ParagonIE_Sodium_Core_ChaCha20
{
/**
* @param string $in
* @param string $key
* @param string|null $c
* @return string
*
* @throws SodiumException
*/
public static function hChaCha20(
string $in,
#[SensitiveParameter]
string $key,
?string $c = null
): string {
if (self::strlen($in) !== 16) {
throw new SodiumException('Argument 1 must be 16 bytes');
}
if (self::strlen($key) !== 32) {
throw new SodiumException('Argument 2 must be 32 bytes');
}
$ctx = array();
if ($c === null) {
$ctx[0] = 0x61707865;
$ctx[1] = 0x3320646e;
$ctx[2] = 0x79622d32;
$ctx[3] = 0x6b206574;
} else {
$ctx[0] = self::load_4(self::substr($c, 0, 4));
$ctx[1] = self::load_4(self::substr($c, 4, 4));
$ctx[2] = self::load_4(self::substr($c, 8, 4));
$ctx[3] = self::load_4(self::substr($c, 12, 4));
}
$ctx[4] = self::load_4(self::substr($key, 0, 4));
$ctx[5] = self::load_4(self::substr($key, 4, 4));
$ctx[6] = self::load_4(self::substr($key, 8, 4));
$ctx[7] = self::load_4(self::substr($key, 12, 4));
$ctx[8] = self::load_4(self::substr($key, 16, 4));
$ctx[9] = self::load_4(self::substr($key, 20, 4));
$ctx[10] = self::load_4(self::substr($key, 24, 4));
$ctx[11] = self::load_4(self::substr($key, 28, 4));
$ctx[12] = self::load_4(self::substr($in, 0, 4));
$ctx[13] = self::load_4(self::substr($in, 4, 4));
$ctx[14] = self::load_4(self::substr($in, 8, 4));
$ctx[15] = self::load_4(self::substr($in, 12, 4));
return self::hChaCha20Bytes($ctx);
}
/**
* @param array $ctx
* @return string
* @throws TypeError
*/
protected static function hChaCha20Bytes(array $ctx): string
{
$x0 = (int) $ctx[0];
$x1 = (int) $ctx[1];
$x2 = (int) $ctx[2];
$x3 = (int) $ctx[3];
$x4 = (int) $ctx[4];
$x5 = (int) $ctx[5];
$x6 = (int) $ctx[6];
$x7 = (int) $ctx[7];
$x8 = (int) $ctx[8];
$x9 = (int) $ctx[9];
$x10 = (int) $ctx[10];
$x11 = (int) $ctx[11];
$x12 = (int) $ctx[12];
$x13 = (int) $ctx[13];
$x14 = (int) $ctx[14];
$x15 = (int) $ctx[15];
for ($i = 0; $i < 10; ++$i) {
[$x0, $x4, $x8, $x12] = self::quarterRound($x0, $x4, $x8, $x12);
[$x1, $x5, $x9, $x13] = self::quarterRound($x1, $x5, $x9, $x13);
[$x2, $x6, $x10, $x14] = self::quarterRound($x2, $x6, $x10, $x14);
[$x3, $x7, $x11, $x15] = self::quarterRound($x3, $x7, $x11, $x15);
[$x0, $x5, $x10, $x15] = self::quarterRound($x0, $x5, $x10, $x15);
[$x1, $x6, $x11, $x12] = self::quarterRound($x1, $x6, $x11, $x12);
[$x2, $x7, $x8, $x13] = self::quarterRound($x2, $x7, $x8, $x13);
[$x3, $x4, $x9, $x14] = self::quarterRound($x3, $x4, $x9, $x14);
}
return self::store32_le(($x0 & 0xffffffff)) .
self::store32_le(($x1 & 0xffffffff)) .
self::store32_le(($x2 & 0xffffffff)) .
self::store32_le(($x3 & 0xffffffff)) .
self::store32_le(($x12 & 0xffffffff)) .
self::store32_le(($x13 & 0xffffffff)) .
self::store32_le(($x14 & 0xffffffff)) .
self::store32_le(($x15 & 0xffffffff));
}
}
+101
View File
@@ -0,0 +1,101 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_HSalsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_HSalsa20
*/
abstract class ParagonIE_Sodium_Core_HSalsa20 extends ParagonIE_Sodium_Core_Salsa20
{
/**
* Calculate an hsalsa20 hash of a single block
*
* HSalsa20 doesn't have a counter and will never be used for more than
* one block (used to derive a subkey for xsalsa20).
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $k
* @param string|null $c
* @return string
* @throws TypeError
*/
public static function hsalsa20(
string $in,
#[SensitiveParameter]
string $k,
?string $c = null
): string {
if ($c === null) {
$x0 = 0x61707865;
$x5 = 0x3320646e;
$x10 = 0x79622d32;
$x15 = 0x6b206574;
} else {
$x0 = self::load_4(self::substr($c, 0, 4));
$x5 = self::load_4(self::substr($c, 4, 4));
$x10 = self::load_4(self::substr($c, 8, 4));
$x15 = self::load_4(self::substr($c, 12, 4));
}
$x1 = self::load_4(self::substr($k, 0, 4));
$x2 = self::load_4(self::substr($k, 4, 4));
$x3 = self::load_4(self::substr($k, 8, 4));
$x4 = self::load_4(self::substr($k, 12, 4));
$x11 = self::load_4(self::substr($k, 16, 4));
$x12 = self::load_4(self::substr($k, 20, 4));
$x13 = self::load_4(self::substr($k, 24, 4));
$x14 = self::load_4(self::substr($k, 28, 4));
$x6 = self::load_4(self::substr($in, 0, 4));
$x7 = self::load_4(self::substr($in, 4, 4));
$x8 = self::load_4(self::substr($in, 8, 4));
$x9 = self::load_4(self::substr($in, 12, 4));
for ($i = self::ROUNDS; $i > 0; $i -= 2) {
$x4 ^= self::rotate($x0 + $x12, 7);
$x8 ^= self::rotate($x4 + $x0, 9);
$x12 ^= self::rotate($x8 + $x4, 13);
$x0 ^= self::rotate($x12 + $x8, 18);
$x9 ^= self::rotate($x5 + $x1, 7);
$x13 ^= self::rotate($x9 + $x5, 9);
$x1 ^= self::rotate($x13 + $x9, 13);
$x5 ^= self::rotate($x1 + $x13, 18);
$x14 ^= self::rotate($x10 + $x6, 7);
$x2 ^= self::rotate($x14 + $x10, 9);
$x6 ^= self::rotate($x2 + $x14, 13);
$x10 ^= self::rotate($x6 + $x2, 18);
$x3 ^= self::rotate($x15 + $x11, 7);
$x7 ^= self::rotate($x3 + $x15, 9);
$x11 ^= self::rotate($x7 + $x3, 13);
$x15 ^= self::rotate($x11 + $x7, 18);
$x1 ^= self::rotate($x0 + $x3, 7);
$x2 ^= self::rotate($x1 + $x0, 9);
$x3 ^= self::rotate($x2 + $x1, 13);
$x0 ^= self::rotate($x3 + $x2, 18);
$x6 ^= self::rotate($x5 + $x4, 7);
$x7 ^= self::rotate($x6 + $x5, 9);
$x4 ^= self::rotate($x7 + $x6, 13);
$x5 ^= self::rotate($x4 + $x7, 18);
$x11 ^= self::rotate($x10 + $x9, 7);
$x8 ^= self::rotate($x11 + $x10, 9);
$x9 ^= self::rotate($x8 + $x11, 13);
$x10 ^= self::rotate($x9 + $x8, 18);
$x12 ^= self::rotate($x15 + $x14, 7);
$x13 ^= self::rotate($x12 + $x15, 9);
$x14 ^= self::rotate($x13 + $x12, 13);
$x15 ^= self::rotate($x14 + $x13, 18);
}
return self::store32_le($x0) .
self::store32_le($x5) .
self::store32_le($x10) .
self::store32_le($x15) .
self::store32_le($x6) .
self::store32_le($x7) .
self::store32_le($x8) .
self::store32_le($x9);
}
}
+71
View File
@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_Poly1305', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Poly1305
*/
abstract class ParagonIE_Sodium_Core_Poly1305 extends ParagonIE_Sodium_Core_Util
{
const BLOCK_SIZE = 16;
/**
* @internal You should not use this directly from another application
*
* @param string $m
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function onetimeauth(
string $m,
#[SensitiveParameter]
string $key
): string {
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Key must be 32 bytes long.'
);
}
$state = new ParagonIE_Sodium_Core_Poly1305_State(
self::substr($key, 0, 32)
);
return $state
->update($m)
->finish();
}
/**
* @internal You should not use this directly from another application
*
* @param string $mac
* @param string $m
* @param string $key
* @return bool
* @throws SodiumException
* @throws TypeError
*/
public static function onetimeauth_verify(
string $mac,
string $m,
#[SensitiveParameter]
string $key
): bool {
if (self::strlen($key) !== 32) {
throw new InvalidArgumentException(
'Key must be 32 bytes long.'
);
}
$state = new ParagonIE_Sodium_Core_Poly1305_State(
self::substr($key, 0, 32)
);
$calc = $state
->update($m)
->finish();
return self::verify_16($calc, $mac);
}
}
@@ -0,0 +1,424 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_Poly1305_State', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Poly1305_State
*/
class ParagonIE_Sodium_Core_Poly1305_State extends ParagonIE_Sodium_Core_Util
{
/**
* @var array<int, int>
*/
protected array $buffer = array();
protected bool $final = false;
/**
* @var array<int, int>
*/
public array $h;
protected int $leftover = 0;
/**
* @var int[]
*/
public array $r;
/**
* @var int[]
*/
public array $pad;
/**
* ParagonIE_Sodium_Core_Poly1305_State constructor.
*
* @internal You should not use this directly from another application
*
* @param string $key
* @throws InvalidArgumentException
* @throws TypeError
*/
public function __construct(string $key = '')
{
if (self::strlen($key) < 32) {
throw new InvalidArgumentException(
'Poly1305 requires a 32-byte key'
);
}
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
$this->r = array(
((self::load_4(self::substr($key, 0, 4))) & 0x3ffffff),
((self::load_4(self::substr($key, 3, 4)) >> 2) & 0x3ffff03),
((self::load_4(self::substr($key, 6, 4)) >> 4) & 0x3ffc0ff),
((self::load_4(self::substr($key, 9, 4)) >> 6) & 0x3f03fff),
((self::load_4(self::substr($key, 12, 4)) >> 8) & 0x00fffff)
);
/* h = 0 */
$this->h = array(0, 0, 0, 0, 0);
/* save pad for later */
$this->pad = array(
self::load_4(self::substr($key, 16, 4)),
self::load_4(self::substr($key, 20, 4)),
self::load_4(self::substr($key, 24, 4)),
self::load_4(self::substr($key, 28, 4)),
);
$this->leftover = 0;
$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
*
* @param string $message
* @return self
* @throws SodiumException
* @throws TypeError
*/
public function update(string $message = ''): self
{
$bytes = self::strlen($message);
if ($bytes < 1) {
return $this;
}
/* handle leftover */
if ($this->leftover) {
$want = ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - $this->leftover;
if ($want > $bytes) {
$want = $bytes;
}
for ($i = 0; $i < $want; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
// We snip off the leftmost bytes.
$message = self::substr($message, $want);
$bytes = self::strlen($message);
$this->leftover += $want;
if ($this->leftover < ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
// We still don't have enough to run $this->blocks()
return $this;
}
$this->blocks(
self::intArrayToString($this->buffer),
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
);
$this->leftover = 0;
}
/* process full blocks */
if ($bytes >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
/** @var int $want */
$want = $bytes & ~(ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - 1);
if ($want >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
$block = self::substr($message, 0, $want);
if (self::strlen($block) >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
$this->blocks($block, $want);
$message = self::substr($message, $want);
$bytes = self::strlen($message);
}
}
}
/* store leftover */
if ($bytes) {
for ($i = 0; $i < $bytes; ++$i) {
$mi = self::chrToInt($message[$i]);
$this->buffer[$this->leftover + $i] = $mi;
}
$this->leftover = $this->leftover + $bytes;
}
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param int $bytes
* @return static
* @throws TypeError
*/
public function blocks(string $message, int $bytes): static
{
if (self::strlen($message) < 16) {
$message = str_pad($message, 16, "\x00");
}
$hibit = $this->final ? 0 : 1 << 24; /* 1 << 128 */
$r0 = $this->r[0];
$r1 = $this->r[1];
$r2 = $this->r[2];
$r3 = $this->r[3];
$r4 = $this->r[4];
$s1 = self::mul($r1, 5, 3);
$s2 = self::mul($r2, 5, 3);
$s3 = self::mul($r3, 5, 3);
$s4 = self::mul($r4, 5, 3);
$h0 = $this->h[0];
$h1 = $this->h[1];
$h2 = $this->h[2];
$h3 = $this->h[3];
$h4 = $this->h[4];
while ($bytes >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) {
/* h += m[i] */
$h0 += self::load_4(self::substr($message, 0, 4)) & 0x3ffffff;
$h1 += (self::load_4(self::substr($message, 3, 4)) >> 2) & 0x3ffffff;
$h2 += (self::load_4(self::substr($message, 6, 4)) >> 4) & 0x3ffffff;
$h3 += (self::load_4(self::substr($message, 9, 4)) >> 6) & 0x3ffffff;
$h4 += (self::load_4(self::substr($message, 12, 4)) >> 8) | $hibit;
/* h *= r */
$d0 = (
self::mul($h0, $r0, 27) +
self::mul($s4, $h1, 27) +
self::mul($s3, $h2, 27) +
self::mul($s2, $h3, 27) +
self::mul($s1, $h4, 27)
);
$d1 = (
self::mul($h0, $r1, 27) +
self::mul($h1, $r0, 27) +
self::mul($s4, $h2, 27) +
self::mul($s3, $h3, 27) +
self::mul($s2, $h4, 27)
);
$d2 = (
self::mul($h0, $r2, 27) +
self::mul($h1, $r1, 27) +
self::mul($h2, $r0, 27) +
self::mul($s4, $h3, 27) +
self::mul($s3, $h4, 27)
);
$d3 = (
self::mul($h0, $r3, 27) +
self::mul($h1, $r2, 27) +
self::mul($h2, $r1, 27) +
self::mul($h3, $r0, 27) +
self::mul($s4, $h4, 27)
);
$d4 = (
self::mul($h0, $r4, 27) +
self::mul($h1, $r3, 27) +
self::mul($h2, $r2, 27) +
self::mul($h3, $r1, 27) +
self::mul($h4, $r0, 27)
);
/* (partial) h %= p */
$c = $d0 >> 26;
$h0 = $d0 & 0x3ffffff;
$d1 += $c;
$c = $d1 >> 26;
$h1 = $d1 & 0x3ffffff;
$d2 += $c;
$c = $d2 >> 26;
$h2 = $d2 & 0x3ffffff;
$d3 += $c;
$c = $d3 >> 26;
$h3 = $d3 & 0x3ffffff;
$d4 += $c;
$c = $d4 >> 26;
$h4 = $d4 & 0x3ffffff;
$h0 += self::mul($c, 5, 3);
$c = $h0 >> 26;
$h0 &= 0x3ffffff;
$h1 += $c;
// Chop off the left 32 bytes.
$message = self::substr(
$message,
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
);
$bytes -= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE;
}
$this->h = array(
($h0 & 0xffffffff),
($h1 & 0xffffffff),
($h2 & 0xffffffff),
($h3 & 0xffffffff),
($h4 & 0xffffffff)
);
return $this;
}
/**
* @internal You should not use this directly from another application
*
* @return string
* @throws TypeError
*/
public function finish(): string
{
/* process the remaining block */
if ($this->leftover) {
$i = $this->leftover;
$this->buffer[$i++] = 1;
for (; $i < ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE; ++$i) {
$this->buffer[$i] = 0;
}
$this->final = true;
$this->blocks(
self::substr(
self::intArrayToString($this->buffer),
0,
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
),
ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
);
}
$h0 = $this->h[0];
$h1 = $this->h[1];
$h2 = $this->h[2];
$h3 = $this->h[3];
$h4 = $this->h[4];
/** @var int $c */
$c = $h1 >> 26;
/** @var int $h1 */
$h1 &= 0x3ffffff;
/** @var int $h2 */
$h2 += $c;
/** @var int $c */
$c = $h2 >> 26;
/** @var int $h2 */
$h2 &= 0x3ffffff;
$h3 += $c;
/** @var int $c */
$c = $h3 >> 26;
$h3 &= 0x3ffffff;
$h4 += $c;
/** @var int $c */
$c = $h4 >> 26;
$h4 &= 0x3ffffff;
/** @var int $h0 */
$h0 += self::mul($c, 5, 3);
/** @var int $c */
$c = $h0 >> 26;
/** @var int $h0 */
$h0 &= 0x3ffffff;
/** @var int $h1 */
$h1 += $c;
/* compute h + -p */
/** @var int $g0 */
$g0 = $h0 + 5;
/** @var int $c */
$c = $g0 >> 26;
/** @var int $g0 */
$g0 &= 0x3ffffff;
/** @var int $g1 */
$g1 = $h1 + $c;
/** @var int $c */
$c = $g1 >> 26;
$g1 &= 0x3ffffff;
/** @var int $g2 */
$g2 = $h2 + $c;
/** @var int $c */
$c = $g2 >> 26;
/** @var int $g2 */
$g2 &= 0x3ffffff;
/** @var int $g3 */
$g3 = $h3 + $c;
/** @var int $c */
$c = $g3 >> 26;
/** @var int $g3 */
$g3 &= 0x3ffffff;
/** @var int $g4 */
$g4 = ($h4 + $c - (1 << 26)) & 0xffffffff;
/* select h if h < p, or h + -p if h >= p */
/** @var int $mask */
$mask = ($g4 >> 31) - 1;
$g0 &= $mask;
$g1 &= $mask;
$g2 &= $mask;
$g3 &= $mask;
$g4 &= $mask;
/** @var int $mask */
$mask = ~$mask & 0xffffffff;
/** @var int $h0 */
$h0 = ($h0 & $mask) | $g0;
/** @var int $h1 */
$h1 = ($h1 & $mask) | $g1;
/** @var int $h2 */
$h2 = ($h2 & $mask) | $g2;
/** @var int $h3 */
$h3 = ($h3 & $mask) | $g3;
/** @var int $h4 */
$h4 = ($h4 & $mask) | $g4;
/* h = h % (2^128) */
/** @var int $h0 */
$h0 = (($h0) | ($h1 << 26)) & 0xffffffff;
/** @var int $h1 */
$h1 = (($h1 >> 6) | ($h2 << 20)) & 0xffffffff;
/** @var int $h2 */
$h2 = (($h2 >> 12) | ($h3 << 14)) & 0xffffffff;
/** @var int $h3 */
$h3 = (($h3 >> 18) | ($h4 << 8)) & 0xffffffff;
/* mac = (h + pad) % (2^128) */
$f = ($h0 + $this->pad[0]);
$h0 = $f;
$f = ($h1 + $this->pad[1] + ($f >> 32));
$h1 = $f;
$f = ($h2 + $this->pad[2] + ($f >> 32));
$h2 = $f;
$f = ($h3 + $this->pad[3] + ($f >> 32));
$h3 = $f;
return self::store32_le($h0 & 0xffffffff) .
self::store32_le($h1 & 0xffffffff) .
self::store32_le($h2 & 0xffffffff) .
self::store32_le($h3 & 0xffffffff);
}
}
+764
View File
@@ -0,0 +1,764 @@
<?php
declare(strict_types=1);
/**
* Class ParagonIE_Sodium_Core_Ristretto255
*/
class ParagonIE_Sodium_Core_Ristretto255 extends ParagonIE_Sodium_Core_Ed25519
{
const crypto_core_ristretto255_HASHBYTES = 64;
const HASH_SC_L = 48;
const CORE_H2C_SHA256 = 1;
const CORE_H2C_SHA512 = 2;
/**
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param int $b
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_cneg(
ParagonIE_Sodium_Core_Curve25519_Fe $f,
int $b
): ParagonIE_Sodium_Core_Curve25519_Fe {
$negf = self::fe_neg($f);
return self::fe_cmov($f, $negf, $b);
}
/**
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
* @throws SodiumException
*/
public static function fe_abs(
ParagonIE_Sodium_Core_Curve25519_Fe $f
): ParagonIE_Sodium_Core_Curve25519_Fe {
return self::fe_cneg($f, self::fe_isnegative($f));
}
/**
* Returns 0 if this field element results in all NUL bytes.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return int
* @throws SodiumException
*/
public static function fe_iszero(ParagonIE_Sodium_Core_Curve25519_Fe $f): int
{
static $zero;
if ($zero === null) {
$zero = str_repeat("\x00", 32);
}
/** @var string $zero */
$str = self::fe_tobytes($f);
$d = 0;
for ($i = 0; $i < 32; ++$i) {
$d |= self::chrToInt($str[$i]);
}
return (($d - 1) >> 31) & 1;
}
/**
* @param ParagonIE_Sodium_Core_Curve25519_Fe $u
* @param ParagonIE_Sodium_Core_Curve25519_Fe $v
* @return array{x: ParagonIE_Sodium_Core_Curve25519_Fe, nonsquare: int}
*
* @throws SodiumException
*/
public static function ristretto255_sqrt_ratio_m1(
ParagonIE_Sodium_Core_Curve25519_Fe $u,
ParagonIE_Sodium_Core_Curve25519_Fe $v
): array {
$sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::SQRTM1);
$v3 = self::fe_mul(
self::fe_sq($v),
$v
); /* v3 = v^3 */
$x = self::fe_mul(
self::fe_mul(
self::fe_sq($v3),
$u
),
$v
); /* x = uv^7 */
$x = self::fe_mul(
self::fe_mul(
self::fe_pow22523($x), /* x = (uv^7)^((q-5)/8) */
$v3
),
$u
); /* x = uv^3(uv^7)^((q-5)/8) */
$vxx = self::fe_mul(
self::fe_sq($x),
$v
); /* vx^2 */
$m_root_check = self::fe_sub($vxx, $u); /* vx^2-u */
$p_root_check = self::fe_add($vxx, $u); /* vx^2+u */
$f_root_check = self::fe_mul($u, $sqrtm1); /* u*sqrt(-1) */
$f_root_check = self::fe_add($vxx, $f_root_check); /* vx^2+u*sqrt(-1) */
$has_m_root = self::fe_iszero($m_root_check);
$has_p_root = self::fe_iszero($p_root_check);
$has_f_root = self::fe_iszero($f_root_check);
$x_sqrtm1 = self::fe_mul($x, $sqrtm1); /* x*sqrt(-1) */
$x = self::fe_abs(
self::fe_cmov($x, $x_sqrtm1, $has_p_root | $has_f_root)
);
return array(
'x' => $x,
'nonsquare' => $has_m_root | $has_p_root
);
}
/**
* @param string $s
* @return int
* @throws SodiumException
*/
public static function ristretto255_point_is_canonical(
#[SensitiveParameter]
string $s
): int {
$c = (self::chrToInt($s[31]) & 0x7f) ^ 0x7f;
for ($i = 30; $i > 0; --$i) {
$c |= self::chrToInt($s[$i]) ^ 0xff;
}
$c = ($c - 1) >> 8;
$d = (0xed - 1 - self::chrToInt($s[0])) >> 8;
$e = self::chrToInt($s[31]) >> 7;
return 1 - ((($c & $d) | $e | self::chrToInt($s[0])) & 1);
}
/**
* @param string $s
* @param bool $skipCanonicalCheck
* @return array{h: ParagonIE_Sodium_Core_Curve25519_Ge_P3, res: int}
* @throws SodiumException
*/
public static function ristretto255_frombytes(
#[SensitiveParameter]
string $s,
bool $skipCanonicalCheck = false
): array {
if (!$skipCanonicalCheck) {
if (!self::ristretto255_point_is_canonical($s)) {
throw new SodiumException('S is not canonical');
}
}
$s_ = self::fe_frombytes($s);
$ss = self::fe_sq($s_); /* ss = s^2 */
$u1 = self::fe_sub(self::fe_1(), $ss); /* u1 = 1-ss */
$u1u1 = self::fe_sq($u1); /* u1u1 = u1^2 */
$u2 = self::fe_add(self::fe_1(), $ss); /* u2 = 1+ss */
$u2u2 = self::fe_sq($u2); /* u2u2 = u2^2 */
$v = self::fe_mul(
ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::D),
$u1u1
); /* v = d*u1^2 */
$v = self::fe_neg($v); /* v = -d*u1^2 */
$v = self::fe_sub($v, $u2u2); /* v = -(d*u1^2)-u2^2 */
$v_u2u2 = self::fe_mul($v, $u2u2); /* v_u2u2 = v*u2^2 */
$one = self::fe_1();
$result = self::ristretto255_sqrt_ratio_m1($one, $v_u2u2);
$inv_sqrt = $result['x'];
$notsquare = $result['nonsquare'];
$h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3();
$h->X = self::fe_mul($inv_sqrt, $u2);
$h->Y = self::fe_mul(self::fe_mul($inv_sqrt, $h->X), $v);
$h->X = self::fe_mul($h->X, $s_);
$h->X = self::fe_abs(
self::fe_add($h->X, $h->X)
);
$h->Y = self::fe_mul($u1, $h->Y);
$h->Z = self::fe_1();
$h->T = self::fe_mul($h->X, $h->Y);
$res = - ((1 - $notsquare) | self::fe_isnegative($h->T) | self::fe_iszero($h->Y));
return array('h' => $h, 'res' => $res);
}
/**
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h
* @return string
* @throws SodiumException
*/
public static function ristretto255_p3_tobytes(
ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h
): string {
$sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::SQRTM1);
$invsqrtamd = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::INVSQRTAMD);
$u1 = self::fe_add($h->Z, $h->Y); /* u1 = Z+Y */
$zmy = self::fe_sub($h->Z, $h->Y); /* zmy = Z-Y */
$u1 = self::fe_mul($u1, $zmy); /* u1 = (Z+Y)*(Z-Y) */
$u2 = self::fe_mul($h->X, $h->Y); /* u2 = X*Y */
$u1_u2u2 = self::fe_mul(self::fe_sq($u2), $u1); /* u1_u2u2 = u1*u2^2 */
$one = self::fe_1();
$result = self::ristretto255_sqrt_ratio_m1($one, $u1_u2u2);
$inv_sqrt = $result['x'];
$den1 = self::fe_mul($inv_sqrt, $u1); /* den1 = inv_sqrt*u1 */
$den2 = self::fe_mul($inv_sqrt, $u2); /* den2 = inv_sqrt*u2 */
$z_inv = self::fe_mul($h->T, self::fe_mul($den1, $den2)); /* z_inv = den1*den2*T */
$ix = self::fe_mul($h->X, $sqrtm1); /* ix = X*sqrt(-1) */
$iy = self::fe_mul($h->Y, $sqrtm1); /* iy = Y*sqrt(-1) */
$eden = self::fe_mul($den1, $invsqrtamd);
$t_z_inv = self::fe_mul($h->T, $z_inv); /* t_z_inv = T*z_inv */
$rotate = self::fe_isnegative($t_z_inv);
$x_ = clone $h->X;
$y_ = clone $h->Y;
$den_inv = clone $den2;
$x_ = self::fe_cmov($x_, $iy, $rotate);
$y_ = self::fe_cmov($y_, $ix, $rotate);
$den_inv = self::fe_cmov($den_inv, $eden, $rotate);
$x_z_inv = self::fe_mul($x_, $z_inv);
$y_ = self::fe_cneg($y_, self::fe_isnegative($x_z_inv));
return self::fe_tobytes(
self::fe_abs(
self::fe_mul(
$den_inv,
self::fe_sub($h->Z, $y_)
)
)
);
}
/**
* @param ParagonIE_Sodium_Core_Curve25519_Fe $t
* @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
*
* @throws SodiumException
*/
public static function ristretto255_elligator(
ParagonIE_Sodium_Core_Curve25519_Fe $t
): ParagonIE_Sodium_Core_Curve25519_Ge_P3 {
$sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::SQRTM1);
$onemsqd = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::ONEMSQD);
$d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::D);
$sqdmone = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::SQDMONE);
$sqrtadm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::SQRTADM1);
$one = self::fe_1();
$r = self::fe_mul($sqrtm1, self::fe_sq($t)); /* r = sqrt(-1)*t^2 */
$u = self::fe_mul(self::fe_add($r, $one), $onemsqd); /* u = (r+1)*(1-d^2) */
$c = self::fe_neg(self::fe_1()); /* c = -1 */
$rpd = self::fe_add($r, $d); /* rpd = r+d */
$v = self::fe_mul(
self::fe_sub(
$c,
self::fe_mul($r, $d)
),
$rpd
); /* v = (c-r*d)*(r+d) */
$result = self::ristretto255_sqrt_ratio_m1($u, $v);
$s = $result['x'];
$wasnt_square = 1 - $result['nonsquare'];
$s_prime = self::fe_neg(
self::fe_abs(
self::fe_mul($s, $t)
)
); /* s_prime = -|s*t| */
$s = self::fe_cmov($s, $s_prime, $wasnt_square);
$c = self::fe_cmov($c, $r, $wasnt_square);
$n = self::fe_sub(
self::fe_mul(
self::fe_mul(
self::fe_sub($r, $one),
$c
),
$sqdmone
),
$v
); /* n = c*(r-1)*(d-1)^2-v */
$w0 = self::fe_mul(
self::fe_add($s, $s),
$v
); /* w0 = 2s*v */
$w1 = self::fe_mul($n, $sqrtadm1); /* w1 = n*sqrt(ad-1) */
$ss = self::fe_sq($s); /* ss = s^2 */
$w2 = self::fe_sub($one, $ss); /* w2 = 1-s^2 */
$w3 = self::fe_add($one, $ss); /* w3 = 1+s^2 */
return new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
self::fe_mul($w0, $w3),
self::fe_mul($w2, $w1),
self::fe_mul($w1, $w3),
self::fe_mul($w0, $w2)
);
}
/**
* @param string $h
* @return string
* @throws SodiumException
*/
public static function ristretto255_from_hash(
#[SensitiveParameter]
string $h
): string {
if (self::strlen($h) !== 64) {
throw new SodiumException('Hash must be 64 bytes');
}
$r0 = self::fe_frombytes(self::substr($h, 0, 32));
$r1 = self::fe_frombytes(self::substr($h, 32, 32));
$p0 = self::ristretto255_elligator($r0);
$p1 = self::ristretto255_elligator($r1);
$p_p1p1 = self::ge_add(
$p0,
self::ge_p3_to_cached($p1)
);
return self::ristretto255_p3_tobytes(
self::ge_p1p1_to_p3($p_p1p1)
);
}
/**
* @param string $p
* @return int
* @throws SodiumException
*/
public static function is_valid_point(
#[SensitiveParameter]
string $p
): int {
$result = self::ristretto255_frombytes($p);
if ($result['res'] !== 0) {
return 0;
}
return 1;
}
/**
* @param string $p
* @param string $q
* @return string
* @throws SodiumException
*/
public static function ristretto255_add(
string $p,
string $q
): string {
$p_res = self::ristretto255_frombytes($p);
$q_res = self::ristretto255_frombytes($q);
if ($p_res['res'] !== 0 || $q_res['res'] !== 0) {
throw new SodiumException('Could not add points');
}
$p_p3 = $p_res['h'];
$q_p3 = $q_res['h'];
$q_cached = self::ge_p3_to_cached($q_p3);
$r_p1p1 = self::ge_add($p_p3, $q_cached);
$r_p3 = self::ge_p1p1_to_p3($r_p1p1);
return self::ristretto255_p3_tobytes($r_p3);
}
/**
* @param string $p
* @param string $q
* @return string
* @throws SodiumException
*/
public static function ristretto255_sub(
#[SensitiveParameter]
string $p,
#[SensitiveParameter]
string $q
): string {
$p_res = self::ristretto255_frombytes($p);
$q_res = self::ristretto255_frombytes($q);
if ($p_res['res'] !== 0 || $q_res['res'] !== 0) {
throw new SodiumException('Could not add points');
}
$p_p3 = $p_res['h'];
$q_p3 = $q_res['h'];
$q_cached = self::ge_p3_to_cached($q_p3);
$r_p1p1 = self::ge_sub($p_p3, $q_cached);
$r_p3 = self::ge_p1p1_to_p3($r_p1p1);
return self::ristretto255_p3_tobytes($r_p3);
}
/**
* @param int $hLen
* @param ?string $ctx
* @param string $msg
* @return string
* @throws SodiumException
*/
protected static function h2c_string_to_hash_sha256(
int $hLen,
#[SensitiveParameter]
?string $ctx,
#[SensitiveParameter]
string $msg
): string {
$h = array_fill(0, $hLen, 0);
if (is_null($ctx)) {
$ctx = '';
}
$ctx_len = self::strlen($ctx);
if ($hLen > 0xff) {
throw new SodiumException('Hash must be less than 256 bytes');
}
if ($ctx_len > 0xff) {
$st = hash_init('sha256');
hash_update($st, "H2C-OVERSIZE-DST-");
hash_update($st, $ctx);
$ctx = hash_final($st, true);
$ctx_len = 32;
}
$t = array(0, $hLen, 0);
$ux = str_repeat("\0", 64);
$st = hash_init('sha256');
hash_update($st, $ux);
hash_update($st, $msg);
hash_update($st, self::intArrayToString($t));
hash_update($st, $ctx);
hash_update($st, self::intToChr($ctx_len));
$u0 = hash_final($st, true);
for ($i = 0; $i < $hLen; $i += 64) {
$ux = self::xorStrings($ux, $u0);
++$t[2];
$st = hash_init('sha256');
hash_update($st, $ux);
hash_update($st, self::intToChr($t[2]));
hash_update($st, $ctx);
hash_update($st, self::intToChr($ctx_len));
$ux = hash_final($st, true);
$amount = min($hLen - $i, 64);
for ($j = 0; $j < $amount; ++$j) {
$h[$i + $j] = self::chrToInt($ux[$i]);
}
}
return self::intArrayToString(array_slice($h, 0, $hLen));
}
/**
* @param int $hLen
* @param ?string $ctx
* @param string $msg
* @return string
* @throws SodiumException
*/
protected static function h2c_string_to_hash_sha512(
int $hLen,
#[SensitiveParameter]
?string $ctx,
#[SensitiveParameter]
string $msg
): string {
$h = array_fill(0, $hLen, 0);
if (is_null($ctx)) {
$ctx = '';
}
$ctx_len = self::strlen($ctx);
if ($hLen > 0xff) {
throw new SodiumException('Hash must be less than 256 bytes');
}
if ($ctx_len > 0xff) {
$st = hash_init('sha256');
hash_update($st, "H2C-OVERSIZE-DST-");
hash_update($st, $ctx);
$ctx = hash_final($st, true);
$ctx_len = 32;
}
$t = array(0, $hLen, 0);
$ux = str_repeat("\0", 128);
$st = hash_init('sha512');
hash_update($st, $ux);
hash_update($st, $msg);
hash_update($st, self::intArrayToString($t));
hash_update($st, $ctx);
hash_update($st, self::intToChr($ctx_len));
$u0 = hash_final($st, true);
for ($i = 0; $i < $hLen; $i += 128) {
$ux = self::xorStrings($ux, $u0);
++$t[2];
$st = hash_init('sha512');
hash_update($st, $ux);
hash_update($st, self::intToChr($t[2]));
hash_update($st, $ctx);
hash_update($st, self::intToChr($ctx_len));
$ux = hash_final($st, true);
$amount = min($hLen - $i, 128);
for ($j = 0; $j < $amount; ++$j) {
$h[$i + $j] = self::chrToInt($ux[$i]);
}
}
return self::intArrayToString(array_slice($h, 0, $hLen));
}
/**
* @param int $hLen
* @param ?string $ctx
* @param string $msg
* @param int $hash_alg
* @return string
* @throws SodiumException
*/
public static function h2c_string_to_hash(
int $hLen,
#[SensitiveParameter]
?string $ctx,
#[SensitiveParameter]
string $msg,
int $hash_alg
): string {
return match ($hash_alg) {
self::CORE_H2C_SHA256 => self::h2c_string_to_hash_sha256($hLen, $ctx, $msg),
self::CORE_H2C_SHA512 => self::h2c_string_to_hash_sha512($hLen, $ctx, $msg),
default => throw new SodiumException('Invalid H2C hash algorithm'),
};
}
/**
* @param ?string $ctx
* @param string $msg
* @param int $hash_alg
* @return string
* @throws SodiumException
*/
protected static function _string_to_element(
#[SensitiveParameter]
?string $ctx,
#[SensitiveParameter]
string $msg,
int $hash_alg
): string {
return self::ristretto255_from_hash(
self::h2c_string_to_hash(self::crypto_core_ristretto255_HASHBYTES, $ctx, $msg, $hash_alg)
);
}
/**
* @return string
* @throws SodiumException
* @throws Exception
*/
public static function ristretto255_random(): string
{
return self::ristretto255_from_hash(
ParagonIE_Sodium_Compat::randombytes_buf(self::crypto_core_ristretto255_HASHBYTES)
);
}
/**
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_random(): string
{
return self::scalar_random();
}
/**
* @param string $s
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_complement(
#[SensitiveParameter]
string $s
): string {
return self::scalar_complement($s);
}
/**
* @param string $s
* @return string
*/
public static function ristretto255_scalar_invert(
#[SensitiveParameter]
string $s
): string {
return self::sc25519_invert($s);
}
/**
* @param string $s
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_negate(
#[SensitiveParameter]
string $s
): string {
return self::scalar_negate($s);
}
/**
* @param string $x
* @param string $y
* @return string
*
* @throws SodiumException
*/
public static function ristretto255_scalar_add(
#[SensitiveParameter]
string $x,
#[SensitiveParameter]
string $y
): string {
return self::scalar_add($x, $y);
}
/**
* @param string $x
* @param string $y
* @return string
*
* @throws SodiumException
*/
public static function ristretto255_scalar_sub(
#[SensitiveParameter]
string $x,
#[SensitiveParameter]
string $y
): string {
return self::scalar_sub($x, $y);
}
/**
* @param string $x
* @param string $y
* @return string
*/
public static function ristretto255_scalar_mul(
#[SensitiveParameter]
string $x,
#[SensitiveParameter]
string $y
): string {
return self::sc25519_mul($x, $y);
}
/**
* @param string $ctx
* @param string $msg
* @param int $hash_alg
* @return string
* @throws SodiumException
*/
public static function ristretto255_scalar_from_string(
#[SensitiveParameter]
string $ctx,
#[SensitiveParameter]
string $msg,
int $hash_alg
): string {
$h = array_fill(0, 64, 0);
$h_be = self::stringToIntArray(
self::h2c_string_to_hash(
self::HASH_SC_L, $ctx, $msg, $hash_alg
)
);
for ($i = 0; $i < self::HASH_SC_L; ++$i) {
$h[$i] = $h_be[self::HASH_SC_L - 1 - $i];
}
return self::ristretto255_scalar_reduce(self::intArrayToString($h));
}
/**
* @param string $s
* @return string
*/
public static function ristretto255_scalar_reduce(
#[SensitiveParameter]
string $s
): string {
return self::sc_reduce($s);
}
/**
* @param string $n
* @param string $p
* @return string
* @throws SodiumException
*/
public static function scalarmult_ristretto255(
#[SensitiveParameter]
string $n,
#[SensitiveParameter]
string $p
): string {
if (self::strlen($n) !== 32) {
throw new SodiumException('Scalar must be 32 bytes, ' . self::strlen($p) . ' given.');
}
if (self::strlen($p) !== 32) {
throw new SodiumException('Point must be 32 bytes, ' . self::strlen($p) . ' given.');
}
$result = self::ristretto255_frombytes($p);
if ($result['res'] !== 0) {
throw new SodiumException('Could not multiply points');
}
$P = $result['h'];
$t = self::stringToIntArray($n);
$t[31] &= 0x7f;
$Q = self::ge_scalarmult(self::intArrayToString($t), $P);
$q = self::ristretto255_p3_tobytes($Q);
if (ParagonIE_Sodium_Compat::is_zero($q)) {
throw new SodiumException('An unknown error has occurred');
}
return $q;
}
/**
* @param string $n
* @return string
* @throws SodiumException
*/
public static function scalarmult_ristretto255_base(
#[SensitiveParameter]
string $n
): string {
$t = self::stringToIntArray($n);
$t[31] &= 0x7f;
$Q = self::ge_scalarmult_base(self::intArrayToString($t));
$q = self::ristretto255_p3_tobytes($Q);
if (ParagonIE_Sodium_Compat::is_zero($q)) {
throw new SodiumException('An unknown error has occurred');
}
return $q;
}
}
+293
View File
@@ -0,0 +1,293 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_Salsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Salsa20
*/
abstract class ParagonIE_Sodium_Core_Salsa20 extends ParagonIE_Sodium_Core_Util
{
const ROUNDS = 20;
/**
* Calculate an salsa20 hash of a single block
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $k
* @param string|null $c
* @return string
* @throws TypeError
*/
public static function core_salsa20(
string $in,
#[SensitiveParameter]
string $k,
?string $c = null
): string {
if (self::strlen($k) < 32) {
throw new RangeException('Key must be 32 bytes long');
}
if ($c === null) {
$j0 = $x0 = 0x61707865;
$j5 = $x5 = 0x3320646e;
$j10 = $x10 = 0x79622d32;
$j15 = $x15 = 0x6b206574;
} else {
$j0 = $x0 = self::load_4(self::substr($c, 0, 4));
$j5 = $x5 = self::load_4(self::substr($c, 4, 4));
$j10 = $x10 = self::load_4(self::substr($c, 8, 4));
$j15 = $x15 = self::load_4(self::substr($c, 12, 4));
}
$j1 = $x1 = self::load_4(self::substr($k, 0, 4));
$j2 = $x2 = self::load_4(self::substr($k, 4, 4));
$j3 = $x3 = self::load_4(self::substr($k, 8, 4));
$j4 = $x4 = self::load_4(self::substr($k, 12, 4));
$j6 = $x6 = self::load_4(self::substr($in, 0, 4));
$j7 = $x7 = self::load_4(self::substr($in, 4, 4));
$j8 = $x8 = self::load_4(self::substr($in, 8, 4));
$j9 = $x9 = self::load_4(self::substr($in, 12, 4));
$j11 = $x11 = self::load_4(self::substr($k, 16, 4));
$j12 = $x12 = self::load_4(self::substr($k, 20, 4));
$j13 = $x13 = self::load_4(self::substr($k, 24, 4));
$j14 = $x14 = self::load_4(self::substr($k, 28, 4));
for ($i = self::ROUNDS; $i > 0; $i -= 2) {
$x4 ^= self::rotate($x0 + $x12, 7);
$x8 ^= self::rotate($x4 + $x0, 9);
$x12 ^= self::rotate($x8 + $x4, 13);
$x0 ^= self::rotate($x12 + $x8, 18);
$x9 ^= self::rotate($x5 + $x1, 7);
$x13 ^= self::rotate($x9 + $x5, 9);
$x1 ^= self::rotate($x13 + $x9, 13);
$x5 ^= self::rotate($x1 + $x13, 18);
$x14 ^= self::rotate($x10 + $x6, 7);
$x2 ^= self::rotate($x14 + $x10, 9);
$x6 ^= self::rotate($x2 + $x14, 13);
$x10 ^= self::rotate($x6 + $x2, 18);
$x3 ^= self::rotate($x15 + $x11, 7);
$x7 ^= self::rotate($x3 + $x15, 9);
$x11 ^= self::rotate($x7 + $x3, 13);
$x15 ^= self::rotate($x11 + $x7, 18);
$x1 ^= self::rotate($x0 + $x3, 7);
$x2 ^= self::rotate($x1 + $x0, 9);
$x3 ^= self::rotate($x2 + $x1, 13);
$x0 ^= self::rotate($x3 + $x2, 18);
$x6 ^= self::rotate($x5 + $x4, 7);
$x7 ^= self::rotate($x6 + $x5, 9);
$x4 ^= self::rotate($x7 + $x6, 13);
$x5 ^= self::rotate($x4 + $x7, 18);
$x11 ^= self::rotate($x10 + $x9, 7);
$x8 ^= self::rotate($x11 + $x10, 9);
$x9 ^= self::rotate($x8 + $x11, 13);
$x10 ^= self::rotate($x9 + $x8, 18);
$x12 ^= self::rotate($x15 + $x14, 7);
$x13 ^= self::rotate($x12 + $x15, 9);
$x14 ^= self::rotate($x13 + $x12, 13);
$x15 ^= self::rotate($x14 + $x13, 18);
}
$x0 += $j0;
$x1 += $j1;
$x2 += $j2;
$x3 += $j3;
$x4 += $j4;
$x5 += $j5;
$x6 += $j6;
$x7 += $j7;
$x8 += $j8;
$x9 += $j9;
$x10 += $j10;
$x11 += $j11;
$x12 += $j12;
$x13 += $j13;
$x14 += $j14;
$x15 += $j15;
return self::store32_le($x0) .
self::store32_le($x1) .
self::store32_le($x2) .
self::store32_le($x3) .
self::store32_le($x4) .
self::store32_le($x5) .
self::store32_le($x6) .
self::store32_le($x7) .
self::store32_le($x8) .
self::store32_le($x9) .
self::store32_le($x10) .
self::store32_le($x11) .
self::store32_le($x12) .
self::store32_le($x13) .
self::store32_le($x14) .
self::store32_le($x15);
}
/**
* @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 salsa20(
int $len,
string $nonce,
#[SensitiveParameter]
string $key
): string {
if (self::strlen($key) !== 32) {
throw new RangeException('Key must be 32 bytes long');
}
$kcopy = $key;
$in = self::substr($nonce, 0, 8) . str_repeat("\0", 8);
$c = '';
while ($len >= 64) {
$c .= self::core_salsa20($in, $kcopy);
$u = 1;
// Internal counter.
for ($i = 8; $i < 16; ++$i) {
$u += self::chrToInt($in[$i]);
$in[$i] = self::intToChr($u & 0xff);
$u >>= 8;
}
$len -= 64;
}
if ($len > 0) {
$c .= self::substr(
self::core_salsa20($in, $kcopy),
0,
$len
);
}
try {
ParagonIE_Sodium_Compat::memzero($kcopy);
} catch (SodiumException) {
$kcopy = null;
}
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param string $m
* @param string $n
* @param int $ic
* @param string $k
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20_xor_ic(
#[SensitiveParameter]
string $m,
string $n,
int $ic,
#[SensitiveParameter]
string $k
): string {
$mlen = self::strlen($m);
if ($mlen < 1) {
return '';
}
$kcopy = self::substr($k, 0, 32);
$in = self::substr($n, 0, 8);
// Initialize the counter
$in .= ParagonIE_Sodium_Core_Util::store64_le($ic);
$c = '';
while ($mlen >= 64) {
$block = self::core_salsa20($in, $kcopy);
$c .= self::xorStrings(
self::substr($m, 0, 64),
self::substr($block, 0, 64)
);
$u = 1;
for ($i = 8; $i < 16; ++$i) {
$u += self::chrToInt($in[$i]);
$in[$i] = self::intToChr($u & 0xff);
$u >>= 8;
}
$mlen -= 64;
$m = self::substr($m, 64);
}
if ($mlen) {
$block = self::core_salsa20($in, $kcopy);
$c .= self::xorStrings(
self::substr($m, 0, $mlen),
self::substr($block, 0, $mlen)
);
}
try {
ParagonIE_Sodium_Compat::memzero($block);
ParagonIE_Sodium_Compat::memzero($kcopy);
} catch (SodiumException) {
$block = null;
$kcopy = null;
}
return $c;
}
/**
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function salsa20_xor(
#[SensitiveParameter]
string $message,
string $nonce,
#[SensitiveParameter]
string $key
): string {
return self::xorStrings(
$message,
self::salsa20(
self::strlen($message),
$nonce,
$key
)
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $u
* @param int $c
* @return int
*/
public static function rotate(int $u, int $c): int
{
$u &= 0xffffffff;
$c %= 32;
return (0xffffffff & (
($u << $c)
|
($u >> (32 - $c))
)
);
}
}
@@ -0,0 +1,161 @@
<?php
declare(strict_types=1);
/**
* Class ParagonIE_Sodium_Core_SecretStream_State
*/
class ParagonIE_Sodium_Core_SecretStream_State
{
protected string $key;
protected int $counter;
protected string $nonce;
protected string $_pad;
/**
* ParagonIE_Sodium_Core_SecretStream_State constructor.
* @param string $key
* @param string|null $nonce
*/
public function __construct(
#[SensitiveParameter]
string $key,
?string $nonce = null
) {
$this->key = $key;
$this->counter = 1;
if (is_null($nonce)) {
$nonce = str_repeat("\0", 12);
}
$this->nonce = str_pad($nonce, 12, "\0");
$this->_pad = str_repeat("\0", 4);
}
/**
* @return self
*/
public function counterReset(): self
{
$this->counter = 1;
$this->_pad = str_repeat("\0", 4);
return $this;
}
/**
* @return string
*/
public function getKey(): string
{
return $this->key;
}
/**
* @return string
*/
public function getCounter(): string
{
return ParagonIE_Sodium_Core_Util::store32_le($this->counter);
}
/**
* @return string
*/
public function getNonce(): string
{
if (ParagonIE_Sodium_Core_Util::strlen($this->nonce) !== 12) {
$this->nonce = str_pad($this->nonce, 12, "\0");
}
return $this->nonce;
}
/**
* @return string
*/
public function getCombinedNonce(): string
{
return $this->getCounter() .
ParagonIE_Sodium_Core_Util::substr($this->getNonce(), 0, 8);
}
/**
* @return self
*/
public function incrementCounter(): self
{
++$this->counter;
return $this;
}
/**
* @return bool
*/
public function needsRekey(): bool
{
return ($this->counter & 0xffff) === 0;
}
/**
* @param string $newKeyAndNonce
* @return self
*/
public function rekey(
#[SensitiveParameter]
string $newKeyAndNonce
): self {
$this->key = ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 0, 32);
$this->nonce = str_pad(
ParagonIE_Sodium_Core_Util::substr($newKeyAndNonce, 32),
12,
"\0"
);
return $this;
}
/**
* @param string $str
* @return self
*/
public function xorNonce(
#[SensitiveParameter]
string $str
): self {
$this->nonce = ParagonIE_Sodium_Core_Util::xorStrings(
$this->getNonce(),
str_pad(
ParagonIE_Sodium_Core_Util::substr($str, 0, 8),
12,
"\0"
)
);
return $this;
}
/**
* @param string $string
* @return self
*/
public static function fromString(
#[SensitiveParameter]
string $string
): self {
$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(): string
{
return $this->key .
$this->getCounter() .
$this->nonce .
$this->_pad;
}
}
+310
View File
@@ -0,0 +1,310 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_SipHash', false)) {
return;
}
/**
* Class ParagonIE_SodiumCompat_Core_SipHash
*
* Only uses 32-bit arithmetic, while the original SipHash used 64-bit integers
*/
class ParagonIE_Sodium_Core_SipHash extends ParagonIE_Sodium_Core_Util
{
/**
* @internal You should not use this directly from another application
*
* @param int[] $v
* @return int[]
*
*/
public static function sipRound(array $v): array
{
# v0 += v1;
list($v[0], $v[1]) = self::add(
array($v[0], $v[1]),
array($v[2], $v[3])
);
# v1=ROTL(v1,13);
list($v[2], $v[3]) = self::rotl_64($v[2], $v[3], 13);
# v1 ^= v0;
$v[2] = $v[2] ^ $v[0];
$v[3] = $v[3] ^ $v[1];
# v0=ROTL(v0,32);
list($v[0], $v[1]) = self::rotl_64($v[0], $v[1], 32);
# v2 += v3;
list($v[4], $v[5]) = self::add(
array($v[4], $v[5]),
array($v[6], $v[7])
);
# v3=ROTL(v3,16);
list($v[6], $v[7]) = self::rotl_64($v[6], $v[7], 16);
# v3 ^= v2;
$v[6] = $v[6] ^ $v[4];
$v[7] = $v[7] ^ $v[5];
# v0 += v3;
list($v[0], $v[1]) = self::add(
array($v[0], $v[1]),
array($v[6], $v[7])
);
# v3=ROTL(v3,21);
list($v[6], $v[7]) = self::rotl_64($v[6], $v[7], 21);
# v3 ^= v0;
$v[6] = $v[6] ^ $v[0];
$v[7] = $v[7] ^ $v[1];
# v2 += v1;
list($v[4], $v[5]) = self::add(
array($v[4], $v[5]),
array($v[2], $v[3])
);
# v1=ROTL(v1,17);
list($v[2], $v[3]) = self::rotl_64($v[2], $v[3], 17);
# v1 ^= v2;;
$v[2] = $v[2] ^ $v[4];
$v[3] = $v[3] ^ $v[5];
# v2=ROTL(v2,32)
list($v[4], $v[5]) = self::rotl_64($v[4], $v[5], 32);
return $v;
}
/**
* Add two 32 bit integers representing a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int[] $a
* @param int[] $b
* @return array<int, mixed>
*/
public static function add(array $a, array $b): array
{
/** @var int $x1 */
$x1 = $a[1] + $b[1];
/** @var int $c */
$c = $x1 >> 32; // Carry if ($a + $b) > 0xffffffff
/** @var int $x0 */
$x0 = $a[0] + $b[0] + $c;
return array(
$x0 & 0xffffffff,
$x1 & 0xffffffff
);
}
/**
* @internal You should not use this directly from another application
*
* @param int $int0
* @param int $int1
* @param int $c
* @return array<int, mixed>
*/
public static function rotl_64(int $int0, int $int1, int $c): array
{
$int0 &= 0xffffffff;
$int1 &= 0xffffffff;
$c &= 63;
if ($c === 32) {
return array($int1, $int0);
}
if ($c > 31) {
$tmp = $int1;
$int1 = $int0;
$int0 = $tmp;
$c &= 31;
}
if ($c === 0) {
return array($int0, $int1);
}
return array(
0xffffffff & (
($int0 << $c)
|
($int1 >> (32 - $c))
),
0xffffffff & (
($int1 << $c)
|
($int0 >> (32 - $c))
),
);
}
/**
* Implements Siphash-2-4 using only 32-bit numbers.
*
* When we split an int into two, the higher bits go to the lower index.
* e.g. 0xDEADBEEFAB10C92D becomes [
* 0 => 0xDEADBEEF,
* 1 => 0xAB10C92D
* ].
*
* @internal You should not use this directly from another application
*
* @param string $in
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*
* @psalm-suppress PossiblyUndefinedArrayOffset
*/
public static function sipHash24(
#[SensitiveParameter]
string $in,
#[SensitiveParameter]
string $key
): string {
$inlen = self::strlen($in);
# /* "somepseudorandomlygeneratedbytes" */
# u64 v0 = 0x736f6d6570736575ULL;
# u64 v1 = 0x646f72616e646f6dULL;
# u64 v2 = 0x6c7967656e657261ULL;
# u64 v3 = 0x7465646279746573ULL;
$v = array(
0x736f6d65, // 0
0x70736575, // 1
0x646f7261, // 2
0x6e646f6d, // 3
0x6c796765, // 4
0x6e657261, // 5
0x74656462, // 6
0x79746573 // 7
);
// v0 => $v[0], $v[1]
// v1 => $v[2], $v[3]
// v2 => $v[4], $v[5]
// v3 => $v[6], $v[7]
# u64 k0 = LOAD64_LE( k );
# u64 k1 = LOAD64_LE( k + 8 );
$k = array(
self::load_4(self::substr($key, 4, 4)),
self::load_4(self::substr($key, 0, 4)),
self::load_4(self::substr($key, 12, 4)),
self::load_4(self::substr($key, 8, 4))
);
// k0 => $k[0], $k[1]
// k1 => $k[2], $k[3]
# b = ( ( u64 )inlen ) << 56;
$b = array(
$inlen << 24,
0
);
// See docblock for why the 0th index gets the higher bits.
# v3 ^= k1;
$v[6] ^= $k[2];
$v[7] ^= $k[3];
# v2 ^= k0;
$v[4] ^= $k[0];
$v[5] ^= $k[1];
# v1 ^= k1;
$v[2] ^= $k[2];
$v[3] ^= $k[3];
# v0 ^= k0;
$v[0] ^= $k[0];
$v[1] ^= $k[1];
$left = $inlen;
# for ( ; in != end; in += 8 )
while ($left >= 8) {
# m = LOAD64_LE( in );
$m = array(
self::load_4(self::substr($in, 4, 4)),
self::load_4(self::substr($in, 0, 4))
);
# v3 ^= m;
$v[6] ^= $m[0];
$v[7] ^= $m[1];
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
# v0 ^= m;
$v[0] ^= $m[0];
$v[1] ^= $m[1];
$in = self::substr($in, 8);
$left -= 8;
}
# switch( left )
# {
# case 7: b |= ( ( u64 )in[ 6] ) << 48;
# case 6: b |= ( ( u64 )in[ 5] ) << 40;
# case 5: b |= ( ( u64 )in[ 4] ) << 32;
# case 4: b |= ( ( u64 )in[ 3] ) << 24;
# case 3: b |= ( ( u64 )in[ 2] ) << 16;
# case 2: b |= ( ( u64 )in[ 1] ) << 8;
# case 1: b |= ( ( u64 )in[ 0] ); break;
# case 0: break;
# }
switch ($left) {
case 7:
$b[0] |= self::chrToInt($in[6]) << 16;
case 6:
$b[0] |= self::chrToInt($in[5]) << 8;
case 5:
$b[0] |= self::chrToInt($in[4]);
case 4:
$b[1] |= self::chrToInt($in[3]) << 24;
case 3:
$b[1] |= self::chrToInt($in[2]) << 16;
case 2:
$b[1] |= self::chrToInt($in[1]) << 8;
case 1:
$b[1] |= self::chrToInt($in[0]);
case 0:
break;
}
// See docblock for why the 0th index gets the higher bits.
# v3 ^= b;
$v[6] ^= $b[0];
$v[7] ^= $b[1];
# SIPROUND;
# SIPROUND;
$v = self::sipRound($v);
$v = self::sipRound($v);
# v0 ^= b;
$v[0] ^= $b[0];
$v[1] ^= $b[1];
// Flip the lower 8 bits of v2 which is ($v[4], $v[5]) in our implementation
# v2 ^= 0xff;
$v[5] ^= 0xff;
# SIPROUND;
# SIPROUND;
# SIPROUND;
# SIPROUND;
$v = self::sipRound(self::sipRound(self::sipRound(self::sipRound($v))));
# b = v0 ^ v1 ^ v2 ^ v3;
# STORE64_LE( out, b );
return self::store32_le($v[1] ^ $v[3] ^ $v[5] ^ $v[7]) .
self::store32_le($v[0] ^ $v[2] ^ $v[4] ^ $v[6]);
}
}
+620
View File
@@ -0,0 +1,620 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_Util', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_Util
*/
abstract class ParagonIE_Sodium_Core_Util
{
const U32_MAX = 0xFFFFFFFF;
/**
* @param int $integer
* @param int $size (16, 32, 64)
* @return int
*/
public static function abs(
#[SensitiveParameter]
int $integer,
int $size = 0
): int {
$realSize = (PHP_INT_SIZE << 3) - 1;
if ($size) {
--$size;
} else {
$size = $realSize;
}
$negative = -(($integer >> $size) & 1);
return (
($integer ^ $negative)
+
(($negative >> $realSize) & 1)
);
}
/**
* @param string $a
* @param string $b
* @return string
* @throws SodiumException
*/
public static function andStrings(
#[SensitiveParameter]
string $a,
#[SensitiveParameter]
string $b
): string {
$len = self::strlen($a);
if (self::strlen($b) !== $len) {
throw new SodiumException('Both strings must be of equal length to combine with bitwise AND');
}
return $a & $b;
}
/**
* Convert a binary string into a hexadecimal string without cache-timing
* leaks
*
* @internal You should not use this directly from another application
*
* @param string $binaryString (raw binary)
* @return string
* @throws TypeError
*/
public static function bin2hex(
#[SensitiveParameter]
string $binaryString
): string {
$hex = '';
$len = self::strlen($binaryString);
for ($i = 0; $i < $len; ++$i) {
/** @var array<int, int> $chunk */
$chunk = unpack('C', $binaryString[$i]);
/** @var int $c */
$c = $chunk[1] & 0xf;
/** @var int $b */
$b = $chunk[1] >> 4;
$hex .= pack(
'CC',
(87 + $b + ((($b - 10) >> 8) & ~38)),
(87 + $c + ((($c - 10) >> 8) & ~38))
);
}
return $hex;
}
/**
* Cache-timing-safe variant of ord()
*
* @internal You should not use this directly from another application
*
* @param string $chr
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function chrToInt(
#[SensitiveParameter]
string $chr
): int {
if (self::strlen($chr) !== 1) {
throw new SodiumException('chrToInt() expects a string that is exactly 1 character long');
}
/** @var array<int, int> $chunk */
$chunk = unpack('C', $chr);
return $chunk[1];
}
/**
* Compares two strings.
*
* @internal You should not use this directly from another application
*
* @param string $left
* @param string $right
* @param ?int $len
* @return int
* @throws SodiumException
* @throws TypeError
*/
public static function compare(
#[SensitiveParameter]
string $left,
#[SensitiveParameter]
string $right,
?int $len = null
): int {
$leftLen = self::strlen($left);
$rightLen = self::strlen($right);
if ($len === null) {
$len = max($leftLen, $rightLen);
$left = str_pad($left, $len, "\x00");
$right = str_pad($right, $len, "\x00");
} elseif ($leftLen !== $rightLen) {
throw new SodiumException("Argument #1 and argument #2 must have the same length");
}
$gt = 0;
$eq = 1;
$i = $len;
while ($i !== 0) {
--$i;
$gt |= ((self::chrToInt($right[$i]) - self::chrToInt($left[$i])) >> 8) & $eq;
$eq &= ((self::chrToInt($right[$i]) ^ self::chrToInt($left[$i])) - 1) >> 8;
}
return ($gt + $gt + $eq) - 1;
}
/**
* Evaluate whether or not two strings are equal (in constant-time)
*
* @param string $left
* @param string $right
* @return bool
*
* @throws TypeError
*/
public static function hashEquals(
#[SensitiveParameter]
string $left,
#[SensitiveParameter]
string $right
): bool {
return hash_equals($left, $right);
}
/**
* Convert a hexadecimal string into a binary string without cache-timing
* leaks
*
* @internal You should not use this directly from another application
*
* @param string $hexString
* @param string $ignore
* @param bool $strictPadding
* @return string (raw binary)
* @throws SodiumException
* @throws TypeError
*/
public static function hex2bin(
#[SensitiveParameter]
string $hexString,
string $ignore = '',
bool $strictPadding = false
): string {
$hex_pos = 0;
$bin = '';
$c_acc = 0;
$hex_len = self::strlen($hexString);
$state = 0;
$chunk = unpack('C*', $hexString);
while ($hex_pos < $hex_len) {
++$hex_pos;
/** @var int $c */
$c = $chunk[$hex_pos];
$c_num = $c ^ 48;
$c_num0 = ($c_num - 10) >> 8;
$c_alpha = ($c & ~32) - 55;
$c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8;
if (($c_num0 | $c_alpha0) === 0) {
if ($ignore && $state === 0 && str_contains($ignore, self::intToChr($c))) {
continue;
}
throw new SodiumException(
'hex2bin() only expects hexadecimal characters'
);
}
$c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0);
if ($state === 0) {
$c_acc = $c_val * 16;
} else {
$bin .= pack('C', $c_acc | $c_val);
}
$state ^= 1;
}
if ($strictPadding && $state !== 0) {
throw new SodiumException(
'Expected an even number of hexadecimal characters'
);
}
return $bin;
}
/**
* Turn an array of integers into a string
*
* @internal You should not use this directly from another application
*
* @param array<int, int> $ints
* @return string
*/
public static function intArrayToString(array $ints): string
{
$args = $ints;
foreach ($args as $i => $v) {
$args[$i] = ($v & 0xff);
}
array_unshift($args, str_repeat('C', count($ints)));
return (string) (call_user_func_array('pack', $args));
}
/**
* Cache-timing-safe variant of ord()
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function intToChr(
#[SensitiveParameter]
int $int
): string {
return pack('C', $int);
}
/**
* Load a 3 character substring into an integer
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return int
* @throws RangeException
* @throws TypeError
*/
public static function load_3(
#[SensitiveParameter]
string $string
): int {
/* Input validation: */
if (self::strlen($string) < 3) {
throw new RangeException(
'String must be 3 bytes or more; ' . self::strlen($string) . ' given.'
);
}
/** @var array<int, int> $unpacked */
$unpacked = unpack('V', $string . "\0");
return ($unpacked[1] & 0xffffff);
}
/**
* Load a 4 character substring into an integer
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return int
* @throws RangeException
* @throws TypeError
*/
public static function load_4(
#[SensitiveParameter]
string $string
): int {
/* Input validation: */
if (self::strlen($string) < 4) {
throw new RangeException(
'String must be 4 bytes or more; ' . self::strlen($string) . ' given.'
);
}
/** @var array<int, int> $unpacked */
$unpacked = unpack('V', $string);
return $unpacked[1];
}
/**
* Load a 8 character substring into an integer
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return int
*
* @throws RangeException
* @throws SodiumException
* @throws TypeError
*/
public static function load64_le(
#[SensitiveParameter]
string $string
): int {
/* Input validation: */
if (self::strlen($string) < 4) {
throw new RangeException(
'String must be 4 bytes or more; ' . self::strlen($string) . ' given.'
);
}
$unpacked = unpack('P', $string);
return (int) $unpacked[1];
}
/**
* @internal You should not use this directly from another application
*
* @param string $left
* @param string $right
* @return int
* @throws TypeError
*/
public static function memcmp(
#[SensitiveParameter]
string $left,
#[SensitiveParameter]
string $right
): int {
$e = (int) !self::hashEquals($left, $right);
return 0 - $e;
}
/**
* Multiply two integers in constant-time
*
* Micro-architecture timing side-channels caused by how your CPU
* implements multiplication are best prevented by never using the
* multiplication operators and ensuring that our code always takes
* the same number of operations to complete, regardless of the values
* of $a and $b.
*
* @internal You should not use this directly from another application
*
* @param int $a
* @param int $b
* @param int $size Limits the number of operations (useful for small,
* constant operands)
* @return int
*/
public static function mul(
#[SensitiveParameter]
int $a,
#[SensitiveParameter]
int $b,
int $size = 0
): int {
if (ParagonIE_Sodium_Compat::$fastMult) {
return (int) ($a * $b);
}
static $defaultSize = null;
if (!$defaultSize) {
$defaultSize = (PHP_INT_SIZE << 3) - 1;
}
if ($size < 1) {
$size = $defaultSize;
}
/** @var int $size */
$c = 0;
/**
* Mask is either -1 or 0.
*
* -1 in binary looks like 0x1111 ... 1111
* 0 in binary looks like 0x0000 ... 0000
*/
$mask = -(($b >> ($defaultSize)) & 1);
/**
* Ensure $b is a positive integer, without creating
* a branching side-channel
*
* @var int $b
*/
$b = ($b & ~$mask) | ($mask & -$b);
/**
* Unless $size is provided:
*
* This loop always runs 32 times when PHP_INT_SIZE is 4.
* This loop always runs 64 times when PHP_INT_SIZE is 8.
*/
for ($i = $size; $i >= 0; --$i) {
$c += ($a & -($b & 1));
$a <<= 1;
$b >>= 1;
}
$c = (int) @($c & -1);
/**
* If $b was negative, we then apply the same value to $c here.
* It doesn't matter much if $a was negative; the $c += above would
* have produced a negative integer to begin with. But a negative $b
* makes $b >>= 1 never return 0, so we would end up with incorrect
* results.
*
* The end result is what we'd expect from integer multiplication.
*/
return (($c & ~$mask) | ($mask & -$c));
}
/**
* Convert any arbitrary numbers into two 32-bit integers that represent
* a 64-bit integer.
*
* @internal You should not use this directly from another application
*
* @param int|float $num
* @return array<int, int>
* @psalm-suppress RedundantCastGivenDocblockType
*/
public static function numericTo64BitInteger(int|float $num): array
{
$high = 0;
/** @var int $low */
if (PHP_INT_SIZE === 4) {
$low = (int) $num;
} else {
$low = $num & 0xffffffff;
}
if ((+(abs($num))) >= 1) {
if ($num > 0) {
/** @var int $high */
$high = min((+(floor($num/4294967296))), 4294967295);
} else {
$high = ~~((+(ceil(($num - (+((~~($num)))))/4294967296))));
}
}
/**
* @var int $high
* @var int $low
*/
return array((int) $high, (int) $low);
}
/**
* Store a 32-bit integer into a string, treating it as little-endian.
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function store32_le(int $int): string
{
return pack('V', $int);
}
/**
* Stores a 64-bit integer as an string, treating it as little-endian.
*
* @internal You should not use this directly from another application
*
* @param int $int
* @return string
* @throws TypeError
*/
public static function store64_le(int $int): string
{
return pack('P', $int);
}
/**
* Safe string length
*
* @internal You should not use this directly from another application
*
* @param string $str
* @return int
* @throws TypeError
*/
public static function strlen(
#[SensitiveParameter]
string $str
): int {
return strlen($str);
}
/**
* Turn a string into an array of integers
*
* @internal You should not use this directly from another application
*
* @param string $string
* @return array<int, int>
* @throws TypeError
*/
public static function stringToIntArray(string $string): array
{
return array_values(
unpack('C*', $string)
);
}
/**
* Safe substring
*
* @internal You should not use this directly from another application
*
* @param string $str
* @param int $start
* @param ?int $length
* @return string
* @throws TypeError
*/
public static function substr(
#[SensitiveParameter]
string $str,
int $start = 0,
?int $length = null
): string {
if ($length === 0) {
return '';
}
return substr($str, $start, $length);
}
/**
* Compare a 16-character byte string in constant time.
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @return bool
* @throws TypeError
*/
public static function verify_16(
#[SensitiveParameter]
string $a,
#[SensitiveParameter]
string $b
): bool {
return self::hashEquals(
self::substr($a, 0, 16),
self::substr($b, 0, 16)
);
}
/**
* Compare a 32-character byte string in constant time.
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @return bool
*
* @throws SodiumException
* @throws TypeError
*/
public static function verify_32(
#[SensitiveParameter]
string $a,
#[SensitiveParameter]
string $b
): bool {
return self::hashEquals(
self::substr($a, 0, 32),
self::substr($b, 0, 32)
);
}
/**
* Calculate $a ^ $b for two strings.
*
* @internal You should not use this directly from another application
*
* @param string $a
* @param string $b
* @return string
* @throws TypeError
*/
public static function xorStrings(
#[SensitiveParameter]
string $a,
#[SensitiveParameter]
string $b
): string {
return $a ^ $b;
}
}
+232
View File
@@ -0,0 +1,232 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_X25519', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_X25519
*/
abstract class ParagonIE_Sodium_Core_X25519 extends ParagonIE_Sodium_Core_Curve25519
{
/**
* Alters the objects passed to this method in place.
*
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @param ParagonIE_Sodium_Core_Curve25519_Fe $g
* @param int $b
* @return void
*/
public static function fe_cswap(
ParagonIE_Sodium_Core_Curve25519_Fe $f,
ParagonIE_Sodium_Core_Curve25519_Fe $g,
int $b = 0
): void {
$b = -$b;
$x0 = ($f->e0 ^ $g->e0) & $b;
$x1 = ($f->e1 ^ $g->e1) & $b;
$x2 = ($f->e2 ^ $g->e2) & $b;
$x3 = ($f->e3 ^ $g->e3) & $b;
$x4 = ($f->e4 ^ $g->e4) & $b;
$x5 = ($f->e5 ^ $g->e5) & $b;
$x6 = ($f->e6 ^ $g->e6) & $b;
$x7 = ($f->e7 ^ $g->e7) & $b;
$x8 = ($f->e8 ^ $g->e8) & $b;
$x9 = ($f->e9 ^ $g->e9) & $b;
$f->e0 ^= $x0;
$f->e1 ^= $x1;
$f->e2 ^= $x2;
$f->e3 ^= $x3;
$f->e4 ^= $x4;
$f->e5 ^= $x5;
$f->e6 ^= $x6;
$f->e7 ^= $x7;
$f->e8 ^= $x8;
$f->e9 ^= $x9;
$g->e0 ^= $x0;
$g->e1 ^= $x1;
$g->e2 ^= $x2;
$g->e3 ^= $x3;
$g->e4 ^= $x4;
$g->e5 ^= $x5;
$g->e6 ^= $x6;
$g->e7 ^= $x7;
$g->e8 ^= $x8;
$g->e9 ^= $x9;
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $f
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function fe_mul121666(ParagonIE_Sodium_Core_Curve25519_Fe $f): ParagonIE_Sodium_Core_Curve25519_Fe
{
$h0 = self::mul($f->e0, 121666, 17);
$h1 = self::mul($f->e1, 121666, 17);
$h2 = self::mul($f->e2, 121666, 17);
$h3 = self::mul($f->e3, 121666, 17);
$h4 = self::mul($f->e4, 121666, 17);
$h5 = self::mul($f->e5, 121666, 17);
$h6 = self::mul($f->e6, 121666, 17);
$h7 = self::mul($f->e7, 121666, 17);
$h8 = self::mul($f->e8, 121666, 17);
$h9 = self::mul($f->e9, 121666, 17);
$carry9 = ($h9 + (1 << 24)) >> 25;
$h0 += self::mul($carry9, 19, 5);
$h9 -= $carry9 << 25;
$carry1 = ($h1 + (1 << 24)) >> 25;
$h2 += $carry1;
$h1 -= $carry1 << 25;
$carry3 = ($h3 + (1 << 24)) >> 25;
$h4 += $carry3;
$h3 -= $carry3 << 25;
$carry5 = ($h5 + (1 << 24)) >> 25;
$h6 += $carry5;
$h5 -= $carry5 << 25;
$carry7 = ($h7 + (1 << 24)) >> 25;
$h8 += $carry7;
$h7 -= $carry7 << 25;
$carry0 = ($h0 + (1 << 25)) >> 26;
$h1 += $carry0;
$h0 -= $carry0 << 26;
$carry2 = ($h2 + (1 << 25)) >> 26;
$h3 += $carry2;
$h2 -= $carry2 << 26;
$carry4 = ($h4 + (1 << 25)) >> 26;
$h5 += $carry4;
$h4 -= $carry4 << 26;
$carry6 = ($h6 + (1 << 25)) >> 26;
$h7 += $carry6;
$h6 -= $carry6 << 26;
$carry8 = ($h8 + (1 << 25)) >> 26;
$h9 += $carry8;
$h8 -= $carry8 << 26;
return new ParagonIE_Sodium_Core_Curve25519_Fe($h0, $h1, $h2, $h3, $h4, $h5, $h6, $h7, $h8, $h9);
}
/**
* @internal You should not use this directly from another application
*
* Inline comments preceded by # are from libsodium's ref10 code.
*
* @param string $n
* @param string $p
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_scalarmult_curve25519_ref10(
#[SensitiveParameter]
string $n,
#[SensitiveParameter]
string $p
): string {
$e = $n;
$e[0] = self::intToChr(
self::chrToInt($e[0]) & 248
);
$e[31] = self::intToChr(
(self::chrToInt($e[31]) & 127) | 64
);
$x1 = self::fe_frombytes($p);
$x2 = self::fe_1();
$z2 = self::fe_0();
$x3 = clone $x1;
$z3 = self::fe_1();
$swap = 0;
for ($pos = 254; $pos >= 0; --$pos) {
# b = e[pos / 8] >> (pos & 7);
$b = self::chrToInt(
$e[$pos >> 3]
) >> ($pos & 7);
$b &= 1;
$swap ^= $b;
self::fe_cswap($x2, $x3, $swap);
self::fe_cswap($z2, $z3, $swap);
$swap = $b;
$tmp0 = self::fe_sub($x3, $z3);
$tmp1 = self::fe_sub($x2, $z2);
$x2 = self::fe_add($x2, $z2);
$z2 = self::fe_add($x3, $z3);
$z3 = self::fe_mul($tmp0, $x2);
$z2 = self::fe_mul($z2, $tmp1);
$tmp0 = self::fe_sq($tmp1);
$tmp1 = self::fe_sq($x2);
$x3 = self::fe_add($z3, $z2);
$z2 = self::fe_sub($z3, $z2);
$x2 = self::fe_mul($tmp1, $tmp0);
$tmp1 = self::fe_sub($tmp1, $tmp0);
$z2 = self::fe_sq($z2);
$z3 = self::fe_mul121666($tmp1);
$x3 = self::fe_sq($x3);
$tmp0 = self::fe_add($tmp0, $z3);
$z3 = self::fe_mul($x1, $z2);
$z2 = self::fe_mul($tmp1, $tmp0);
}
self::fe_cswap($x2, $x3, $swap);
self::fe_cswap($z2, $z3, $swap);
$z2 = self::fe_invert($z2);
$x2 = self::fe_mul($x2, $z2);
return self::fe_tobytes($x2);
}
/**
* @internal You should not use this directly from another application
*
* @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY
* @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ
* @return ParagonIE_Sodium_Core_Curve25519_Fe
*/
public static function edwards_to_montgomery(
ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY,
ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ
): ParagonIE_Sodium_Core_Curve25519_Fe {
$tempX = self::fe_add($edwardsZ, $edwardsY);
$tempZ = self::fe_sub($edwardsZ, $edwardsY);
$tempZ = self::fe_invert($tempZ);
return self::fe_mul($tempX, $tempZ);
}
/**
* @internal You should not use this directly from another application
*
* @param string $n
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function crypto_scalarmult_curve25519_ref10_base(
#[SensitiveParameter]
string $n
): string {
$e = $n;
$e[0] = self::intToChr(
self::chrToInt($e[0]) & 248
);
$e[31] = self::intToChr(
(self::chrToInt($e[31]) & 127) | 64
);
$A = self::ge_scalarmult_base($e);
$pk = self::edwards_to_montgomery($A->Y, $A->Z);
return self::fe_tobytes($pk);
}
}
+137
View File
@@ -0,0 +1,137 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_XChaCha20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_XChaCha20
*/
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 stream(
int $len,
string $nonce,
#[SensitiveParameter]
string $key
): string {
if (self::strlen($nonce) !== 24) {
throw new SodiumException('Nonce must be 24 bytes long');
}
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_Ctx(
self::hChaCha20(
self::substr($nonce, 0, 16),
$key
),
self::substr($nonce, 16, 8)
),
str_repeat("\x00", $len)
);
}
/**
* @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(
int $len,
string $nonce,
#[SensitiveParameter]
string $key
): string {
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
*
* @param string $message
* @param string $nonce
* @param string $key
* @param string $ic
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function streamXorIc(
#[SensitiveParameter]
string $message,
string $nonce,
#[SensitiveParameter]
string $key,
string $ic = ''
): string {
if (self::strlen($nonce) !== 24) {
throw new SodiumException('Nonce must be 24 bytes long');
}
return self::encryptBytes(
new ParagonIE_Sodium_Core_ChaCha20_Ctx(
self::hChaCha20(self::substr($nonce, 0, 16), $key),
self::substr($nonce, 16, 8),
$ic
),
$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(
#[SensitiveParameter]
string $message,
string $nonce,
string $key,
string $ic = ''
): string {
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
);
}
}
+66
View File
@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
if (class_exists('ParagonIE_Sodium_Core_XSalsa20', false)) {
return;
}
/**
* Class ParagonIE_Sodium_Core_XSalsa20
*/
abstract class ParagonIE_Sodium_Core_XSalsa20 extends ParagonIE_Sodium_Core_HSalsa20
{
/**
* Expand a key and nonce into an xsalsa20 keystream.
*
* @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 xsalsa20(
int $len,
string $nonce,
#[SensitiveParameter]
string $key
): string {
return self::salsa20(
$len,
self::substr($nonce, 16, 8),
self::hsalsa20($nonce, $key)
);
}
/**
* Encrypt a string with XSalsa20. Doesn't provide integrity.
*
* @internal You should not use this directly from another application
*
* @param string $message
* @param string $nonce
* @param string $key
* @return string
* @throws SodiumException
* @throws TypeError
*/
public static function xsalsa20_xor(
#[SensitiveParameter]
string $message,
string $nonce,
#[SensitiveParameter]
string $key
): string {
return self::xorStrings(
$message,
self::xsalsa20(
self::strlen($message),
$nonce,
$key
)
);
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+13
View File
@@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
if (class_exists('SodiumException', false)) {
return;
}
/**
* Class SodiumException
*/
class SodiumException extends Exception
{
}