Implement transit encryption engine with versioned key management

Add complete transit engine supporting symmetric encryption (AES-256-GCM,
XChaCha20-Poly1305), asymmetric signing (Ed25519, ECDSA P-256/P-384),
and HMAC (SHA-256/SHA-512) with versioned key rotation, min decryption
version enforcement, key trimming, batch operations, and rewrap.

Includes proto definitions, gRPC handlers, REST routes, and comprehensive
tests covering all 18 operations, auth enforcement, and edge cases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-16 19:45:56 -07:00
parent ac4577f778
commit cbd77c58e8
10 changed files with 6718 additions and 4 deletions

View File

@@ -0,0 +1,291 @@
syntax = "proto3";
package metacrypt.v2;
option go_package = "git.wntrmute.dev/kyle/metacrypt/gen/metacrypt/v2;metacryptv2";
// TransitService provides typed, authenticated access to transit engine
// operations: symmetric encryption, signing, HMAC, and versioned key
// management. All RPCs require the service to be unsealed.
service TransitService {
// CreateKey creates a new named encryption key. Admin only.
rpc CreateKey(CreateTransitKeyRequest) returns (CreateTransitKeyResponse);
// DeleteKey permanently removes a named key. Admin only.
// Only succeeds if allow_deletion is true on the key config.
rpc DeleteKey(DeleteTransitKeyRequest) returns (DeleteTransitKeyResponse);
// GetKey returns metadata for a named key (no raw material). Auth required.
rpc GetKey(GetTransitKeyRequest) returns (GetTransitKeyResponse);
// ListKeys returns the names of all configured keys. Auth required.
rpc ListKeys(ListTransitKeysRequest) returns (ListTransitKeysResponse);
// RotateKey creates a new version of the named key. Admin only.
rpc RotateKey(RotateTransitKeyRequest) returns (RotateTransitKeyResponse);
// UpdateKeyConfig updates key configuration (e.g. min_decryption_version).
// Admin only.
rpc UpdateKeyConfig(UpdateTransitKeyConfigRequest) returns (UpdateTransitKeyConfigResponse);
// TrimKey deletes versions below min_decryption_version. Admin only.
rpc TrimKey(TrimTransitKeyRequest) returns (TrimTransitKeyResponse);
// Encrypt encrypts plaintext with the latest key version. Auth required.
rpc Encrypt(TransitEncryptRequest) returns (TransitEncryptResponse);
// Decrypt decrypts ciphertext. Auth required.
rpc Decrypt(TransitDecryptRequest) returns (TransitDecryptResponse);
// Rewrap re-encrypts ciphertext with the latest key version without
// exposing plaintext. Auth required.
rpc Rewrap(TransitRewrapRequest) returns (TransitRewrapResponse);
// BatchEncrypt encrypts multiple items in a single request. Auth required.
rpc BatchEncrypt(TransitBatchEncryptRequest) returns (TransitBatchResponse);
// BatchDecrypt decrypts multiple items in a single request. Auth required.
rpc BatchDecrypt(TransitBatchDecryptRequest) returns (TransitBatchResponse);
// BatchRewrap re-encrypts multiple items in a single request. Auth required.
rpc BatchRewrap(TransitBatchRewrapRequest) returns (TransitBatchResponse);
// Sign signs input data with an asymmetric key. Auth required.
rpc Sign(TransitSignRequest) returns (TransitSignResponse);
// Verify verifies a signature against input data. Auth required.
rpc Verify(TransitVerifyRequest) returns (TransitVerifyResponse);
// Hmac computes or verifies an HMAC. Auth required.
rpc Hmac(TransitHmacRequest) returns (TransitHmacResponse);
// GetPublicKey returns the public key for an asymmetric key. Auth required.
rpc GetPublicKey(GetTransitPublicKeyRequest) returns (GetTransitPublicKeyResponse);
}
// --- CreateKey ---
message CreateTransitKeyRequest {
string mount = 1;
string name = 2;
// type is the key algorithm: aes256-gcm, chacha20-poly, ed25519,
// ecdsa-p256, ecdsa-p384, hmac-sha256, hmac-sha512.
// Defaults to aes256-gcm if empty.
string type = 3;
}
message CreateTransitKeyResponse {
string name = 1;
string type = 2;
int32 version = 3;
}
// --- DeleteKey ---
message DeleteTransitKeyRequest {
string mount = 1;
string name = 2;
}
message DeleteTransitKeyResponse {}
// --- GetKey ---
message GetTransitKeyRequest {
string mount = 1;
string name = 2;
}
message GetTransitKeyResponse {
string name = 1;
string type = 2;
int32 current_version = 3;
int32 min_decryption_version = 4;
bool allow_deletion = 5;
repeated int32 versions = 6;
}
// --- ListKeys ---
message ListTransitKeysRequest {
string mount = 1;
}
message ListTransitKeysResponse {
repeated string keys = 1;
}
// --- RotateKey ---
message RotateTransitKeyRequest {
string mount = 1;
string name = 2;
}
message RotateTransitKeyResponse {
string name = 1;
int32 version = 2;
}
// --- UpdateKeyConfig ---
message UpdateTransitKeyConfigRequest {
string mount = 1;
string name = 2;
int32 min_decryption_version = 3;
bool allow_deletion = 4;
}
message UpdateTransitKeyConfigResponse {}
// --- TrimKey ---
message TrimTransitKeyRequest {
string mount = 1;
string name = 2;
}
message TrimTransitKeyResponse {
int32 trimmed = 1;
}
// --- Encrypt ---
message TransitEncryptRequest {
string mount = 1;
string key = 2;
// plaintext is base64-encoded data to encrypt.
string plaintext = 3;
// context is optional base64-encoded additional authenticated data (AAD).
string context = 4;
}
message TransitEncryptResponse {
// ciphertext in format "metacrypt:v{version}:{base64(nonce+ciphertext+tag)}"
string ciphertext = 1;
}
// --- Decrypt ---
message TransitDecryptRequest {
string mount = 1;
string key = 2;
string ciphertext = 3;
string context = 4;
}
message TransitDecryptResponse {
// plaintext is base64-encoded decrypted data.
string plaintext = 1;
}
// --- Rewrap ---
message TransitRewrapRequest {
string mount = 1;
string key = 2;
string ciphertext = 3;
string context = 4;
}
message TransitRewrapResponse {
string ciphertext = 1;
}
// --- Batch ---
message TransitBatchItem {
string plaintext = 1;
string ciphertext = 2;
string context = 3;
string reference = 4;
}
message TransitBatchResultItem {
string plaintext = 1;
string ciphertext = 2;
string reference = 3;
string error = 4;
}
message TransitBatchEncryptRequest {
string mount = 1;
string key = 2;
repeated TransitBatchItem items = 3;
}
message TransitBatchDecryptRequest {
string mount = 1;
string key = 2;
repeated TransitBatchItem items = 3;
}
message TransitBatchRewrapRequest {
string mount = 1;
string key = 2;
repeated TransitBatchItem items = 3;
}
message TransitBatchResponse {
repeated TransitBatchResultItem results = 1;
}
// --- Sign ---
message TransitSignRequest {
string mount = 1;
string key = 2;
// input is base64-encoded data to sign.
string input = 3;
}
message TransitSignResponse {
// signature in format "metacrypt:v{version}:{base64(signature_bytes)}"
string signature = 1;
}
// --- Verify ---
message TransitVerifyRequest {
string mount = 1;
string key = 2;
string input = 3;
string signature = 4;
}
message TransitVerifyResponse {
bool valid = 1;
}
// --- HMAC ---
message TransitHmacRequest {
string mount = 1;
string key = 2;
// input is base64-encoded data to HMAC.
string input = 3;
// hmac, if set, switches to verify mode.
string hmac = 4;
}
message TransitHmacResponse {
// hmac is set in compute mode.
string hmac = 1;
// valid is set in verify mode.
bool valid = 2;
}
// --- GetPublicKey ---
message GetTransitPublicKeyRequest {
string mount = 1;
string name = 2;
int32 version = 3;
}
message GetTransitPublicKeyResponse {
// public_key is base64-encoded PKIX DER public key.
string public_key = 1;
int32 version = 2;
string type = 3;
}