1package kms 2 3import ( 4 "crypto/aes" 5 "crypto/cipher" 6 "crypto/rand" 7 "crypto/sha256" 8 "encoding/hex" 9 "io" 10) 11 12type builtinSecret struct { 13 BaseSecret 14} 15 16func init() { 17 RegisterSecretProvider(SchemeBuiltin, SecretStatusAES256GCM, newBuiltinSecret) 18} 19 20func newBuiltinSecret(base BaseSecret, url, masterKey string) SecretProvider { 21 return &builtinSecret{ 22 BaseSecret: base, 23 } 24} 25 26func (s *builtinSecret) Name() string { 27 return "Builtin" 28} 29 30func (s *builtinSecret) IsEncrypted() bool { 31 return s.Status == SecretStatusAES256GCM 32} 33 34func (s *builtinSecret) deriveKey(key []byte) []byte { 35 var combined []byte 36 combined = append(combined, key...) 37 if s.AdditionalData != "" { 38 combined = append(combined, []byte(s.AdditionalData)...) 39 } 40 combined = append(combined, key...) 41 hash := sha256.Sum256(combined) 42 return hash[:] 43} 44 45func (s *builtinSecret) Encrypt() error { 46 if s.Payload == "" { 47 return ErrInvalidSecret 48 } 49 switch s.Status { 50 case SecretStatusPlain: 51 key := make([]byte, 32) 52 if _, err := io.ReadFull(rand.Reader, key); err != nil { 53 return err 54 } 55 block, err := aes.NewCipher(s.deriveKey(key)) 56 if err != nil { 57 return err 58 } 59 gcm, err := cipher.NewGCM(block) 60 if err != nil { 61 return err 62 } 63 nonce := make([]byte, gcm.NonceSize()) 64 if _, err = io.ReadFull(rand.Reader, nonce); err != nil { 65 return err 66 } 67 var aad []byte 68 if s.AdditionalData != "" { 69 aad = []byte(s.AdditionalData) 70 } 71 ciphertext := gcm.Seal(nonce, nonce, []byte(s.Payload), aad) 72 s.Key = hex.EncodeToString(key) 73 s.Payload = hex.EncodeToString(ciphertext) 74 s.Status = SecretStatusAES256GCM 75 return nil 76 default: 77 return ErrWrongSecretStatus 78 } 79} 80 81func (s *builtinSecret) Decrypt() error { 82 switch s.Status { 83 case SecretStatusAES256GCM: 84 encrypted, err := hex.DecodeString(s.Payload) 85 if err != nil { 86 return err 87 } 88 key, err := hex.DecodeString(s.Key) 89 if err != nil { 90 return err 91 } 92 block, err := aes.NewCipher(s.deriveKey(key)) 93 if err != nil { 94 return err 95 } 96 gcm, err := cipher.NewGCM(block) 97 if err != nil { 98 return err 99 } 100 nonceSize := gcm.NonceSize() 101 if len(encrypted) < nonceSize { 102 return errMalformedCiphertext 103 } 104 nonce, ciphertext := encrypted[:nonceSize], encrypted[nonceSize:] 105 var aad []byte 106 if s.AdditionalData != "" { 107 aad = []byte(s.AdditionalData) 108 } 109 plaintext, err := gcm.Open(nil, nonce, ciphertext, aad) 110 if err != nil { 111 return err 112 } 113 s.Status = SecretStatusPlain 114 s.Payload = string(plaintext) 115 s.Key = "" 116 s.AdditionalData = "" 117 return nil 118 default: 119 return ErrWrongSecretStatus 120 } 121} 122 123func (s *builtinSecret) Clone() SecretProvider { 124 baseSecret := BaseSecret{ 125 Status: s.Status, 126 Payload: s.Payload, 127 Key: s.Key, 128 AdditionalData: s.AdditionalData, 129 Mode: s.Mode, 130 } 131 return newBuiltinSecret(baseSecret, "", "") 132} 133