hs2019 signatures hashed with SHA-512, and SHA-512 digests

A draft-cavage hs2019 signature leaves the hash to the key: with an RSA key it is tried with SHA-256, as nearly everyone
signs, then with SHA-512, as some do; rsa-sha256 stays SHA-256 only. A Digest of SHA-512= is checked as SHA-256= is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-06 11:13:59 +02:00
1 parent 0310bbe0f9
commit e708f1ad2e
5 files changed
+39 -7

No files matched your search

@@ -152,9 +152,11 @@ namespace PrivaPub.Federation.Signing
{
if (!parameters.Headers.Contains("digest"))
return "the digest is not signed";
var expectedHash = Convert.ToBase64String(SHA256.HashData(body));
var sha256 = Convert.ToBase64String(SHA256.HashData(body));
var sha512 = Convert.ToBase64String(SHA512.HashData(body));
var matches = request.Headers["Digest"].ToString().Split(',').Select(d => d.Trim())
.Any(d => d.StartsWith("SHA-256=", StringComparison.OrdinalIgnoreCase) && d[8..] == expectedHash);
.Any(d => d.StartsWith("SHA-256=", StringComparison.OrdinalIgnoreCase) && d[8..] == sha256
|| d.StartsWith("SHA-512=", StringComparison.OrdinalIgnoreCase) && d[8..] == sha512);
if (!matches)
return "the digest does not match the body";
}
@@ -213,7 +215,8 @@ namespace PrivaPub.Federation.Signing
return string.IsNullOrEmpty(raw) || raw[0] != '/' ? $"{request.PathBase}{request.Path}{request.QueryString}" : raw;
}
public static bool Verify(string publicKeyPem, string signingString, byte[] signature)
// hs2019 leaves the hash to the key: RSA with SHA-256, as nearly everyone signs, else with SHA-512, as some do
public static bool Verify(string publicKeyPem, string signingString, byte[] signature, string algorithm = "rsa-sha256")
{
if (string.IsNullOrEmpty(publicKeyPem) || signingString == null)
return false;
@@ -221,8 +224,9 @@ namespace PrivaPub.Federation.Signing
{
using var rsa = RSA.Create();
rsa.ImportFromPem(publicKeyPem);
return rsa.VerifyData(Encoding.UTF8.GetBytes(signingString), signature,
HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
var data = Encoding.UTF8.GetBytes(signingString);
return rsa.VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)
|| algorithm == "hs2019" && rsa.VerifyData(data, signature, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
}
catch (CryptographicException)
{