wp/wp-includes/sodium_compat/src/Crypto.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
   776 
   776 
   777         return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx);
   777         return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx);
   778     }
   778     }
   779 
   779 
   780     /**
   780     /**
       
   781      * Initialize a hashing context for BLAKE2b.
       
   782      *
       
   783      * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
       
   784      *
       
   785      * @param string $key
       
   786      * @param int $outputLength
       
   787      * @param string $salt
       
   788      * @param string $personal
       
   789      * @return string
       
   790      * @throws RangeException
       
   791      * @throws SodiumException
       
   792      * @throws TypeError
       
   793      */
       
   794     public static function generichash_init_salt_personal(
       
   795         $key = '',
       
   796         $outputLength = 32,
       
   797         $salt = '',
       
   798         $personal = ''
       
   799     ) {
       
   800         // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized
       
   801         ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
       
   802 
       
   803         $k = null;
       
   804         if (!empty($key)) {
       
   805             $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key);
       
   806             if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) {
       
   807                 throw new RangeException('Invalid key size');
       
   808             }
       
   809         }
       
   810         if (!empty($salt)) {
       
   811             $s = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($salt);
       
   812         } else {
       
   813             $s = null;
       
   814         }
       
   815         if (!empty($salt)) {
       
   816             $p = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($personal);
       
   817         } else {
       
   818             $p = null;
       
   819         }
       
   820 
       
   821         /** @var SplFixedArray $ctx */
       
   822         $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength, $s, $p);
       
   823 
       
   824         return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx);
       
   825     }
       
   826 
       
   827     /**
   781      * Update a hashing context for BLAKE2b with $message
   828      * Update a hashing context for BLAKE2b with $message
   782      *
   829      *
   783      * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
   830      * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
   784      *
   831      *
   785      * @param string $ctx
   832      * @param string $ctx
  1184         }
  1231         }
  1185         return $m;
  1232         return $m;
  1186     }
  1233     }
  1187 
  1234 
  1188     /**
  1235     /**
       
  1236      * @param string $key
       
  1237      * @return array<int, string> Returns a state and a header.
       
  1238      * @throws Exception
       
  1239      * @throws SodiumException
       
  1240      */
       
  1241     public static function secretstream_xchacha20poly1305_init_push($key)
       
  1242     {
       
  1243         # randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES);
       
  1244         $out = random_bytes(24);
       
  1245 
       
  1246         # crypto_core_hchacha20(state->k, out, k, NULL);
       
  1247         $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20($out, $key);
       
  1248         $state = new ParagonIE_Sodium_Core_SecretStream_State(
       
  1249             $subkey,
       
  1250             ParagonIE_Sodium_Core_Util::substr($out, 16, 8) . str_repeat("\0", 4)
       
  1251         );
       
  1252 
       
  1253         # _crypto_secretstream_xchacha20poly1305_counter_reset(state);
       
  1254         $state->counterReset();
       
  1255 
       
  1256         # memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES,
       
  1257         #        crypto_secretstream_xchacha20poly1305_INONCEBYTES);
       
  1258         # memset(state->_pad, 0, sizeof state->_pad);
       
  1259         return array(
       
  1260             $state->toString(),
       
  1261             $out
       
  1262         );
       
  1263     }
       
  1264 
       
  1265     /**
       
  1266      * @param string $key
       
  1267      * @param string $header
       
  1268      * @return string Returns a state.
       
  1269      * @throws Exception
       
  1270      */
       
  1271     public static function secretstream_xchacha20poly1305_init_pull($key, $header)
       
  1272     {
       
  1273         # crypto_core_hchacha20(state->k, in, k, NULL);
       
  1274         $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
       
  1275             ParagonIE_Sodium_Core_Util::substr($header, 0, 16),
       
  1276             $key
       
  1277         );
       
  1278         $state = new ParagonIE_Sodium_Core_SecretStream_State(
       
  1279             $subkey,
       
  1280             ParagonIE_Sodium_Core_Util::substr($header, 16)
       
  1281         );
       
  1282         $state->counterReset();
       
  1283         # memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES,
       
  1284         #     crypto_secretstream_xchacha20poly1305_INONCEBYTES);
       
  1285         # memset(state->_pad, 0, sizeof state->_pad);
       
  1286         # return 0;
       
  1287         return $state->toString();
       
  1288     }
       
  1289 
       
  1290     /**
       
  1291      * @param string $state
       
  1292      * @param string $msg
       
  1293      * @param string $aad
       
  1294      * @param int $tag
       
  1295      * @return string
       
  1296      * @throws SodiumException
       
  1297      */
       
  1298     public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
       
  1299     {
       
  1300         $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
       
  1301         # crypto_onetimeauth_poly1305_state poly1305_state;
       
  1302         # unsigned char                     block[64U];
       
  1303         # unsigned char                     slen[8U];
       
  1304         # unsigned char                    *c;
       
  1305         # unsigned char                    *mac;
       
  1306 
       
  1307         $msglen = ParagonIE_Sodium_Core_Util::strlen($msg);
       
  1308         $aadlen = ParagonIE_Sodium_Core_Util::strlen($aad);
       
  1309 
       
  1310         if ((($msglen + 63) >> 6) > 0xfffffffe) {
       
  1311             throw new SodiumException(
       
  1312                 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
       
  1313             );
       
  1314         }
       
  1315 
       
  1316         # if (outlen_p != NULL) {
       
  1317         #     *outlen_p = 0U;
       
  1318         # }
       
  1319         # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
       
  1320         #     sodium_misuse();
       
  1321         # }
       
  1322 
       
  1323         # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
       
  1324         # crypto_onetimeauth_poly1305_init(&poly1305_state, block);
       
  1325         # sodium_memzero(block, sizeof block);
       
  1326         $auth = new ParagonIE_Sodium_Core_Poly1305_State(
       
  1327             ParagonIE_Sodium_Core_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
       
  1328         );
       
  1329 
       
  1330         # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
       
  1331         $auth->update($aad);
       
  1332 
       
  1333         # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
       
  1334         #     (0x10 - adlen) & 0xf);
       
  1335         $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
       
  1336 
       
  1337         # memset(block, 0, sizeof block);
       
  1338         # block[0] = tag;
       
  1339         # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
       
  1340         #                                    state->nonce, 1U, state->k);
       
  1341         $block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
       
  1342             ParagonIE_Sodium_Core_Util::intToChr($tag) . str_repeat("\0", 63),
       
  1343             $st->getCombinedNonce(),
       
  1344             $st->getKey(),
       
  1345             ParagonIE_Sodium_Core_Util::store64_le(1)
       
  1346         );
       
  1347 
       
  1348         # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
       
  1349         $auth->update($block);
       
  1350 
       
  1351         # out[0] = block[0];
       
  1352         $out = $block[0];
       
  1353         # c = out + (sizeof tag);
       
  1354         # crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k);
       
  1355         $cipher = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
       
  1356             $msg,
       
  1357             $st->getCombinedNonce(),
       
  1358             $st->getKey(),
       
  1359             ParagonIE_Sodium_Core_Util::store64_le(2)
       
  1360         );
       
  1361 
       
  1362         # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
       
  1363         $auth->update($cipher);
       
  1364 
       
  1365         $out .= $cipher;
       
  1366         unset($cipher);
       
  1367 
       
  1368         # crypto_onetimeauth_poly1305_update
       
  1369         # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
       
  1370         $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
       
  1371 
       
  1372         # STORE64_LE(slen, (uint64_t) adlen);
       
  1373         $slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen);
       
  1374 
       
  1375         # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
       
  1376         $auth->update($slen);
       
  1377 
       
  1378         # STORE64_LE(slen, (sizeof block) + mlen);
       
  1379         $slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen);
       
  1380 
       
  1381         # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
       
  1382         $auth->update($slen);
       
  1383 
       
  1384         # mac = c + mlen;
       
  1385         # crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
       
  1386         $mac = $auth->finish();
       
  1387         $out .= $mac;
       
  1388 
       
  1389         # sodium_memzero(&poly1305_state, sizeof poly1305_state);
       
  1390         unset($auth);
       
  1391 
       
  1392 
       
  1393         # XOR_BUF(STATE_INONCE(state), mac,
       
  1394         #     crypto_secretstream_xchacha20poly1305_INONCEBYTES);
       
  1395         $st->xorNonce($mac);
       
  1396 
       
  1397         # sodium_increment(STATE_COUNTER(state),
       
  1398         #     crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
       
  1399         $st->incrementCounter();
       
  1400         // Overwrite by reference:
       
  1401         $state = $st->toString();
       
  1402 
       
  1403         /** @var bool $rekey */
       
  1404         $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
       
  1405         # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
       
  1406         #     sodium_is_zero(STATE_COUNTER(state),
       
  1407         #         crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
       
  1408         #     crypto_secretstream_xchacha20poly1305_rekey(state);
       
  1409         # }
       
  1410         if ($rekey || $st->needsRekey()) {
       
  1411             // DO REKEY
       
  1412             self::secretstream_xchacha20poly1305_rekey($state);
       
  1413         }
       
  1414         # if (outlen_p != NULL) {
       
  1415         #     *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen;
       
  1416         # }
       
  1417         return $out;
       
  1418     }
       
  1419 
       
  1420     /**
       
  1421      * @param string $state
       
  1422      * @param string $cipher
       
  1423      * @param string $aad
       
  1424      * @return bool|array{0: string, 1: int}
       
  1425      * @throws SodiumException
       
  1426      */
       
  1427     public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '')
       
  1428     {
       
  1429         $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
       
  1430 
       
  1431         $cipherlen = ParagonIE_Sodium_Core_Util::strlen($cipher);
       
  1432         #     mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
       
  1433         $msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
       
  1434         $aadlen = ParagonIE_Sodium_Core_Util::strlen($aad);
       
  1435 
       
  1436         #     if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
       
  1437         #         sodium_misuse();
       
  1438         #     }
       
  1439         if ((($msglen + 63) >> 6) > 0xfffffffe) {
       
  1440             throw new SodiumException(
       
  1441                 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
       
  1442             );
       
  1443         }
       
  1444 
       
  1445         #     crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
       
  1446         #     crypto_onetimeauth_poly1305_init(&poly1305_state, block);
       
  1447         #     sodium_memzero(block, sizeof block);
       
  1448         $auth = new ParagonIE_Sodium_Core_Poly1305_State(
       
  1449             ParagonIE_Sodium_Core_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
       
  1450         );
       
  1451 
       
  1452         #     crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
       
  1453         $auth->update($aad);
       
  1454 
       
  1455         #     crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
       
  1456         #         (0x10 - adlen) & 0xf);
       
  1457         $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
       
  1458 
       
  1459 
       
  1460         #     memset(block, 0, sizeof block);
       
  1461         #     block[0] = in[0];
       
  1462         #     crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
       
  1463         #                                        state->nonce, 1U, state->k);
       
  1464         $block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
       
  1465             $cipher[0] . str_repeat("\0", 63),
       
  1466             $st->getCombinedNonce(),
       
  1467             $st->getKey(),
       
  1468             ParagonIE_Sodium_Core_Util::store64_le(1)
       
  1469         );
       
  1470         #     tag = block[0];
       
  1471         #     block[0] = in[0];
       
  1472         #     crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
       
  1473         $tag = ParagonIE_Sodium_Core_Util::chrToInt($block[0]);
       
  1474         $block[0] = $cipher[0];
       
  1475         $auth->update($block);
       
  1476 
       
  1477 
       
  1478         #     c = in + (sizeof tag);
       
  1479         #     crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
       
  1480         $auth->update(ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen));
       
  1481 
       
  1482         #     crypto_onetimeauth_poly1305_update
       
  1483         #     (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
       
  1484         $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
       
  1485 
       
  1486         #     STORE64_LE(slen, (uint64_t) adlen);
       
  1487         #     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
       
  1488         $slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen);
       
  1489         $auth->update($slen);
       
  1490 
       
  1491         #     STORE64_LE(slen, (sizeof block) + mlen);
       
  1492         #     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
       
  1493         $slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen);
       
  1494         $auth->update($slen);
       
  1495 
       
  1496         #     crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
       
  1497         #     sodium_memzero(&poly1305_state, sizeof poly1305_state);
       
  1498         $mac = $auth->finish();
       
  1499 
       
  1500         #     stored_mac = c + mlen;
       
  1501         #     if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
       
  1502         #     sodium_memzero(mac, sizeof mac);
       
  1503         #         return -1;
       
  1504         #     }
       
  1505 
       
  1506         $stored = ParagonIE_Sodium_Core_Util::substr($cipher, $msglen + 1, 16);
       
  1507         if (!ParagonIE_Sodium_Core_Util::hashEquals($mac, $stored)) {
       
  1508             return false;
       
  1509         }
       
  1510 
       
  1511         #     crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k);
       
  1512         $out = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
       
  1513             ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen),
       
  1514             $st->getCombinedNonce(),
       
  1515             $st->getKey(),
       
  1516             ParagonIE_Sodium_Core_Util::store64_le(2)
       
  1517         );
       
  1518 
       
  1519         #     XOR_BUF(STATE_INONCE(state), mac,
       
  1520         #         crypto_secretstream_xchacha20poly1305_INONCEBYTES);
       
  1521         $st->xorNonce($mac);
       
  1522 
       
  1523         #     sodium_increment(STATE_COUNTER(state),
       
  1524         #         crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
       
  1525         $st->incrementCounter();
       
  1526 
       
  1527         #     if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
       
  1528         #         sodium_is_zero(STATE_COUNTER(state),
       
  1529         #             crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
       
  1530         #         crypto_secretstream_xchacha20poly1305_rekey(state);
       
  1531         #     }
       
  1532 
       
  1533         // Overwrite by reference:
       
  1534         $state = $st->toString();
       
  1535 
       
  1536         /** @var bool $rekey */
       
  1537         $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
       
  1538         if ($rekey || $st->needsRekey()) {
       
  1539             // DO REKEY
       
  1540             self::secretstream_xchacha20poly1305_rekey($state);
       
  1541         }
       
  1542         return array($out, $tag);
       
  1543     }
       
  1544 
       
  1545     /**
       
  1546      * @param string $state
       
  1547      * @return void
       
  1548      * @throws SodiumException
       
  1549      */
       
  1550     public static function secretstream_xchacha20poly1305_rekey(&$state)
       
  1551     {
       
  1552         $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
       
  1553         # unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES +
       
  1554         # crypto_secretstream_xchacha20poly1305_INONCEBYTES];
       
  1555         # size_t        i;
       
  1556         # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
       
  1557         #     new_key_and_inonce[i] = state->k[i];
       
  1558         # }
       
  1559         $new_key_and_inonce = $st->getKey();
       
  1560 
       
  1561         # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
       
  1562         #     new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] =
       
  1563         #         STATE_INONCE(state)[i];
       
  1564         # }
       
  1565         $new_key_and_inonce .= ParagonIE_Sodium_Core_Util::substR($st->getNonce(), 0, 8);
       
  1566 
       
  1567         # crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce,
       
  1568         #                                 sizeof new_key_and_inonce,
       
  1569         #                                 state->nonce, state->k);
       
  1570 
       
  1571         $st->rekey(ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
       
  1572             $new_key_and_inonce,
       
  1573             $st->getCombinedNonce(),
       
  1574             $st->getKey(),
       
  1575             ParagonIE_Sodium_Core_Util::store64_le(0)
       
  1576         ));
       
  1577 
       
  1578         # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
       
  1579         #     state->k[i] = new_key_and_inonce[i];
       
  1580         # }
       
  1581         # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
       
  1582         #     STATE_INONCE(state)[i] =
       
  1583         #          new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i];
       
  1584         # }
       
  1585         # _crypto_secretstream_xchacha20poly1305_counter_reset(state);
       
  1586         $st->counterReset();
       
  1587 
       
  1588         $state = $st->toString();
       
  1589     }
       
  1590 
       
  1591     /**
  1189      * Detached Ed25519 signature.
  1592      * Detached Ed25519 signature.
  1190      *
  1593      *
  1191      * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
  1594      * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
  1192      *
  1595      *
  1193      * @param string $message
  1596      * @param string $message