SHA-256 over raw asset bytes and over the canonical JSON form of metadata (encoding/json already sorts map keys and preserves struct field order deterministically, so no separate canonicalization library is needed for our own fixed types). A Timestamper interface stands in for the RFC-3161 timestamp step — no concrete implementation yet, since which TSA to use is an open decision (CLAUDE.md "Offene Punkte") that directly affects the archive's evidentiary weight, not a purely technical choice to make silently. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
33 lines
1.1 KiB
Go
33 lines
1.1 KiB
Go
// Package evidence bildet die Beweiskette: Hashing von Assets und
|
|
// Metadaten, RFC-3161-Zeitstempel über diesen Hash. Das Append-only-
|
|
// Prinzip selbst wird von internal/store (Postgres-Trigger) erzwungen —
|
|
// dieses Paket liefert nur die Bausteine, die evidence_package braucht.
|
|
package evidence
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
// HashBytes berechnet den SHA-256-Digest über beliebige Bytes, z. B.
|
|
// ein Asset wie Screenshot oder Video.
|
|
func HashBytes(data []byte) []byte {
|
|
sum := sha256.Sum256(data)
|
|
return sum[:]
|
|
}
|
|
|
|
// HashMetadata berechnet den SHA-256-Digest über die kanonisierte JSON-
|
|
// Repräsentation von v. "Kanonisiert" heißt hier: encoding/json sortiert
|
|
// Objektschlüssel bereits deterministisch, und Struct-Felder behalten
|
|
// ihre Deklarationsreihenfolge — für unsere eigenen, fest definierten
|
|
// Go-Typen ist das schon eine stabile, reproduzierbare Serialisierung,
|
|
// ohne dass es eine eigene Kanonisierungs-Bibliothek bräuchte.
|
|
func HashMetadata(v any) ([]byte, error) {
|
|
data, err := json.Marshal(v)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("evidence: metadata marshal: %w", err)
|
|
}
|
|
return HashBytes(data), nil
|
|
}
|