0) {
return str_pad(substr($b, 0, 32), 32, "\0");
}
return str_pad(substr($env, 0, 32), 32, "\0");
}
// Fallback: alter Key aus bestehender Installation (32 ASCII-Bytes)
return "12345678901234567890123456789012";
}
// --- HKDF (SHA-256) über Token -> Session-Key (32 Byte) ---
// Kompatibel zu Android-Implementierung: salt = leer, info = "qdb-aes"
function hkdf_session_key_from_token(string $tokenHex, string $info = 'qdb-aes', int $len = 32): string {
$ikm = @hex2bin(trim($tokenHex));
if ($ikm === false) $ikm = $tokenHex; // Falls bereits binär
if (function_exists('hash_hkdf')) {
return hash_hkdf('sha256', $ikm, $len, $info, '');
}
// Fallback: eigene HKDF-Implementierung
$hashLen = 32;
$salt = str_repeat("\0", $hashLen);
$prk = hash_hmac('sha256', $ikm, $salt, true);
$okm = '';
$t = '';
$n = (int)ceil($len / $hashLen);
for ($i = 1; $i <= $n; $i++) {
$t = hash_hmac('sha256', $t . $info . chr($i), $prk, true);
$okm .= $t;
}
return substr($okm, 0, $len);
}
// --- Token-Storage (mit Ablauf) ---
function tokens_file_path(): string {
return __DIR__ . '/tokens.jsonl';
}
function token_add(string $token, int $ttlSeconds = 86400): void {
$rec = [
'token' => $token,
'created' => time(),
'exp' => time() + $ttlSeconds,
];
file_put_contents(tokens_file_path(), json_encode($rec) . PHP_EOL, FILE_APPEND | LOCK_EX);
// optional weiterhin für Alt-Skripte:
file_put_contents(__DIR__ . '/valid_tokens.txt', $token . PHP_EOL, FILE_APPEND | LOCK_EX);
}
function token_is_valid(string $token): bool {
$f = tokens_file_path();
if (!file_exists($f)) return false;
$h = fopen($f, 'r');
if (!$h) return false;
$now = time();
$valid = false;
while (($line = fgets($h)) !== false) {
$j = json_decode($line, true);
if (!is_array($j)) continue;
if (($j['token'] ?? '') === $token && ($j['exp'] ?? 0) >= $now) {
$valid = true; break;
}
}
fclose($h);
return $valid;
}
// --- AES-256-CBC: IV(16) + CIPHERTEXT ---
function aes256_cbc_encrypt_bytes(string $plain, string $key): string {
$key = str_pad(substr($key, 0, 32), 32, "\0");
$iv = random_bytes(16);
$cipher = openssl_encrypt($plain, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
if ($cipher === false) throw new Exception('openssl_encrypt failed');
return $iv . $cipher;
}
function aes256_cbc_decrypt_bytes(string $data, string $key): string {
if (strlen($data) < 16) throw new Exception('cipher too short');
$key = str_pad(substr($key, 0, 32), 32, "\0");
$iv = substr($data, 0, 16);
$ct = substr($data, 16);
$plain = openssl_decrypt($ct, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
if ($plain === false) throw new Exception('openssl_decrypt failed');
return $plain;
}