Documentation
¶
Overview ¶
Package crypto implements a **FIPS 140-3 compliant KEM-DEM envelope encryption scheme** suitable for multi-gigabyte streams using ECDH P-256 and AES-256-GCM. This design is Go 1.24+ FIPS compatible (GOFIPS140=v1.0.0) and depends only on standard library crypto packages.
────────────────────────── Design summary ─────────────────────────────
⚙ KEM (Key-Encapsulation Mechanism)
• ECDH P-256 + AES-256-GCM for DEK wrapping
• Output: variable-size encrypted DEK (48-byte DEK + 16-byte GCM tag + ephemeral pubkey)
• Provides forward secrecy for each blob
⚙ DEM (Data-Encapsulation Mechanism)
• AES-256-GCM in ~64 KiB framed chunks (65519 bytes max)
• Nonce = 4-byte random prefix ∥ 8-byte little-endian counter
• First frame authenticates header via associated data (prevents tampering)
• Constant ~64 KiB RAM, O(1) header re-wrap for key rotation
⚙ Fleet key
• Single ECDSA P-256 key-pair per customer
• Public key used directly for ECDH operations
• Private key stored in cloud secret store and fetched at boot
File layout
┌─────────────────────────────────────────────────────────────────────────┐
│ uint16 wrappedLen │ 125B wrapped DEK │ 12B base nonce │ frames... │
└─────────────────────────────────────────────────────────────────────────┘
▲ ▲
│ └─ AES-256-GCM frames
└─ ECDH + AES-GCM wrapped DEK
Security properties
• Confidentiality & integrity: AES-256-GCM per frame
• Header authentication: first frame includes header as associated data
• Forward-secrecy per object: new ephemeral ECDH key each encryption
• Key rotation: requires re-wrapping only the ~139-byte header
• FIPS 140-3 compliant: uses only approved algorithms
Typical workflow
────────────────
Publisher:
1) generate DEK, encrypt stream → dst
2) ephemeral ECDH + AES-GCM wrap DEK with fleet public key
3) write header {len, wrapped DEK, nonce} - ~139 bytes total
4) first frame includes header as associated data for authentication
Machine node:
1) read header, unwrap DEK with fleet private key via ECDH
2) stream-decrypt frames on the fly (first frame verifies header)
Public API ──────────
EncryptFIPSKEMDEMStream(pub *ecdsa.PublicKey, r io.Reader, w io.Writer) DecryptFIPSKEMDEMStream(priv *ecdsa.PrivateKey, r io.Reader, w io.Writer)
Both return the number of plaintext bytes processed and ensure that every error path is authenticated-failure-safe.
Index ¶
- Constants
- Variables
- func DecryptBytes(encryptedData []byte, key string) ([]byte, error)
- func DecryptFIPSKEMDEMStream(priv *ecdsa.PrivateKey, src io.Reader, dst io.Writer) (int64, error)
- func DecryptStream(reader io.Reader, writer io.WriteCloser, key string) error
- func EncryptBytes(data []byte, key string) ([]byte, error)
- func EncryptFIPSKEMDEMStream(pub *ecdsa.PublicKey, src io.Reader, dst io.Writer) (int64, error)
- func EncryptStream(reader io.Reader, writer io.WriteCloser, key string) error
- func SignHTTPRequest(key *ecdsa.PrivateKey, req *http.Request, body []byte) error
- func VerifyHTTPRequest(key *ecdsa.PublicKey, req *http.Request, body []byte, ...) error
- func VerifyHTTPRequestSignatureWithBody(key *ecdsa.PublicKey, req *http.Request, bodyReader io.Reader, ...) error
- func VerifyHTTPRequestStreaming(key *ecdsa.PublicKey, req *http.Request, bodyReader io.Reader, ...) error
- type SignatureContext
- type StreamingSignatureReader
Constants ¶
const MaxChunkSize = 10 * 1024 * 1024 // 10 MiB
MaxChunkSize is the maximum allowed ciphertext chunk length (bytes).
Variables ¶
var ErrChunkSizeTooLarge = errors.New("chunk size too large")
ErrChunkSizeTooLarge is returned when a chunk size exceeds the maximum allowed size.
var (
ErrSignatureComputationTimeout = errors.New("signature computation timeout")
)
Predefined errors for better error handling and testing
Functions ¶
func DecryptBytes ¶ added in v1.0.81
DecryptBytes decrypts a byte array and returns the decrypted bytes. For better performance with large data or when you have readers/writers available, use DecryptStream instead.
func DecryptFIPSKEMDEMStream ¶ added in v1.0.74
DecryptFIPSKEMDEMStream reverses EncryptFIPSKEMDEMStream using FIPS-approved algorithms.
func DecryptStream ¶ added in v1.0.13
DecryptStream decrypts data from a reader (like an HTTP response body) using a chunked approach where each chunk has its own nonce and authentication tag. This is secure for large files and streaming data sources. The format of each chunk is: [4-byte chunk size (little-endian)][nonce][encrypted data][tag]
func EncryptBytes ¶ added in v1.0.81
EncryptBytes encrypts a byte array and returns the encrypted bytes. For better performance with large data or when you have readers/writers available, use EncryptStream instead.
func EncryptFIPSKEMDEMStream ¶ added in v1.0.74
EncryptFIPSKEMDEMStream copies src → dst using FIPS-approved algorithms, returns plaintext bytes written.
func EncryptStream ¶ added in v1.0.13
EncryptStream encrypts data from a reader using a chunked approach where each chunk has its own nonce and authentication tag. This is secure for large files and streaming data sources. The format of each chunk is: [4-byte chunk size (little-endian)][nonce][encrypted data][tag]
func SignHTTPRequest ¶ added in v1.0.73
func VerifyHTTPRequest ¶ added in v1.0.73
func VerifyHTTPRequestSignatureWithBody ¶ added in v1.0.86
func VerifyHTTPRequestSignatureWithBody(key *ecdsa.PublicKey, req *http.Request, bodyReader io.Reader, timestamp time.Time, nonce string, checkNonce func(string) error) error
VerifyHTTPRequestSignatureWithBody verifies a streaming signature from request trailer without requiring SignatureContext. This allows verification to be decoupled from signing by reading and hashing the body on the verifier side.
Types ¶
type SignatureContext ¶ added in v1.0.85
type SignatureContext struct {
// contains filtered or unexported fields
}
SignatureContext holds the state needed for signature verification
func PrepareHTTPRequestForStreaming ¶ added in v1.0.85
func PrepareHTTPRequestForStreaming(key *ecdsa.PrivateKey, req *http.Request) (*SignatureContext, error)
PrepareHTTPRequestForStreaming sets up a request for streaming signature. Returns a SignatureContext that should be used to complete the signature after the body is streamed.
func (*SignatureContext) Nonce ¶ added in v1.0.86
func (ctx *SignatureContext) Nonce() string
Nonce returns the nonce used for signature generation
func (*SignatureContext) Timestamp ¶ added in v1.0.86
func (ctx *SignatureContext) Timestamp() string
Timestamp returns the timestamp used for signature generation
type StreamingSignatureReader ¶ added in v1.0.86
type StreamingSignatureReader struct {
// contains filtered or unexported fields
}
StreamingSignatureReader wraps the request body and ensures signature is computed before request is sent
func (*StreamingSignatureReader) Close ¶ added in v1.0.86
func (s *StreamingSignatureReader) Close() error
Close implements io.Closer
func (*StreamingSignatureReader) Error ¶ added in v1.0.86
func (s *StreamingSignatureReader) Error() error
Error returns any error that occurred during signature computation