# HG changeset patch # User Peter Sanchez # Date 1679420166 21600 # Tue Mar 21 11:36:06 2023 -0600 # Node ID 9ce1ff47fa3c2fe9c5980bdd36489895a8179d73 # Parent 19b37ada49be85f6ed5aa8b52e7d71770d14026b More crypto helpers diff --git a/cookies/cookies.go b/cookies/cookies.go --- a/cookies/cookies.go +++ b/cookies/cookies.go @@ -23,23 +23,6 @@ ErrInvalidValue = errors.New("invalid cookie value") ) -// KeyWallet is a simple struct to pass on various keys. The -// reasoning is for cases where you have to change a secret -// key without affecting already encrypted/signed data that's -// in the wild. -// -// # The first key in `Keys` should be the current main key -// -// If `Reset` is true then if any key, other than the current -// main key was used for the cookie signing/encryption it will -// resign/encrypt the value with the current main key. Mainly -// useful for edge cases where you need to phase out an old -// key for whatever reason -type KeyWallet struct { - Keys [][]byte - Reset bool -} - // Set will set a cookie with no additional processing. func Set(c echo.Context, cookie *http.Cookie) { c.SetCookie(cookie) @@ -92,7 +75,7 @@ } // SetSigned will set a cookie and sign the value -func SetSigned(c echo.Context, cookie *http.Cookie, kw *KeyWallet) error { +func SetSigned(c echo.Context, cookie *http.Cookie, kw *crypto.KeyWallet) error { mac := hmac.New(sha256.New, kw.Keys[0]) mac.Write([]byte(cookie.Name)) mac.Write([]byte(cookie.Value)) @@ -109,7 +92,7 @@ } // GetSigned will get a cookie and verify it's signature -func GetSigned(c echo.Context, name string, kw *KeyWallet) (*http.Cookie, error) { +func GetSigned(c echo.Context, name string, kw *crypto.KeyWallet) (*http.Cookie, error) { cookie, err := Get(c, name) if err != nil { return nil, err @@ -154,7 +137,7 @@ } // SetEncrypted will set a cookie that is encrypted -func SetEncrypted(c echo.Context, cookie *http.Cookie, kw *KeyWallet) error { +func SetEncrypted(c echo.Context, cookie *http.Cookie, kw *crypto.KeyWallet) error { // Prepare the plaintext input for encryption. Because we want to // authenticate the cookie name as well as the value, we make this plaintext // in the format "{cookie name}:{cookie value}". We use the : character as a @@ -181,7 +164,7 @@ } // GetEncrypted will get an encrypted cookie and decrypt it -func GetEncrypted(c echo.Context, name string, kw *KeyWallet) (*http.Cookie, error) { +func GetEncrypted(c echo.Context, name string, kw *crypto.KeyWallet) (*http.Cookie, error) { cookie, err := Get(c, name) if err != nil { return nil, err diff --git a/crypto/crypto.go b/crypto/crypto.go --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -14,6 +14,23 @@ // ErrInvalidValue ... var ErrInvalidValue = errors.New("invalid encrypted value") +// KeyWallet is a simple struct to pass on various keys. The +// reasoning is for cases where you have to change a secret +// key without affecting already encrypted/signed data that's +// in the wild. +// +// # The first key in `Keys` should be the current main key +// +// If `Reset` is true then if any key, other than the current +// main key was used for the cookie signing/encryption it will +// resign/encrypt the value with the current main key. Mainly +// useful for edge cases where you need to phase out an old +// key for whatever reason +type KeyWallet struct { + Keys [][]byte + Reset bool +} + // GenerateKey will generate a random key of `keylen` length to be // used for cookie signing and/or encryption. If `alpha` is true then the key // will consist of only alphanumeric characters (plus common symbols) diff --git a/crypto/middleware.go b/crypto/middleware.go --- a/crypto/middleware.go +++ b/crypto/middleware.go @@ -3,6 +3,7 @@ import ( "context" "errors" + "strings" ) var cryptoCtxKey = &contextKey{"crypto"} @@ -16,7 +17,7 @@ return context.WithValue(ctx, cryptoCtxKey, crypto) } -// ForContext pulls *sql.DB obj for context +// ForContext pulls crypto value for context func ForContext(ctx context.Context) string { crypto, ok := ctx.Value(cryptoCtxKey).(string) if !ok { @@ -24,3 +25,14 @@ } return crypto } + +// KWForContext pulls crypto value for context and stores it into a KeyWallet +func KWForContext(ctx context.Context) *KeyWallet { + contextKeys := ForContext(ctx) + keys := strings.Split(contextKeys, " ") + kw := &KeyWallet{} + for _, key := range keys { + kw.Keys = append(kw.Keys, []byte(key)) + } + return kw +}