| | <?php |
| |
|
| | if (class_exists('ParagonIE_Sodium_Crypto32', false)) { |
| | return; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | abstract class ParagonIE_Sodium_Crypto32 |
| | { |
| | const aead_chacha20poly1305_KEYBYTES = 32; |
| | const aead_chacha20poly1305_NSECBYTES = 0; |
| | const aead_chacha20poly1305_NPUBBYTES = 8; |
| | const aead_chacha20poly1305_ABYTES = 16; |
| |
|
| | const aead_chacha20poly1305_IETF_KEYBYTES = 32; |
| | const aead_chacha20poly1305_IETF_NSECBYTES = 0; |
| | const aead_chacha20poly1305_IETF_NPUBBYTES = 12; |
| | const aead_chacha20poly1305_IETF_ABYTES = 16; |
| |
|
| | const aead_xchacha20poly1305_IETF_KEYBYTES = 32; |
| | const aead_xchacha20poly1305_IETF_NSECBYTES = 0; |
| | const aead_xchacha20poly1305_IETF_NPUBBYTES = 24; |
| | const aead_xchacha20poly1305_IETF_ABYTES = 16; |
| |
|
| | const box_curve25519xsalsa20poly1305_SEEDBYTES = 32; |
| | const box_curve25519xsalsa20poly1305_PUBLICKEYBYTES = 32; |
| | const box_curve25519xsalsa20poly1305_SECRETKEYBYTES = 32; |
| | const box_curve25519xsalsa20poly1305_BEFORENMBYTES = 32; |
| | const box_curve25519xsalsa20poly1305_NONCEBYTES = 24; |
| | const box_curve25519xsalsa20poly1305_MACBYTES = 16; |
| | const box_curve25519xsalsa20poly1305_BOXZEROBYTES = 16; |
| | const box_curve25519xsalsa20poly1305_ZEROBYTES = 32; |
| |
|
| | const onetimeauth_poly1305_BYTES = 16; |
| | const onetimeauth_poly1305_KEYBYTES = 32; |
| |
|
| | const secretbox_xsalsa20poly1305_KEYBYTES = 32; |
| | const secretbox_xsalsa20poly1305_NONCEBYTES = 24; |
| | const secretbox_xsalsa20poly1305_MACBYTES = 16; |
| | const secretbox_xsalsa20poly1305_BOXZEROBYTES = 16; |
| | const secretbox_xsalsa20poly1305_ZEROBYTES = 32; |
| |
|
| | const secretbox_xchacha20poly1305_KEYBYTES = 32; |
| | const secretbox_xchacha20poly1305_NONCEBYTES = 24; |
| | const secretbox_xchacha20poly1305_MACBYTES = 16; |
| | const secretbox_xchacha20poly1305_BOXZEROBYTES = 16; |
| | const secretbox_xchacha20poly1305_ZEROBYTES = 32; |
| |
|
| | const stream_salsa20_KEYBYTES = 32; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function aead_chacha20poly1305_decrypt( |
| | $message = '', |
| | $ad = '', |
| | $nonce = '', |
| | $key = '' |
| | ) { |
| | |
| | $len = ParagonIE_Sodium_Core32_Util::strlen($message); |
| |
|
| | |
| | $clen = $len - self::aead_chacha20poly1305_ABYTES; |
| |
|
| | |
| | $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad); |
| |
|
| | |
| | $mac = ParagonIE_Sodium_Core32_Util::substr( |
| | $message, |
| | $clen, |
| | self::aead_chacha20poly1305_ABYTES |
| | ); |
| |
|
| | |
| | $ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 0, $clen); |
| |
|
| | |
| | $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream( |
| | 32, |
| | $nonce, |
| | $key |
| | ); |
| |
|
| | |
| | $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0); |
| | try { |
| | ParagonIE_Sodium_Compat::memzero($block0); |
| | } catch (SodiumException $ex) { |
| | $block0 = null; |
| | } |
| | $state->update($ad); |
| | $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen)); |
| | $state->update($ciphertext); |
| | $state->update(ParagonIE_Sodium_Core32_Util::store64_le($clen)); |
| | $computed_mac = $state->finish(); |
| |
|
| | |
| | if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) { |
| | throw new SodiumException('Invalid MAC'); |
| | } |
| |
|
| | |
| | return ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( |
| | $ciphertext, |
| | $nonce, |
| | $key, |
| | ParagonIE_Sodium_Core32_Util::store64_le(1) |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function aead_chacha20poly1305_encrypt( |
| | $message = '', |
| | $ad = '', |
| | $nonce = '', |
| | $key = '' |
| | ) { |
| | |
| | $len = ParagonIE_Sodium_Core32_Util::strlen($message); |
| |
|
| | |
| | $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad); |
| |
|
| | |
| | $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream( |
| | 32, |
| | $nonce, |
| | $key |
| | ); |
| | $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0); |
| | try { |
| | ParagonIE_Sodium_Compat::memzero($block0); |
| | } catch (SodiumException $ex) { |
| | $block0 = null; |
| | } |
| |
|
| | |
| | $ciphertext = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( |
| | $message, |
| | $nonce, |
| | $key, |
| | ParagonIE_Sodium_Core32_Util::store64_le(1) |
| | ); |
| |
|
| | $state->update($ad); |
| | $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen)); |
| | $state->update($ciphertext); |
| | $state->update(ParagonIE_Sodium_Core32_Util::store64_le($len)); |
| | return $ciphertext . $state->finish(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function aead_chacha20poly1305_ietf_decrypt( |
| | $message = '', |
| | $ad = '', |
| | $nonce = '', |
| | $key = '' |
| | ) { |
| | |
| | $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad); |
| |
|
| | |
| | $len = ParagonIE_Sodium_Core32_Util::strlen($message); |
| |
|
| | |
| | $clen = $len - self::aead_chacha20poly1305_IETF_ABYTES; |
| |
|
| | |
| | $block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream( |
| | 32, |
| | $nonce, |
| | $key |
| | ); |
| |
|
| | |
| | $mac = ParagonIE_Sodium_Core32_Util::substr( |
| | $message, |
| | $len - self::aead_chacha20poly1305_IETF_ABYTES, |
| | self::aead_chacha20poly1305_IETF_ABYTES |
| | ); |
| |
|
| | |
| | $ciphertext = ParagonIE_Sodium_Core32_Util::substr( |
| | $message, |
| | 0, |
| | $len - self::aead_chacha20poly1305_IETF_ABYTES |
| | ); |
| |
|
| | |
| | $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0); |
| | try { |
| | ParagonIE_Sodium_Compat::memzero($block0); |
| | } catch (SodiumException $ex) { |
| | $block0 = null; |
| | } |
| | $state->update($ad); |
| | $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf))); |
| | $state->update($ciphertext); |
| | $state->update(str_repeat("\x00", (0x10 - $clen) & 0xf)); |
| | $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen)); |
| | $state->update(ParagonIE_Sodium_Core32_Util::store64_le($clen)); |
| | $computed_mac = $state->finish(); |
| |
|
| | |
| | if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) { |
| | throw new SodiumException('Invalid MAC'); |
| | } |
| |
|
| | |
| | return ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( |
| | $ciphertext, |
| | $nonce, |
| | $key, |
| | ParagonIE_Sodium_Core32_Util::store64_le(1) |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function aead_chacha20poly1305_ietf_encrypt( |
| | $message = '', |
| | $ad = '', |
| | $nonce = '', |
| | $key = '' |
| | ) { |
| | |
| | $len = ParagonIE_Sodium_Core32_Util::strlen($message); |
| |
|
| | |
| | $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad); |
| |
|
| | |
| | $block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream( |
| | 32, |
| | $nonce, |
| | $key |
| | ); |
| | $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0); |
| | try { |
| | ParagonIE_Sodium_Compat::memzero($block0); |
| | } catch (SodiumException $ex) { |
| | $block0 = null; |
| | } |
| |
|
| | |
| | $ciphertext = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( |
| | $message, |
| | $nonce, |
| | $key, |
| | ParagonIE_Sodium_Core32_Util::store64_le(1) |
| | ); |
| |
|
| | $state->update($ad); |
| | $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf))); |
| | $state->update($ciphertext); |
| | $state->update(str_repeat("\x00", ((0x10 - $len) & 0xf))); |
| | $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen)); |
| | $state->update(ParagonIE_Sodium_Core32_Util::store64_le($len)); |
| | return $ciphertext . $state->finish(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function aead_xchacha20poly1305_ietf_decrypt( |
| | $message = '', |
| | $ad = '', |
| | $nonce = '', |
| | $key = '' |
| | ) { |
| | $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20( |
| | ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16), |
| | $key |
| | ); |
| | $nonceLast = "\x00\x00\x00\x00" . |
| | ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8); |
| |
|
| | return self::aead_chacha20poly1305_ietf_decrypt($message, $ad, $nonceLast, $subkey); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function aead_xchacha20poly1305_ietf_encrypt( |
| | $message = '', |
| | $ad = '', |
| | $nonce = '', |
| | $key = '' |
| | ) { |
| | $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20( |
| | ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16), |
| | $key |
| | ); |
| | $nonceLast = "\x00\x00\x00\x00" . |
| | ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8); |
| |
|
| | return self::aead_chacha20poly1305_ietf_encrypt($message, $ad, $nonceLast, $subkey); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function auth($message, $key) |
| | { |
| | return ParagonIE_Sodium_Core32_Util::substr( |
| | hash_hmac('sha512', $message, $key, true), |
| | 0, |
| | 32 |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function auth_verify($mac, $message, $key) |
| | { |
| | return ParagonIE_Sodium_Core32_Util::hashEquals( |
| | $mac, |
| | self::auth($message, $key) |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function box($plaintext, $nonce, $keypair) |
| | { |
| | return self::secretbox( |
| | $plaintext, |
| | $nonce, |
| | self::box_beforenm( |
| | self::box_secretkey($keypair), |
| | self::box_publickey($keypair) |
| | ) |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function box_seal($message, $publicKey) |
| | { |
| | |
| | $ephemeralKeypair = self::box_keypair(); |
| |
|
| | |
| | $ephemeralSK = self::box_secretkey($ephemeralKeypair); |
| |
|
| | |
| | $ephemeralPK = self::box_publickey($ephemeralKeypair); |
| |
|
| | |
| | $nonce = self::generichash( |
| | $ephemeralPK . $publicKey, |
| | '', |
| | 24 |
| | ); |
| |
|
| | |
| | $keypair = self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey); |
| |
|
| | |
| | $ciphertext = self::box($message, $nonce, $keypair); |
| | try { |
| | ParagonIE_Sodium_Compat::memzero($ephemeralKeypair); |
| | ParagonIE_Sodium_Compat::memzero($ephemeralSK); |
| | ParagonIE_Sodium_Compat::memzero($nonce); |
| | } catch (SodiumException $ex) { |
| | $ephemeralKeypair = null; |
| | $ephemeralSK = null; |
| | $nonce = null; |
| | } |
| | return $ephemeralPK . $ciphertext; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function box_seal_open($message, $keypair) |
| | { |
| | |
| | $ephemeralPK = ParagonIE_Sodium_Core32_Util::substr($message, 0, 32); |
| |
|
| | |
| | $ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 32); |
| |
|
| | |
| | $secretKey = self::box_secretkey($keypair); |
| |
|
| | |
| | $publicKey = self::box_publickey($keypair); |
| |
|
| | |
| | $nonce = self::generichash( |
| | $ephemeralPK . $publicKey, |
| | '', |
| | 24 |
| | ); |
| |
|
| | |
| | $keypair = self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK); |
| |
|
| | |
| | $m = self::box_open($ciphertext, $nonce, $keypair); |
| | try { |
| | ParagonIE_Sodium_Compat::memzero($secretKey); |
| | ParagonIE_Sodium_Compat::memzero($ephemeralPK); |
| | ParagonIE_Sodium_Compat::memzero($nonce); |
| | } catch (SodiumException $ex) { |
| | $secretKey = null; |
| | $ephemeralPK = null; |
| | $nonce = null; |
| | } |
| | return $m; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function box_beforenm($sk, $pk) |
| | { |
| | return ParagonIE_Sodium_Core32_HSalsa20::hsalsa20( |
| | str_repeat("\x00", 16), |
| | self::scalarmult($sk, $pk) |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function box_keypair() |
| | { |
| | $sKey = random_bytes(32); |
| | $pKey = self::scalarmult_base($sKey); |
| | return $sKey . $pKey; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function box_seed_keypair($seed) |
| | { |
| | $sKey = ParagonIE_Sodium_Core32_Util::substr( |
| | hash('sha512', $seed, true), |
| | 0, |
| | 32 |
| | ); |
| | $pKey = self::scalarmult_base($sKey); |
| | return $sKey . $pKey; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function box_keypair_from_secretkey_and_publickey($sKey, $pKey) |
| | { |
| | return ParagonIE_Sodium_Core32_Util::substr($sKey, 0, 32) . |
| | ParagonIE_Sodium_Core32_Util::substr($pKey, 0, 32); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function box_secretkey($keypair) |
| | { |
| | if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== 64) { |
| | throw new RangeException( |
| | 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.' |
| | ); |
| | } |
| | return ParagonIE_Sodium_Core32_Util::substr($keypair, 0, 32); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function box_publickey($keypair) |
| | { |
| | if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) { |
| | throw new RangeException( |
| | 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.' |
| | ); |
| | } |
| | return ParagonIE_Sodium_Core32_Util::substr($keypair, 32, 32); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function box_publickey_from_secretkey($sKey) |
| | { |
| | if (ParagonIE_Sodium_Core32_Util::strlen($sKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) { |
| | throw new RangeException( |
| | 'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.' |
| | ); |
| | } |
| | return self::scalarmult_base($sKey); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function box_open($ciphertext, $nonce, $keypair) |
| | { |
| | return self::secretbox_open( |
| | $ciphertext, |
| | $nonce, |
| | self::box_beforenm( |
| | self::box_secretkey($keypair), |
| | self::box_publickey($keypair) |
| | ) |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function generichash($message, $key = '', $outlen = 32) |
| | { |
| | |
| | ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor(); |
| |
|
| | $k = null; |
| | if (!empty($key)) { |
| | |
| | $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key); |
| | if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) { |
| | throw new RangeException('Invalid key size'); |
| | } |
| | } |
| |
|
| | |
| | $in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message); |
| |
|
| | |
| | $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outlen); |
| | ParagonIE_Sodium_Core32_BLAKE2b::update($ctx, $in, $in->count()); |
| |
|
| | |
| | $out = new SplFixedArray($outlen); |
| | $out = ParagonIE_Sodium_Core32_BLAKE2b::finish($ctx, $out); |
| |
|
| | |
| | $outArray = $out->toArray(); |
| | return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function generichash_final($ctx, $outlen = 32) |
| | { |
| | if (!is_string($ctx)) { |
| | throw new TypeError('Context must be a string'); |
| | } |
| | $out = new SplFixedArray($outlen); |
| |
|
| | |
| | $context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx); |
| |
|
| | |
| | $out = ParagonIE_Sodium_Core32_BLAKE2b::finish($context, $out); |
| |
|
| | |
| | $outArray = $out->toArray(); |
| | return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function generichash_init($key = '', $outputLength = 32) |
| | { |
| | |
| | ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor(); |
| |
|
| | $k = null; |
| | if (!empty($key)) { |
| | $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key); |
| | if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) { |
| | throw new RangeException('Invalid key size'); |
| | } |
| | } |
| |
|
| | |
| | $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength); |
| |
|
| | return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function generichash_init_salt_personal( |
| | $key = '', |
| | $outputLength = 32, |
| | $salt = '', |
| | $personal = '' |
| | ) { |
| | |
| | ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor(); |
| |
|
| | $k = null; |
| | if (!empty($key)) { |
| | $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key); |
| | if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) { |
| | throw new RangeException('Invalid key size'); |
| | } |
| | } |
| | if (!empty($salt)) { |
| | $s = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($salt); |
| | } else { |
| | $s = null; |
| | } |
| | if (!empty($salt)) { |
| | $p = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($personal); |
| | } else { |
| | $p = null; |
| | } |
| |
|
| | |
| | $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength, $s, $p); |
| |
|
| | return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function generichash_update($ctx, $message) |
| | { |
| | |
| | ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor(); |
| |
|
| | |
| | $context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx); |
| |
|
| | |
| | $in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message); |
| |
|
| | ParagonIE_Sodium_Core32_BLAKE2b::update($context, $in, $in->count()); |
| |
|
| | return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($context); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function keyExchange($my_sk, $their_pk, $client_pk, $server_pk) |
| | { |
| | return self::generichash( |
| | self::scalarmult($my_sk, $their_pk) . |
| | $client_pk . |
| | $server_pk |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function scalarmult($sKey, $pKey) |
| | { |
| | $q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10($sKey, $pKey); |
| | self::scalarmult_throw_if_zero($q); |
| | return $q; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function scalarmult_base($secret) |
| | { |
| | $q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10_base($secret); |
| | self::scalarmult_throw_if_zero($q); |
| | return $q; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | protected static function scalarmult_throw_if_zero($q) |
| | { |
| | $d = 0; |
| | for ($i = 0; $i < self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) { |
| | $d |= ParagonIE_Sodium_Core32_Util::chrToInt($q[$i]); |
| | } |
| |
|
| | |
| | if (-(1 & (($d - 1) >> 8))) { |
| | throw new SodiumException('Zero public key is not allowed'); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function secretbox($plaintext, $nonce, $key) |
| | { |
| | |
| | $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key); |
| |
|
| | |
| | $block0 = str_repeat("\x00", 32); |
| |
|
| | |
| | $mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext); |
| | $mlen0 = $mlen; |
| | if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) { |
| | $mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES; |
| | } |
| | $block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0); |
| |
|
| | |
| | $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor( |
| | $block0, |
| | ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), |
| | $subkey |
| | ); |
| |
|
| | |
| | $c = ParagonIE_Sodium_Core32_Util::substr( |
| | $block0, |
| | self::secretbox_xsalsa20poly1305_ZEROBYTES |
| | ); |
| | if ($mlen > $mlen0) { |
| | $c .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic( |
| | ParagonIE_Sodium_Core32_Util::substr( |
| | $plaintext, |
| | self::secretbox_xsalsa20poly1305_ZEROBYTES |
| | ), |
| | ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), |
| | 1, |
| | $subkey |
| | ); |
| | } |
| | $state = new ParagonIE_Sodium_Core32_Poly1305_State( |
| | ParagonIE_Sodium_Core32_Util::substr( |
| | $block0, |
| | 0, |
| | self::onetimeauth_poly1305_KEYBYTES |
| | ) |
| | ); |
| | try { |
| | ParagonIE_Sodium_Compat::memzero($block0); |
| | ParagonIE_Sodium_Compat::memzero($subkey); |
| | } catch (SodiumException $ex) { |
| | $block0 = null; |
| | $subkey = null; |
| | } |
| |
|
| | $state->update($c); |
| |
|
| | |
| | $c = $state->finish() . $c; |
| | unset($state); |
| |
|
| | return $c; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function secretbox_open($ciphertext, $nonce, $key) |
| | { |
| | |
| | $mac = ParagonIE_Sodium_Core32_Util::substr( |
| | $ciphertext, |
| | 0, |
| | self::secretbox_xsalsa20poly1305_MACBYTES |
| | ); |
| |
|
| | |
| | $c = ParagonIE_Sodium_Core32_Util::substr( |
| | $ciphertext, |
| | self::secretbox_xsalsa20poly1305_MACBYTES |
| | ); |
| |
|
| | |
| | $clen = ParagonIE_Sodium_Core32_Util::strlen($c); |
| |
|
| | |
| | $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key); |
| |
|
| | |
| | $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20( |
| | 64, |
| | ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), |
| | $subkey |
| | ); |
| | $verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify( |
| | $mac, |
| | $c, |
| | ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32) |
| | ); |
| | if (!$verified) { |
| | try { |
| | ParagonIE_Sodium_Compat::memzero($subkey); |
| | } catch (SodiumException $ex) { |
| | $subkey = null; |
| | } |
| | throw new SodiumException('Invalid MAC'); |
| | } |
| |
|
| | |
| | $m = ParagonIE_Sodium_Core32_Util::xorStrings( |
| | ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES), |
| | ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xsalsa20poly1305_ZEROBYTES) |
| | ); |
| | if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) { |
| | |
| | $m .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic( |
| | ParagonIE_Sodium_Core32_Util::substr( |
| | $c, |
| | self::secretbox_xsalsa20poly1305_ZEROBYTES |
| | ), |
| | ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), |
| | 1, |
| | (string) $subkey |
| | ); |
| | } |
| | return $m; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function secretbox_xchacha20poly1305($plaintext, $nonce, $key) |
| | { |
| | |
| | $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20( |
| | ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16), |
| | $key |
| | ); |
| | $nonceLast = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8); |
| |
|
| | |
| | $block0 = str_repeat("\x00", 32); |
| |
|
| | |
| | $mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext); |
| | $mlen0 = $mlen; |
| | if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) { |
| | $mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES; |
| | } |
| | $block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0); |
| |
|
| | |
| | $block0 = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( |
| | $block0, |
| | $nonceLast, |
| | $subkey |
| | ); |
| |
|
| | |
| | $c = ParagonIE_Sodium_Core32_Util::substr( |
| | $block0, |
| | self::secretbox_xchacha20poly1305_ZEROBYTES |
| | ); |
| | if ($mlen > $mlen0) { |
| | $c .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( |
| | ParagonIE_Sodium_Core32_Util::substr( |
| | $plaintext, |
| | self::secretbox_xchacha20poly1305_ZEROBYTES |
| | ), |
| | $nonceLast, |
| | $subkey, |
| | ParagonIE_Sodium_Core32_Util::store64_le(1) |
| | ); |
| | } |
| | $state = new ParagonIE_Sodium_Core32_Poly1305_State( |
| | ParagonIE_Sodium_Core32_Util::substr( |
| | $block0, |
| | 0, |
| | self::onetimeauth_poly1305_KEYBYTES |
| | ) |
| | ); |
| | try { |
| | ParagonIE_Sodium_Compat::memzero($block0); |
| | ParagonIE_Sodium_Compat::memzero($subkey); |
| | } catch (SodiumException $ex) { |
| | $block0 = null; |
| | $subkey = null; |
| | } |
| |
|
| | $state->update($c); |
| |
|
| | |
| | $c = $state->finish() . $c; |
| | unset($state); |
| |
|
| | return $c; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key) |
| | { |
| | |
| | $mac = ParagonIE_Sodium_Core32_Util::substr( |
| | $ciphertext, |
| | 0, |
| | self::secretbox_xchacha20poly1305_MACBYTES |
| | ); |
| |
|
| | |
| | $c = ParagonIE_Sodium_Core32_Util::substr( |
| | $ciphertext, |
| | self::secretbox_xchacha20poly1305_MACBYTES |
| | ); |
| |
|
| | |
| | $clen = ParagonIE_Sodium_Core32_Util::strlen($c); |
| |
|
| | |
| | $subkey = ParagonIE_Sodium_Core32_HChaCha20::hchacha20($nonce, $key); |
| |
|
| | |
| | $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream( |
| | 64, |
| | ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), |
| | $subkey |
| | ); |
| | $verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify( |
| | $mac, |
| | $c, |
| | ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32) |
| | ); |
| |
|
| | if (!$verified) { |
| | try { |
| | ParagonIE_Sodium_Compat::memzero($subkey); |
| | } catch (SodiumException $ex) { |
| | $subkey = null; |
| | } |
| | throw new SodiumException('Invalid MAC'); |
| | } |
| |
|
| | |
| | $m = ParagonIE_Sodium_Core32_Util::xorStrings( |
| | ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES), |
| | ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xchacha20poly1305_ZEROBYTES) |
| | ); |
| |
|
| | if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) { |
| | |
| | $m .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( |
| | ParagonIE_Sodium_Core32_Util::substr( |
| | $c, |
| | self::secretbox_xchacha20poly1305_ZEROBYTES |
| | ), |
| | ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), |
| | (string) $subkey, |
| | ParagonIE_Sodium_Core32_Util::store64_le(1) |
| | ); |
| | } |
| | return $m; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function secretstream_xchacha20poly1305_init_push($key) |
| | { |
| | |
| | $out = random_bytes(24); |
| |
|
| | |
| | $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20($out, $key); |
| | $state = new ParagonIE_Sodium_Core32_SecretStream_State( |
| | $subkey, |
| | ParagonIE_Sodium_Core32_Util::substr($out, 16, 8) . str_repeat("\0", 4) |
| | ); |
| |
|
| | |
| | $state->counterReset(); |
| |
|
| | |
| | |
| | |
| | return array( |
| | $state->toString(), |
| | $out |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function secretstream_xchacha20poly1305_init_pull($key, $header) |
| | { |
| | |
| | $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20( |
| | ParagonIE_Sodium_Core32_Util::substr($header, 0, 16), |
| | $key |
| | ); |
| | $state = new ParagonIE_Sodium_Core32_SecretStream_State( |
| | $subkey, |
| | ParagonIE_Sodium_Core32_Util::substr($header, 16) |
| | ); |
| | $state->counterReset(); |
| | |
| | |
| | |
| | |
| | return $state->toString(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0) |
| | { |
| | $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state); |
| | |
| | |
| | |
| | |
| | |
| |
|
| | $msglen = ParagonIE_Sodium_Core32_Util::strlen($msg); |
| | $aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad); |
| |
|
| | if ((($msglen + 63) >> 6) > 0xfffffffe) { |
| | throw new SodiumException( |
| | 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes' |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | $auth = new ParagonIE_Sodium_Core32_Poly1305_State( |
| | ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey()) |
| | ); |
| |
|
| | |
| | $auth->update($aad); |
| |
|
| | |
| | |
| | $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf))); |
| |
|
| | |
| | |
| | |
| | |
| | $block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( |
| | ParagonIE_Sodium_Core32_Util::intToChr($tag) . str_repeat("\0", 63), |
| | $st->getCombinedNonce(), |
| | $st->getKey(), |
| | ParagonIE_Sodium_Core32_Util::store64_le(1) |
| | ); |
| |
|
| | |
| | $auth->update($block); |
| |
|
| | |
| | $out = $block[0]; |
| | |
| | |
| | $cipher = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( |
| | $msg, |
| | $st->getCombinedNonce(), |
| | $st->getKey(), |
| | ParagonIE_Sodium_Core32_Util::store64_le(2) |
| | ); |
| |
|
| | |
| | $auth->update($cipher); |
| |
|
| | $out .= $cipher; |
| | unset($cipher); |
| |
|
| | |
| | |
| | $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf))); |
| |
|
| | |
| | $slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen); |
| |
|
| | |
| | $auth->update($slen); |
| |
|
| | |
| | $slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen); |
| |
|
| | |
| | $auth->update($slen); |
| |
|
| | |
| | |
| | $mac = $auth->finish(); |
| | $out .= $mac; |
| |
|
| | |
| | unset($auth); |
| |
|
| |
|
| | |
| | |
| | $st->xorNonce($mac); |
| |
|
| | |
| | |
| | $st->incrementCounter(); |
| | |
| | $state = $st->toString(); |
| |
|
| | |
| | $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0; |
| | |
| | |
| | |
| | |
| | |
| | if ($rekey || $st->needsRekey()) { |
| | |
| | self::secretstream_xchacha20poly1305_rekey($state); |
| | } |
| | |
| | |
| | |
| | return $out; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '') |
| | { |
| | $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state); |
| |
|
| | $cipherlen = ParagonIE_Sodium_Core32_Util::strlen($cipher); |
| | |
| | $msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES; |
| | $aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad); |
| |
|
| | |
| | |
| | |
| | if ((($msglen + 63) >> 6) > 0xfffffffe) { |
| | throw new SodiumException( |
| | 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes' |
| | ); |
| | } |
| |
|
| | |
| | |
| | |
| | $auth = new ParagonIE_Sodium_Core32_Poly1305_State( |
| | ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey()) |
| | ); |
| |
|
| | |
| | $auth->update($aad); |
| |
|
| | |
| | |
| | $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf))); |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | $block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( |
| | $cipher[0] . str_repeat("\0", 63), |
| | $st->getCombinedNonce(), |
| | $st->getKey(), |
| | ParagonIE_Sodium_Core32_Util::store64_le(1) |
| | ); |
| | |
| | |
| | |
| | $tag = ParagonIE_Sodium_Core32_Util::chrToInt($block[0]); |
| | $block[0] = $cipher[0]; |
| | $auth->update($block); |
| |
|
| |
|
| | |
| | |
| | $auth->update(ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen)); |
| |
|
| | |
| | |
| | $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf))); |
| |
|
| | |
| | |
| | $slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen); |
| | $auth->update($slen); |
| |
|
| | |
| | |
| | $slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen); |
| | $auth->update($slen); |
| |
|
| | |
| | |
| | $mac = $auth->finish(); |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | $stored = ParagonIE_Sodium_Core32_Util::substr($cipher, $msglen + 1, 16); |
| | if (!ParagonIE_Sodium_Core32_Util::hashEquals($mac, $stored)) { |
| | return false; |
| | } |
| |
|
| | |
| | $out = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( |
| | ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen), |
| | $st->getCombinedNonce(), |
| | $st->getKey(), |
| | ParagonIE_Sodium_Core32_Util::store64_le(2) |
| | ); |
| |
|
| | |
| | |
| | $st->xorNonce($mac); |
| |
|
| | |
| | |
| | $st->incrementCounter(); |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | $state = $st->toString(); |
| |
|
| | |
| | $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0; |
| | if ($rekey || $st->needsRekey()) { |
| | |
| | self::secretstream_xchacha20poly1305_rekey($state); |
| | } |
| | return array($out, $tag); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | public static function secretstream_xchacha20poly1305_rekey(&$state) |
| | { |
| | $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state); |
| | |
| | |
| | |
| | |
| | |
| | |
| | $new_key_and_inonce = $st->getKey(); |
| |
|
| | |
| | |
| | |
| | |
| | $new_key_and_inonce .= ParagonIE_Sodium_Core32_Util::substR($st->getNonce(), 0, 8); |
| |
|
| | |
| | |
| | |
| |
|
| | $st->rekey(ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( |
| | $new_key_and_inonce, |
| | $st->getCombinedNonce(), |
| | $st->getKey(), |
| | ParagonIE_Sodium_Core32_Util::store64_le(0) |
| | )); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | $st->counterReset(); |
| |
|
| | $state = $st->toString(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function sign_detached($message, $sk) |
| | { |
| | return ParagonIE_Sodium_Core32_Ed25519::sign_detached($message, $sk); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function sign($message, $sk) |
| | { |
| | return ParagonIE_Sodium_Core32_Ed25519::sign($message, $sk); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function sign_open($signedMessage, $pk) |
| | { |
| | return ParagonIE_Sodium_Core32_Ed25519::sign_open($signedMessage, $pk); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function sign_verify_detached($signature, $message, $pk) |
| | { |
| | return ParagonIE_Sodium_Core32_Ed25519::verify_detached($signature, $message, $pk); |
| | } |
| | } |
| |
|