fixed issues with base64 length limit.

This commit is contained in:
deepend 2025-09-16 10:05:07 -06:00
parent f8f07abc2c
commit 32fd5afc65
6 changed files with 312 additions and 243 deletions

View File

@ -1,5 +1,6 @@
{
"require": {
"paragonie/sodium_compat": "^2.1"
}
"require": {
"paragonie/sodium_compat": "^2.1",
"ext-curl": "*"
}
}

View File

@ -52,6 +52,39 @@ function respond($status, $message, $data = []) {
exit;
}
/**
* Try to decode a Base64 or URL-safe Base64 string (or data: URI).
* Returns decoded bytes on success, or false on failure.
*/
function maybeDecodeBase64($input) {
if ($input === null) return false;
$trim = preg_replace('/\s+/', '', $input);
if (stripos($trim, 'data:') === 0 && ($pos = stripos($trim, ';base64,')) !== false) {
$payload = substr($trim, $pos + 8);
} else {
$payload = $trim;
}
$payload = strtr($payload, '-_', '+/');
$pad = strlen($payload) % 4;
if ($pad) { $payload .= str_repeat('=', 4 - $pad); }
$decoded = base64_decode($payload, true);
if ($decoded === false) { return false; }
// Heuristic to reduce false positives: compare normalized encoding or check for binary-ish data
$re = rtrim(strtr(base64_encode($decoded), '+/', '-_'), '=');
$pa = rtrim(str_replace('=', '', $payload), '=');
if ($re !== $pa) {
$nonPrintable = preg_match_all('/[^\x09\x0A\x0D\x20-\x7E]/', $decoded);
if ($nonPrintable < max(1, (int)(strlen($decoded) * 0.1))) {
return false;
}
}
return $decoded;
}
// Enhance Base64 decoding to handle both raw and URL-safe inputs
function safeBase64Decode($input) {
// First, attempt a direct Base64 decode
@ -173,24 +206,40 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET' && $_GET['action'] === 'retrieve') {
$pubkey_hash = bin2hex(sodium_crypto_generichash($decodedPubkey));
if (!sodium_crypto_sign_verify_detached($decodedSignature, $data, $decodedPubkey)) {
respond(400, "Invalid signature");
// If data looks like base64 (or data:...;base64,...) decode it for size check and storage.
$decodedData = maybeDecodeBase64($data);
$isBase64Payload = ($decodedData !== false);
// Verify signature. First try verifying exactly what we received (backwards compatibility).
$sigOk = sodium_crypto_sign_verify_detached($decodedSignature, $data, $decodedPubkey);
// If that fails and it looked like base64, also try verifying the decoded bytes (clients that sign raw bytes).
if (!$sigOk && $isBase64Payload) {
$sigOk = sodium_crypto_sign_verify_detached($decodedSignature, $decodedData, $decodedPubkey);
}
if (!$sigOk) {
respond(403, "Invalid signature");
}
$stmt = $db->prepare("SELECT * FROM storage WHERE pubkey_hash = :pubkey_hash");
$stmt->execute([':pubkey_hash' => $pubkey_hash]);
if (!$stmt->fetch(PDO::FETCH_ASSOC)) {
respond(404, "Space not found");
}
if (strlen($data) > 1024) {
// Enforce 1k limit against decoded bytes when base64 was used; otherwise against the raw payload.
$dataForLimit = $isBase64Payload ? $decodedData : $data;
if (strlen($dataForLimit) > 1024) {
respond(400, "Data exceeds 1k size limit");
}
// Choose what we store: decoded bytes when base64 was used (so retrieval returns raw), otherwise raw text.
$dataToStore = $isBase64Payload ? $decodedData : $data;
// Normalize MIME type for common images if a data URI was provided.
if ($isBase64Payload && isset($_PUT['mime_type']) && stripos($_PUT['mime_type'], 'image/') === 0) {
$mime_type = $_PUT['mime_type'];
}
// Persist
$stmt = $db->prepare("UPDATE storage SET data = :data, mime_type = :mime_type WHERE pubkey_hash = :pubkey_hash");
$stmt->execute([':data' => $data, ':mime_type' => $mime_type, ':pubkey_hash' => $pubkey_hash]);
$stmt->execute([':data' => $dataToStore, ':mime_type' => $mime_type, ':pubkey_hash' => $pubkey_hash]);
respond(200, "Storage updated");
}
// Handle deletion (not in spec, but helpful)

View File

@ -16,7 +16,8 @@
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="https://github.com/the1024club/the1024.club" target="_blank">Source Code</a></li>
</ul>
</nav>
@ -168,7 +169,7 @@ php 1kb_client.php retrieve public_key.pem
<footer>
<p class="license-title">The MIT License (MIT)</p>
<p class="license-copyright">©2020 The 1024 Club Developers (see AUTHORS.txt)</p>
<p class="license-copyright">©2024 The 1024 Club Developers <a href="https://github.com/the1024club/the1024.club" target="_blank">Source Code</a></p>
<p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</p>
<p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p>
<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>

BIN
utils.zip Normal file

Binary file not shown.

18
utils/verify_keys.php Normal file
View File

@ -0,0 +1,18 @@
<?php
// Load Sodium extension
require __DIR__ . '/../vendor/autoload.php'; // Adjust the path to the autoload file
// Base64 decode the public and private keys
$publicKey = base64_decode('0HCO9Tm3JvvbK+J93PStb4/23HSxEZS9WUrWSjmLIz4=');
$privateKey = base64_decode('s1cAUQfbxa6Q8lJxn90N6aKER17Ng9tD/gHpX+8x6drQcI71Obcm+9sr4n3c9K1vj/bcdLERlL1ZStZKOYsjPg==');
// Derive the public key from the private key to check if they match
$derivedPublicKey = sodium_crypto_sign_publickey_from_secretkey($privateKey);
// Compare the derived public key with the provided public key
if (hash_equals($publicKey, $derivedPublicKey)) {
echo "The public and private key pair match!" . PHP_EOL;
} else {
echo "The public and private key pair do NOT match!" . PHP_EOL;
}
?>