Fix AES-GCM format mismatch between JS Web Crypto and PHP openssl
Web Crypto API AES-GCM outputs: iv + ciphertext + tag (tag appended) PHP openssl was using: iv + tag + ciphertext (tag in middle) Now both use the same format: iv (12 bytes) + ciphertext + tag (16 bytes). Decrypt tries JS format first, falls back to PHP format for compatibility. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,8 @@ class AnalyticsCryptoService
|
||||
$iv = random_bytes(12);
|
||||
$encrypted = openssl_encrypt($json, 'aes-256-gcm', $this->key, \OPENSSL_RAW_DATA, $iv, $tag, '', 16);
|
||||
|
||||
return base64_encode($iv.$tag.$encrypted);
|
||||
// Format compatible with Web Crypto API: iv + ciphertext + tag
|
||||
return base64_encode($iv.$encrypted.$tag);
|
||||
}
|
||||
|
||||
public function decrypt(string $payload): ?array
|
||||
@@ -30,7 +31,21 @@ class AnalyticsCryptoService
|
||||
return null;
|
||||
}
|
||||
|
||||
// Try JS format first: iv (12) + ciphertext_with_tag (tag is last 16 bytes)
|
||||
$iv = substr($raw, 0, 12);
|
||||
$ciphertextWithTag = substr($raw, 12);
|
||||
|
||||
if (\strlen($ciphertextWithTag) >= 16) {
|
||||
$tag = substr($ciphertextWithTag, -16);
|
||||
$encrypted = substr($ciphertextWithTag, 0, -16);
|
||||
|
||||
$json = openssl_decrypt($encrypted, 'aes-256-gcm', $this->key, \OPENSSL_RAW_DATA, $iv, $tag);
|
||||
if (false !== $json) {
|
||||
return json_decode($json, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: PHP format iv (12) + tag (16) + ciphertext
|
||||
$tag = substr($raw, 12, 16);
|
||||
$encrypted = substr($raw, 28);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user