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 |