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 |