| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655 |
- <?php
- if (class_exists('ParagonIE_Sodium_Crypto32', false)) {
- return;
- }
- /**
- * Class ParagonIE_Sodium_Crypto
- *
- * ATTENTION!
- *
- * If you are using this library, you should be using
- * ParagonIE_Sodium_Compat in your code, not this class.
- */
- 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;
- /**
- * AEAD Decryption with ChaCha20-Poly1305
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $message
- * @param string $ad
- * @param string $nonce
- * @param string $key
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function aead_chacha20poly1305_decrypt(
- $message = '',
- $ad = '',
- $nonce = '',
- $key = ''
- ) {
- /** @var int $len - Length of message (ciphertext + MAC) */
- $len = ParagonIE_Sodium_Core32_Util::strlen($message);
- /** @var int $clen - Length of ciphertext */
- $clen = $len - self::aead_chacha20poly1305_ABYTES;
- /** @var int $adlen - Length of associated data */
- $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
- /** @var string $mac - Message authentication code */
- $mac = ParagonIE_Sodium_Core32_Util::substr(
- $message,
- $clen,
- self::aead_chacha20poly1305_ABYTES
- );
- /** @var string $ciphertext - The encrypted message (sans MAC) */
- $ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 0, $clen);
- /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
- $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(
- 32,
- $nonce,
- $key
- );
- /* Recalculate the Poly1305 authentication tag (MAC): */
- $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();
- /* Compare the given MAC with the recalculated MAC: */
- if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) {
- throw new SodiumException('Invalid MAC');
- }
- // Here, we know that the MAC is valid, so we decrypt and return the plaintext
- return ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
- $ciphertext,
- $nonce,
- $key,
- ParagonIE_Sodium_Core32_Util::store64_le(1)
- );
- }
- /**
- * AEAD Encryption with ChaCha20-Poly1305
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $message
- * @param string $ad
- * @param string $nonce
- * @param string $key
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function aead_chacha20poly1305_encrypt(
- $message = '',
- $ad = '',
- $nonce = '',
- $key = ''
- ) {
- /** @var int $len - Length of the plaintext message */
- $len = ParagonIE_Sodium_Core32_Util::strlen($message);
- /** @var int $adlen - Length of the associated data */
- $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
- /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
- $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;
- }
- /** @var string $ciphertext - Raw encrypted data */
- $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();
- }
- /**
- * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $message
- * @param string $ad
- * @param string $nonce
- * @param string $key
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function aead_chacha20poly1305_ietf_decrypt(
- $message = '',
- $ad = '',
- $nonce = '',
- $key = ''
- ) {
- /** @var int $adlen - Length of associated data */
- $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
- /** @var int $len - Length of message (ciphertext + MAC) */
- $len = ParagonIE_Sodium_Core32_Util::strlen($message);
- /** @var int $clen - Length of ciphertext */
- $clen = $len - self::aead_chacha20poly1305_IETF_ABYTES;
- /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
- $block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream(
- 32,
- $nonce,
- $key
- );
- /** @var string $mac - Message authentication code */
- $mac = ParagonIE_Sodium_Core32_Util::substr(
- $message,
- $len - self::aead_chacha20poly1305_IETF_ABYTES,
- self::aead_chacha20poly1305_IETF_ABYTES
- );
- /** @var string $ciphertext - The encrypted message (sans MAC) */
- $ciphertext = ParagonIE_Sodium_Core32_Util::substr(
- $message,
- 0,
- $len - self::aead_chacha20poly1305_IETF_ABYTES
- );
- /* Recalculate the Poly1305 authentication tag (MAC): */
- $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();
- /* Compare the given MAC with the recalculated MAC: */
- if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) {
- throw new SodiumException('Invalid MAC');
- }
- // Here, we know that the MAC is valid, so we decrypt and return the plaintext
- return ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
- $ciphertext,
- $nonce,
- $key,
- ParagonIE_Sodium_Core32_Util::store64_le(1)
- );
- }
- /**
- * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $message
- * @param string $ad
- * @param string $nonce
- * @param string $key
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function aead_chacha20poly1305_ietf_encrypt(
- $message = '',
- $ad = '',
- $nonce = '',
- $key = ''
- ) {
- /** @var int $len - Length of the plaintext message */
- $len = ParagonIE_Sodium_Core32_Util::strlen($message);
- /** @var int $adlen - Length of the associated data */
- $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
- /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
- $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;
- }
- /** @var string $ciphertext - Raw encrypted data */
- $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();
- }
- /**
- * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $message
- * @param string $ad
- * @param string $nonce
- * @param string $key
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- 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);
- }
- /**
- * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $message
- * @param string $ad
- * @param string $nonce
- * @param string $key
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- 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);
- }
- /**
- * HMAC-SHA-512-256 (a.k.a. the leftmost 256 bits of HMAC-SHA-512)
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $message
- * @param string $key
- * @return string
- * @throws TypeError
- */
- public static function auth($message, $key)
- {
- return ParagonIE_Sodium_Core32_Util::substr(
- hash_hmac('sha512', $message, $key, true),
- 0,
- 32
- );
- }
- /**
- * HMAC-SHA-512-256 validation. Constant-time via hash_equals().
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $mac
- * @param string $message
- * @param string $key
- * @return bool
- * @throws SodiumException
- * @throws TypeError
- */
- public static function auth_verify($mac, $message, $key)
- {
- return ParagonIE_Sodium_Core32_Util::hashEquals(
- $mac,
- self::auth($message, $key)
- );
- }
- /**
- * X25519 key exchange followed by XSalsa20Poly1305 symmetric encryption
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $plaintext
- * @param string $nonce
- * @param string $keypair
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function box($plaintext, $nonce, $keypair)
- {
- return self::secretbox(
- $plaintext,
- $nonce,
- self::box_beforenm(
- self::box_secretkey($keypair),
- self::box_publickey($keypair)
- )
- );
- }
- /**
- * X25519-XSalsa20-Poly1305 with one ephemeral X25519 keypair.
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $message
- * @param string $publicKey
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function box_seal($message, $publicKey)
- {
- /** @var string $ephemeralKeypair */
- $ephemeralKeypair = self::box_keypair();
- /** @var string $ephemeralSK */
- $ephemeralSK = self::box_secretkey($ephemeralKeypair);
- /** @var string $ephemeralPK */
- $ephemeralPK = self::box_publickey($ephemeralKeypair);
- /** @var string $nonce */
- $nonce = self::generichash(
- $ephemeralPK . $publicKey,
- '',
- 24
- );
- /** @var string $keypair - The combined keypair used in crypto_box() */
- $keypair = self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey);
- /** @var string $ciphertext Ciphertext + MAC from crypto_box */
- $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;
- }
- /**
- * Opens a message encrypted via box_seal().
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $message
- * @param string $keypair
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function box_seal_open($message, $keypair)
- {
- /** @var string $ephemeralPK */
- $ephemeralPK = ParagonIE_Sodium_Core32_Util::substr($message, 0, 32);
- /** @var string $ciphertext (ciphertext + MAC) */
- $ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 32);
- /** @var string $secretKey */
- $secretKey = self::box_secretkey($keypair);
- /** @var string $publicKey */
- $publicKey = self::box_publickey($keypair);
- /** @var string $nonce */
- $nonce = self::generichash(
- $ephemeralPK . $publicKey,
- '',
- 24
- );
- /** @var string $keypair */
- $keypair = self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK);
- /** @var string $m */
- $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;
- }
- /**
- * Used by crypto_box() to get the crypto_secretbox() key.
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $sk
- * @param string $pk
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function box_beforenm($sk, $pk)
- {
- return ParagonIE_Sodium_Core32_HSalsa20::hsalsa20(
- str_repeat("\x00", 16),
- self::scalarmult($sk, $pk)
- );
- }
- /**
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @return string
- * @throws Exception
- * @throws SodiumException
- * @throws TypeError
- */
- public static function box_keypair()
- {
- $sKey = random_bytes(32);
- $pKey = self::scalarmult_base($sKey);
- return $sKey . $pKey;
- }
- /**
- * @param string $seed
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- 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;
- }
- /**
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $sKey
- * @param string $pKey
- * @return string
- * @throws TypeError
- */
- 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);
- }
- /**
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $keypair
- * @return string
- * @throws RangeException
- * @throws TypeError
- */
- 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);
- }
- /**
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $keypair
- * @return string
- * @throws RangeException
- * @throws TypeError
- */
- 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);
- }
- /**
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $sKey
- * @return string
- * @throws RangeException
- * @throws SodiumException
- * @throws TypeError
- */
- 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);
- }
- /**
- * Decrypt a message encrypted with box().
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $ciphertext
- * @param string $nonce
- * @param string $keypair
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- 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)
- )
- );
- }
- /**
- * Calculate a BLAKE2b hash.
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $message
- * @param string|null $key
- * @param int $outlen
- * @return string
- * @throws RangeException
- * @throws SodiumException
- * @throws TypeError
- */
- public static function generichash($message, $key = '', $outlen = 32)
- {
- // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
- ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
- $k = null;
- if (!empty($key)) {
- /** @var SplFixedArray $k */
- $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
- if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
- throw new RangeException('Invalid key size');
- }
- }
- /** @var SplFixedArray $in */
- $in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message);
- /** @var SplFixedArray $ctx */
- $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outlen);
- ParagonIE_Sodium_Core32_BLAKE2b::update($ctx, $in, $in->count());
- /** @var SplFixedArray $out */
- $out = new SplFixedArray($outlen);
- $out = ParagonIE_Sodium_Core32_BLAKE2b::finish($ctx, $out);
- /** @var array<int, int> */
- $outArray = $out->toArray();
- return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray);
- }
- /**
- * Finalize a BLAKE2b hashing context, returning the hash.
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $ctx
- * @param int $outlen
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function generichash_final($ctx, $outlen = 32)
- {
- if (!is_string($ctx)) {
- throw new TypeError('Context must be a string');
- }
- $out = new SplFixedArray($outlen);
- /** @var SplFixedArray $context */
- $context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx);
- /** @var SplFixedArray $out */
- $out = ParagonIE_Sodium_Core32_BLAKE2b::finish($context, $out);
- /** @var array<int, int> */
- $outArray = $out->toArray();
- return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray);
- }
- /**
- * Initialize a hashing context for BLAKE2b.
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $key
- * @param int $outputLength
- * @return string
- * @throws RangeException
- * @throws SodiumException
- * @throws TypeError
- */
- public static function generichash_init($key = '', $outputLength = 32)
- {
- // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
- ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
- $k = null;
- if (!empty($key)) {
- $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
- if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
- throw new RangeException('Invalid key size');
- }
- }
- /** @var SplFixedArray $ctx */
- $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength);
- return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx);
- }
- /**
- * Initialize a hashing context for BLAKE2b.
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $key
- * @param int $outputLength
- * @param string $salt
- * @param string $personal
- * @return string
- * @throws RangeException
- * @throws SodiumException
- * @throws TypeError
- */
- public static function generichash_init_salt_personal(
- $key = '',
- $outputLength = 32,
- $salt = '',
- $personal = ''
- ) {
- // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
- ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
- $k = null;
- if (!empty($key)) {
- $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
- if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
- throw new RangeException('Invalid key size');
- }
- }
- if (!empty($salt)) {
- $s = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($salt);
- } else {
- $s = null;
- }
- if (!empty($salt)) {
- $p = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($personal);
- } else {
- $p = null;
- }
- /** @var SplFixedArray $ctx */
- $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength, $s, $p);
- return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx);
- }
- /**
- * Update a hashing context for BLAKE2b with $message
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $ctx
- * @param string $message
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function generichash_update($ctx, $message)
- {
- // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
- ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
- /** @var SplFixedArray $context */
- $context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx);
- /** @var SplFixedArray $in */
- $in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message);
- ParagonIE_Sodium_Core32_BLAKE2b::update($context, $in, $in->count());
- return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($context);
- }
- /**
- * Libsodium's crypto_kx().
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $my_sk
- * @param string $their_pk
- * @param string $client_pk
- * @param string $server_pk
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- 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
- );
- }
- /**
- * ECDH over Curve25519
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $sKey
- * @param string $pKey
- * @return string
- *
- * @throws SodiumException
- * @throws TypeError
- */
- 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;
- }
- /**
- * ECDH over Curve25519, using the basepoint.
- * Used to get a secret key from a public key.
- *
- * @param string $secret
- * @return string
- *
- * @throws SodiumException
- * @throws TypeError
- */
- 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;
- }
- /**
- * This throws an Error if a zero public key was passed to the function.
- *
- * @param string $q
- * @return void
- * @throws SodiumException
- * @throws TypeError
- */
- 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]);
- }
- /* branch-free variant of === 0 */
- if (-(1 & (($d - 1) >> 8))) {
- throw new SodiumException('Zero public key is not allowed');
- }
- }
- /**
- * XSalsa20-Poly1305 authenticated symmetric-key encryption.
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $plaintext
- * @param string $nonce
- * @param string $key
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function secretbox($plaintext, $nonce, $key)
- {
- /** @var string $subkey */
- $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
- /** @var string $block0 */
- $block0 = str_repeat("\x00", 32);
- /** @var int $mlen - Length of the plaintext message */
- $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);
- /** @var string $block0 */
- $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor(
- $block0,
- ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
- $subkey
- );
- /** @var string $c */
- $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);
- /** @var string $c - MAC || ciphertext */
- $c = $state->finish() . $c;
- unset($state);
- return $c;
- }
- /**
- * Decrypt a ciphertext generated via secretbox().
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $ciphertext
- * @param string $nonce
- * @param string $key
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function secretbox_open($ciphertext, $nonce, $key)
- {
- /** @var string $mac */
- $mac = ParagonIE_Sodium_Core32_Util::substr(
- $ciphertext,
- 0,
- self::secretbox_xsalsa20poly1305_MACBYTES
- );
- /** @var string $c */
- $c = ParagonIE_Sodium_Core32_Util::substr(
- $ciphertext,
- self::secretbox_xsalsa20poly1305_MACBYTES
- );
- /** @var int $clen */
- $clen = ParagonIE_Sodium_Core32_Util::strlen($c);
- /** @var string $subkey */
- $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
- /** @var string $block0 */
- $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');
- }
- /** @var string $m - Decrypted message */
- $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) {
- // We had more than 1 block, so let's continue to decrypt the rest.
- $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;
- }
- /**
- * XChaCha20-Poly1305 authenticated symmetric-key encryption.
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $plaintext
- * @param string $nonce
- * @param string $key
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function secretbox_xchacha20poly1305($plaintext, $nonce, $key)
- {
- /** @var string $subkey */
- $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
- ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16),
- $key
- );
- $nonceLast = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
- /** @var string $block0 */
- $block0 = str_repeat("\x00", 32);
- /** @var int $mlen - Length of the plaintext message */
- $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);
- /** @var string $block0 */
- $block0 = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
- $block0,
- $nonceLast,
- $subkey
- );
- /** @var string $c */
- $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);
- /** @var string $c - MAC || ciphertext */
- $c = $state->finish() . $c;
- unset($state);
- return $c;
- }
- /**
- * Decrypt a ciphertext generated via secretbox_xchacha20poly1305().
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $ciphertext
- * @param string $nonce
- * @param string $key
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key)
- {
- /** @var string $mac */
- $mac = ParagonIE_Sodium_Core32_Util::substr(
- $ciphertext,
- 0,
- self::secretbox_xchacha20poly1305_MACBYTES
- );
- /** @var string $c */
- $c = ParagonIE_Sodium_Core32_Util::substr(
- $ciphertext,
- self::secretbox_xchacha20poly1305_MACBYTES
- );
- /** @var int $clen */
- $clen = ParagonIE_Sodium_Core32_Util::strlen($c);
- /** @var string $subkey */
- $subkey = ParagonIE_Sodium_Core32_HChaCha20::hchacha20($nonce, $key);
- /** @var string $block0 */
- $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');
- }
- /** @var string $m - Decrypted message */
- $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) {
- // We had more than 1 block, so let's continue to decrypt the rest.
- $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;
- }
- /**
- * @param string $key
- * @return array<int, string> Returns a state and a header.
- * @throws Exception
- * @throws SodiumException
- */
- public static function secretstream_xchacha20poly1305_init_push($key)
- {
- # randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES);
- $out = random_bytes(24);
- # crypto_core_hchacha20(state->k, out, k, NULL);
- $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20($out, $key);
- $state = new ParagonIE_Sodium_Core32_SecretStream_State(
- $subkey,
- ParagonIE_Sodium_Core32_Util::substr($out, 16, 8) . str_repeat("\0", 4)
- );
- # _crypto_secretstream_xchacha20poly1305_counter_reset(state);
- $state->counterReset();
- # memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES,
- # crypto_secretstream_xchacha20poly1305_INONCEBYTES);
- # memset(state->_pad, 0, sizeof state->_pad);
- return array(
- $state->toString(),
- $out
- );
- }
- /**
- * @param string $key
- * @param string $header
- * @return string Returns a state.
- * @throws Exception
- */
- public static function secretstream_xchacha20poly1305_init_pull($key, $header)
- {
- # crypto_core_hchacha20(state->k, in, k, NULL);
- $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
- ParagonIE_Sodium_Core32_Util::substr($header, 0, 16),
- $key
- );
- $state = new ParagonIE_Sodium_Core32_SecretStream_State(
- $subkey,
- ParagonIE_Sodium_Core32_Util::substr($header, 16)
- );
- $state->counterReset();
- # memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES,
- # crypto_secretstream_xchacha20poly1305_INONCEBYTES);
- # memset(state->_pad, 0, sizeof state->_pad);
- # return 0;
- return $state->toString();
- }
- /**
- * @param string $state
- * @param string $msg
- * @param string $aad
- * @param int $tag
- * @return string
- * @throws SodiumException
- */
- public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
- {
- $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
- # crypto_onetimeauth_poly1305_state poly1305_state;
- # unsigned char block[64U];
- # unsigned char slen[8U];
- # unsigned char *c;
- # unsigned char *mac;
- $msglen = ParagonIE_Sodium_Core32_Util::strlen($msg);
- $aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad);
- if ((($msglen + 63) >> 6) > 0xfffffffe) {
- throw new SodiumException(
- 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
- );
- }
- # if (outlen_p != NULL) {
- # *outlen_p = 0U;
- # }
- # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
- # sodium_misuse();
- # }
- # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
- # crypto_onetimeauth_poly1305_init(&poly1305_state, block);
- # sodium_memzero(block, sizeof block);
- $auth = new ParagonIE_Sodium_Core32_Poly1305_State(
- ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
- );
- # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
- $auth->update($aad);
- # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
- # (0x10 - adlen) & 0xf);
- $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
- # memset(block, 0, sizeof block);
- # block[0] = tag;
- # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
- # state->nonce, 1U, state->k);
- $block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
- ParagonIE_Sodium_Core32_Util::intToChr($tag) . str_repeat("\0", 63),
- $st->getCombinedNonce(),
- $st->getKey(),
- ParagonIE_Sodium_Core32_Util::store64_le(1)
- );
- # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
- $auth->update($block);
- # out[0] = block[0];
- $out = $block[0];
- # c = out + (sizeof tag);
- # crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k);
- $cipher = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
- $msg,
- $st->getCombinedNonce(),
- $st->getKey(),
- ParagonIE_Sodium_Core32_Util::store64_le(2)
- );
- # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
- $auth->update($cipher);
- $out .= $cipher;
- unset($cipher);
- # crypto_onetimeauth_poly1305_update
- # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
- $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
- # STORE64_LE(slen, (uint64_t) adlen);
- $slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen);
- # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
- $auth->update($slen);
- # STORE64_LE(slen, (sizeof block) + mlen);
- $slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen);
- # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
- $auth->update($slen);
- # mac = c + mlen;
- # crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
- $mac = $auth->finish();
- $out .= $mac;
- # sodium_memzero(&poly1305_state, sizeof poly1305_state);
- unset($auth);
- # XOR_BUF(STATE_INONCE(state), mac,
- # crypto_secretstream_xchacha20poly1305_INONCEBYTES);
- $st->xorNonce($mac);
- # sodium_increment(STATE_COUNTER(state),
- # crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
- $st->incrementCounter();
- // Overwrite by reference:
- $state = $st->toString();
- /** @var bool $rekey */
- $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
- # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
- # sodium_is_zero(STATE_COUNTER(state),
- # crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
- # crypto_secretstream_xchacha20poly1305_rekey(state);
- # }
- if ($rekey || $st->needsRekey()) {
- // DO REKEY
- self::secretstream_xchacha20poly1305_rekey($state);
- }
- # if (outlen_p != NULL) {
- # *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen;
- # }
- return $out;
- }
- /**
- * @param string $state
- * @param string $cipher
- * @param string $aad
- * @return bool|array{0: string, 1: int}
- * @throws SodiumException
- */
- public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '')
- {
- $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
- $cipherlen = ParagonIE_Sodium_Core32_Util::strlen($cipher);
- # mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
- $msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
- $aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad);
- # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
- # sodium_misuse();
- # }
- if ((($msglen + 63) >> 6) > 0xfffffffe) {
- throw new SodiumException(
- 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
- );
- }
- # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
- # crypto_onetimeauth_poly1305_init(&poly1305_state, block);
- # sodium_memzero(block, sizeof block);
- $auth = new ParagonIE_Sodium_Core32_Poly1305_State(
- ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
- );
- # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
- $auth->update($aad);
- # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
- # (0x10 - adlen) & 0xf);
- $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
- # memset(block, 0, sizeof block);
- # block[0] = in[0];
- # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
- # state->nonce, 1U, state->k);
- $block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
- $cipher[0] . str_repeat("\0", 63),
- $st->getCombinedNonce(),
- $st->getKey(),
- ParagonIE_Sodium_Core32_Util::store64_le(1)
- );
- # tag = block[0];
- # block[0] = in[0];
- # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
- $tag = ParagonIE_Sodium_Core32_Util::chrToInt($block[0]);
- $block[0] = $cipher[0];
- $auth->update($block);
- # c = in + (sizeof tag);
- # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
- $auth->update(ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen));
- # crypto_onetimeauth_poly1305_update
- # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
- $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
- # STORE64_LE(slen, (uint64_t) adlen);
- # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
- $slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen);
- $auth->update($slen);
- # STORE64_LE(slen, (sizeof block) + mlen);
- # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
- $slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen);
- $auth->update($slen);
- # crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
- # sodium_memzero(&poly1305_state, sizeof poly1305_state);
- $mac = $auth->finish();
- # stored_mac = c + mlen;
- # if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
- # sodium_memzero(mac, sizeof mac);
- # return -1;
- # }
- $stored = ParagonIE_Sodium_Core32_Util::substr($cipher, $msglen + 1, 16);
- if (!ParagonIE_Sodium_Core32_Util::hashEquals($mac, $stored)) {
- return false;
- }
- # crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k);
- $out = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
- ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen),
- $st->getCombinedNonce(),
- $st->getKey(),
- ParagonIE_Sodium_Core32_Util::store64_le(2)
- );
- # XOR_BUF(STATE_INONCE(state), mac,
- # crypto_secretstream_xchacha20poly1305_INONCEBYTES);
- $st->xorNonce($mac);
- # sodium_increment(STATE_COUNTER(state),
- # crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
- $st->incrementCounter();
- # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
- # sodium_is_zero(STATE_COUNTER(state),
- # crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
- # crypto_secretstream_xchacha20poly1305_rekey(state);
- # }
- // Overwrite by reference:
- $state = $st->toString();
- /** @var bool $rekey */
- $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
- if ($rekey || $st->needsRekey()) {
- // DO REKEY
- self::secretstream_xchacha20poly1305_rekey($state);
- }
- return array($out, $tag);
- }
- /**
- * @param string $state
- * @return void
- * @throws SodiumException
- */
- public static function secretstream_xchacha20poly1305_rekey(&$state)
- {
- $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state);
- # unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES +
- # crypto_secretstream_xchacha20poly1305_INONCEBYTES];
- # size_t i;
- # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
- # new_key_and_inonce[i] = state->k[i];
- # }
- $new_key_and_inonce = $st->getKey();
- # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
- # new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] =
- # STATE_INONCE(state)[i];
- # }
- $new_key_and_inonce .= ParagonIE_Sodium_Core32_Util::substR($st->getNonce(), 0, 8);
- # crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce,
- # sizeof new_key_and_inonce,
- # state->nonce, state->k);
- $st->rekey(ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
- $new_key_and_inonce,
- $st->getCombinedNonce(),
- $st->getKey(),
- ParagonIE_Sodium_Core32_Util::store64_le(0)
- ));
- # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
- # state->k[i] = new_key_and_inonce[i];
- # }
- # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
- # STATE_INONCE(state)[i] =
- # new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i];
- # }
- # _crypto_secretstream_xchacha20poly1305_counter_reset(state);
- $st->counterReset();
- $state = $st->toString();
- }
- /**
- * Detached Ed25519 signature.
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $message
- * @param string $sk
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function sign_detached($message, $sk)
- {
- return ParagonIE_Sodium_Core32_Ed25519::sign_detached($message, $sk);
- }
- /**
- * Attached Ed25519 signature. (Returns a signed message.)
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $message
- * @param string $sk
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function sign($message, $sk)
- {
- return ParagonIE_Sodium_Core32_Ed25519::sign($message, $sk);
- }
- /**
- * Opens a signed message. If valid, returns the message.
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $signedMessage
- * @param string $pk
- * @return string
- * @throws SodiumException
- * @throws TypeError
- */
- public static function sign_open($signedMessage, $pk)
- {
- return ParagonIE_Sodium_Core32_Ed25519::sign_open($signedMessage, $pk);
- }
- /**
- * Verify a detached signature of a given message and public key.
- *
- * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
- *
- * @param string $signature
- * @param string $message
- * @param string $pk
- * @return bool
- * @throws SodiumException
- * @throws TypeError
- */
- public static function sign_verify_detached($signature, $message, $pk)
- {
- return ParagonIE_Sodium_Core32_Ed25519::verify_detached($signature, $message, $pk);
- }
- }
|