github.com/SaurabhDubey-Groww/go-cloud@v0.0.0-20221124105541-b26c29285fd8/secrets/localsecrets/localsecrets.go (about) 1 // Copyright 2018 The Go Cloud Development Kit Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package localsecrets provides a secrets implementation using a locally 16 // provided symmetric key. 17 // Use NewKeeper to construct a *secrets.Keeper. 18 // 19 // # URLs 20 // 21 // For secrets.OpenKeeper, localsecrets registers for the scheme "base64key". 22 // To customize the URL opener, or for more details on the URL format, 23 // see URLOpener. 24 // See https://gocloud.dev/concepts/urls/ for background information. 25 // 26 // # As 27 // 28 // localsecrets does not support any types for As. 29 package localsecrets // import "gocloud.dev/secrets/localsecrets" 30 31 import ( 32 "context" 33 "crypto/rand" 34 "encoding/base64" 35 "errors" 36 "fmt" 37 "io" 38 "net/url" 39 40 "gocloud.dev/gcerrors" 41 "gocloud.dev/secrets" 42 "golang.org/x/crypto/nacl/secretbox" 43 ) 44 45 func init() { 46 secrets.DefaultURLMux().RegisterKeeper(Scheme, &URLOpener{}) 47 } 48 49 // Scheme is the URL scheme localsecrets registers its URLOpener under on 50 // secrets.DefaultMux. 51 // See the package documentation and/or URLOpener for details. 52 const ( 53 Scheme = "base64key" 54 ) 55 56 // URLOpener opens localsecrets URLs like "base64key://smGbjm71Nxd1Ig5FS0wj9SlbzAIrnolCz9bQQ6uAhl4=". 57 // 58 // The URL host must be base64 encoded, and must decode to exactly 32 bytes. 59 // Note that base64.URLEncoding should be used to avoid URL-unsafe character in the hostname. 60 // If the URL host is empty (e.g., "base64key://"), a new random key is generated. 61 // 62 // No query parameters are supported. 63 type URLOpener struct{} 64 65 // OpenKeeperURL opens Keeper URLs. 66 func (o *URLOpener) OpenKeeperURL(ctx context.Context, u *url.URL) (*secrets.Keeper, error) { 67 for param := range u.Query() { 68 return nil, fmt.Errorf("open keeper %v: invalid query parameter %q", u, param) 69 } 70 var sk [32]byte 71 var err error 72 if u.Host == "" { 73 sk, err = NewRandomKey() 74 } else { 75 sk, err = Base64Key(u.Host) 76 } 77 if err != nil { 78 return nil, fmt.Errorf("open keeper %v: failed to get key: %v", u, err) 79 } 80 return NewKeeper(sk), nil 81 } 82 83 // keeper holds a secret for use in symmetric encryption, 84 // and implements driver.Keeper. 85 type keeper struct { 86 secretKey [32]byte // secretbox key size 87 } 88 89 // NewKeeper returns a *secrets.Keeper that uses the given symmetric 90 // key. See the package documentation for an example. 91 func NewKeeper(sk [32]byte) *secrets.Keeper { 92 return secrets.NewKeeper( 93 &keeper{secretKey: sk}, 94 ) 95 } 96 97 // Base64KeyStd takes a secret key as a base64 string and converts it 98 // to a [32]byte, erroring if the decoded data is not 32 bytes. 99 // It uses base64.StdEncoding. 100 func Base64KeyStd(base64str string) ([32]byte, error) { 101 return base64Key(base64str, base64.StdEncoding) 102 } 103 104 // Base64Key takes a secret key as a base64 string and converts it 105 // to a [32]byte, erroring if the decoded data is not 32 bytes. 106 // It uses base64.URLEncoding. 107 func Base64Key(base64str string) ([32]byte, error) { 108 return base64Key(base64str, base64.URLEncoding) 109 } 110 111 func base64Key(base64str string, encoding *base64.Encoding) ([32]byte, error) { 112 var sk32 [32]byte 113 key, err := encoding.DecodeString(base64str) 114 if err != nil { 115 return sk32, err 116 } 117 keySize := len([]byte(key)) 118 if keySize != 32 { 119 return sk32, fmt.Errorf("Base64Key: secret key material is %v bytes, want 32 bytes", keySize) 120 } 121 copy(sk32[:], key) 122 return sk32, nil 123 } 124 125 // NewRandomKey will generate random secret key material suitable to be 126 // used as the secret key argument to NewKeeper. 127 func NewRandomKey() ([32]byte, error) { 128 var sk32 [32]byte 129 // Read random numbers into the passed slice until it's full. 130 _, err := rand.Read(sk32[:]) 131 if err != nil { 132 return sk32, err 133 } 134 return sk32, nil 135 } 136 137 const nonceSize = 24 138 139 // Encrypt encrypts a message using a per-message generated nonce and 140 // the secret held in the Keeper. 141 func (k *keeper) Encrypt(ctx context.Context, message []byte) ([]byte, error) { 142 var nonce [nonceSize]byte 143 if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil { 144 return nil, err 145 } 146 // secretbox.Seal appends the encrypted message to its first argument and returns 147 // the result; using a slice on top of the nonce array for this "out" arg allows reading 148 // the nonce out of the first nonceSize bytes when the message is decrypted. 149 return secretbox.Seal(nonce[:], message, &nonce, &k.secretKey), nil 150 } 151 152 // Decrypt decrypts a message using a nonce that is read out of the first nonceSize bytes 153 // of the message and a secret held in the Keeper. 154 func (k *keeper) Decrypt(ctx context.Context, message []byte) ([]byte, error) { 155 if len(message) < nonceSize { 156 return nil, fmt.Errorf("localsecrets: invalid message length (%d, expected at least %d)", len(message), nonceSize) 157 } 158 var decryptNonce [nonceSize]byte 159 copy(decryptNonce[:], message[:nonceSize]) 160 161 decrypted, ok := secretbox.Open(nil, message[nonceSize:], &decryptNonce, &k.secretKey) 162 if !ok { 163 return nil, errors.New("localsecrets: Decrypt failed") 164 } 165 return decrypted, nil 166 } 167 168 // Close implements driver.Keeper.Close. 169 func (k *keeper) Close() error { return nil } 170 171 // ErrorAs implements driver.Keeper.ErrorAs. 172 func (k *keeper) ErrorAs(err error, i interface{}) bool { 173 return false 174 } 175 176 // ErrorCode implements driver.ErrorCode. 177 func (k *keeper) ErrorCode(error) gcerrors.ErrorCode { return gcerrors.Unknown }