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