88 "encoding/hex"
99 "errors"
1010 "strings"
11+ "sync"
1112
1213 "golang.org/x/crypto/pbkdf2"
1314)
@@ -38,6 +39,8 @@ type CipherKey struct {
3839// VaultDecryptor handles Ansible Vault decryption
3940type VaultDecryptor struct {
4041 password string
42+ cache map [string ]* CipherKey
43+ mutex sync.RWMutex
4144}
4245
4346// NewVaultDecryptor creates a new vault decryptor with the given password
@@ -47,7 +50,10 @@ func NewVaultDecryptor(password string) *VaultDecryptor {
4750 password = strings .ReplaceAll (password , "\n " , "" )
4851 password = strings .ReplaceAll (password , "\r " , "" )
4952 password = strings .ReplaceAll (password , "\t " , "" )
50- return & VaultDecryptor {password : password }
53+ return & VaultDecryptor {
54+ password : password ,
55+ cache : make (map [string ]* CipherKey ),
56+ }
5157}
5258
5359// IsVaultEncrypted checks if a variable value is Ansible Vault encrypted
@@ -76,7 +82,7 @@ func (vd *VaultDecryptor) Decrypt(vaultData string) (string, error) {
7682 return "" , err
7783 }
7884 // Generate keys
79- key := generateCipherKey ( vd .password , salt )
85+ key := vd .generateCipherKey ( salt )
8086
8187 // Verify checksum
8288 if ! isChecksumValid (checkSum , encryptedData , key .HMACKey ) {
@@ -134,21 +140,40 @@ func parseVaultData(vaultData string) (salt, checkSum, data []byte, err error) {
134140 return salt , checkSum , data , nil
135141}
136142
137- // generateCipherKey generates cipher keys from password and salt
138- func generateCipherKey (password string , salt []byte ) * CipherKey {
143+ // generateCipherKey generates cipher keys from password and salt with caching
144+ func (vd * VaultDecryptor ) generateCipherKey (salt []byte ) * CipherKey {
145+ // Create cache key from salt (password is already stored in the struct)
146+ cacheKey := hex .EncodeToString (salt )
147+
148+ // Try to get from cache first (read lock)
149+ vd .mutex .RLock ()
150+ if cached , exists := vd .cache [cacheKey ]; exists {
151+ vd .mutex .RUnlock ()
152+ return cached
153+ }
154+ vd .mutex .RUnlock ()
155+
156+ // Generate new cipher key
139157 k := pbkdf2 .Key (
140- []byte (password ),
158+ []byte (vd . password ),
141159 salt ,
142160 iteration ,
143161 (cipherKeyLength + hmacKeyLength + ivLength ),
144162 sha256 .New ,
145163 )
146164
147- return & CipherKey {
165+ cipherKey := & CipherKey {
148166 Key : k [:cipherKeyLength ],
149167 HMACKey : k [cipherKeyLength :(cipherKeyLength + hmacKeyLength )],
150168 IV : k [(cipherKeyLength + hmacKeyLength ):(cipherKeyLength + hmacKeyLength + ivLength )],
151169 }
170+
171+ // Store in cache (write lock)
172+ vd .mutex .Lock ()
173+ vd .cache [cacheKey ] = cipherKey
174+ vd .mutex .Unlock ()
175+
176+ return cipherKey
152177}
153178
154179// isChecksumValid validates HMAC checksum
0 commit comments