github.com/grafana/pyroscope@v1.18.0/pkg/frontend/vcs/encryption.go (about) 1 package vcs 2 3 import ( 4 "crypto/aes" 5 "crypto/cipher" 6 "crypto/rand" 7 "encoding/base64" 8 "encoding/json" 9 "errors" 10 "io" 11 12 "golang.org/x/oauth2" 13 ) 14 15 func encryptToken(token *oauth2.Token, key []byte) (string, error) { 16 plaintext, err := json.Marshal(token) 17 if err != nil { 18 return "", err 19 } 20 21 block, err := aes.NewCipher(key) 22 if err != nil { 23 return "", err 24 } 25 26 gcm, err := cipher.NewGCM(block) 27 if err != nil { 28 return "", err 29 } 30 31 nonce := make([]byte, gcm.NonceSize()) 32 if _, err = io.ReadFull(rand.Reader, nonce); err != nil { 33 return "", err 34 } 35 36 // Using nonce as Seal's dst argument results in it being the first 37 // chunk of bytes in the ciphertext. Decrypt retrieves the nonce/IV from this. 38 ciphertext := gcm.Seal(nonce, nonce, plaintext, nil) 39 40 return base64.StdEncoding.EncodeToString(ciphertext), nil 41 } 42 43 func decryptToken(ciphertextBase64 string, key []byte) (*oauth2.Token, error) { 44 ciphertext, err := base64.StdEncoding.DecodeString(ciphertextBase64) 45 if err != nil { 46 return nil, err 47 } 48 49 block, err := aes.NewCipher(key) 50 if err != nil { 51 return nil, err 52 } 53 54 gcm, err := cipher.NewGCM(block) 55 if err != nil { 56 return nil, err 57 } 58 59 nonceSize := gcm.NonceSize() 60 if len(ciphertext) < nonceSize { 61 return nil, errors.New("malformed token") 62 } 63 nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] 64 65 plaintext, err := gcm.Open(nil, nonce, ciphertext, nil) 66 if err != nil { 67 return nil, err 68 } 69 70 var token oauth2.Token 71 if err = json.Unmarshal(plaintext, &token); err != nil { 72 return nil, err 73 } 74 75 return &token, nil 76 }