update
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
@@ -57,17 +58,42 @@ func decodeKey(hexStr string) ([]byte, error) {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// keyCache memoizes deriveKey results so repeatedly encrypting/decrypting the
|
||||
// same record (e.g. re-viewing the same folder) skips the HKDF recompute —
|
||||
// this is a real, measured cost when done per-message across a folder
|
||||
// listing. Keyed on the raw master key bytes (as a string; no new exposure,
|
||||
// the same bytes already live in-process via MasterKey.Current/Previous)
|
||||
// alongside recordID/purpose so a key-rotation's Current vs Previous never
|
||||
// collide.
|
||||
// ponytail: unbounded — every distinct (recordID,purpose) ever seen stays
|
||||
// cached for the process lifetime. Add an LRU/TTL eviction if a long-uptime
|
||||
// instance with a very large distinct-message count ever makes this a real
|
||||
// memory concern; not needed for a first pass.
|
||||
var keyCache sync.Map
|
||||
|
||||
type keyCacheKey struct {
|
||||
master string
|
||||
recordID string
|
||||
purpose string
|
||||
}
|
||||
|
||||
// deriveKey produces a per-record 32-byte key from the master key using HKDF-SHA256.
|
||||
// recordID should be a stable, unique identifier for the record (e.g. message ID,
|
||||
// contact UID) — using the same recordID always derives the same key, which is
|
||||
// required for decryption to work.
|
||||
func deriveKey(master []byte, recordID string, purpose string) ([]byte, error) {
|
||||
ck := keyCacheKey{master: string(master), recordID: recordID, purpose: purpose}
|
||||
if v, ok := keyCache.Load(ck); ok {
|
||||
return v.([]byte), nil
|
||||
}
|
||||
|
||||
info := []byte(purpose + ":" + recordID)
|
||||
r := hkdf.New(sha256.New, master, nil, info)
|
||||
key := make([]byte, keySize)
|
||||
if _, err := io.ReadFull(r, key); err != nil {
|
||||
return nil, fmt.Errorf("hkdf derive: %w", err)
|
||||
}
|
||||
keyCache.Store(ck, key)
|
||||
return key, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user