65 lines
1.4 KiB
Go
65 lines
1.4 KiB
Go
package crypto
|
|
|
|
import (
|
|
"sync"
|
|
)
|
|
|
|
// UEKCache holds decrypted User Encryption Keys in memory, keyed by user ID.
|
|
// Keys are loaded on login and evicted on logout / token expiry.
|
|
//
|
|
// This is the trust boundary: UEKs exist in plaintext only in server memory,
|
|
// never on disk or in the database.
|
|
type UEKCache struct {
|
|
mu sync.RWMutex
|
|
store map[string][]byte
|
|
}
|
|
|
|
// NewUEKCache creates a new empty cache.
|
|
func NewUEKCache() *UEKCache {
|
|
return &UEKCache{store: make(map[string][]byte)}
|
|
}
|
|
|
|
// Store caches a UEK for the given user ID.
|
|
func (c *UEKCache) Store(userID string, uek []byte) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
// Copy to avoid caller mutation
|
|
key := make([]byte, len(uek))
|
|
copy(key, uek)
|
|
c.store[userID] = key
|
|
}
|
|
|
|
// Load retrieves the UEK for a user. Returns (uek, true) if present.
|
|
func (c *UEKCache) Load(userID string) ([]byte, bool) {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
uek, ok := c.store[userID]
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
// Return a copy
|
|
out := make([]byte, len(uek))
|
|
copy(out, uek)
|
|
return out, true
|
|
}
|
|
|
|
// Evict removes the UEK for a user (logout / session expiry).
|
|
func (c *UEKCache) Evict(userID string) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
// Zero the memory before deleting
|
|
if uek, ok := c.store[userID]; ok {
|
|
for i := range uek {
|
|
uek[i] = 0
|
|
}
|
|
}
|
|
delete(c.store, userID)
|
|
}
|
|
|
|
// Size returns the number of cached UEKs (for diagnostics).
|
|
func (c *UEKCache) Size() int {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
return len(c.store)
|
|
}
|