@@ -6,20 +6,24 @@ package pkcs12
66
77import (
88 "bytes"
9+ "crypto/aes"
910 "crypto/cipher"
1011 "crypto/des"
1112 "crypto/rand"
13+ "crypto/sha256"
1214 "crypto/x509/pkix"
1315 "encoding/asn1"
1416 "errors"
1517 "io"
1618
1719 "github.com/hashicorp/packer-plugin-azure/builder/azure/pkcs12/rc2"
20+ "golang.org/x/crypto/pbkdf2"
1821)
1922
2023const (
21- pbeIterationCount = 2048
22- pbeSaltSizeBytes = 8
24+ pbeIterationCount = 2048
25+ pbeIterationCountModern = 100000 // OWASP 2021 baseline for PBKDF2, balances security and performance
26+ pbeSaltSizeBytes = 8
2327)
2428
2529var (
@@ -65,6 +69,21 @@ func (shaWith40BitRC2CBC) deriveIV(salt, password []byte, iterations int) []byte
6569 return pbkdf (sha1Sum , 20 , 64 , salt , password , iterations , 2 , 8 )
6670}
6771
72+ // Modern AES-256-CBC cipher using PBKDF2
73+ type aes256CBC struct {}
74+
75+ func (aes256CBC ) create (key []byte ) (cipher.Block , error ) {
76+ return aes .NewCipher (key )
77+ }
78+
79+ func (aes256CBC ) deriveKey (salt , password []byte , iterations int ) []byte {
80+ return pbkdf2 .Key (password , salt , iterations , 32 , sha256 .New )
81+ }
82+
83+ func (aes256CBC ) deriveIV (salt , password []byte , iterations int ) []byte {
84+ return pbkdf2 .Key (password , salt , iterations , 16 , sha256 .New )
85+ }
86+
6887type pbeParams struct {
6988 Salt []byte
7089 Iterations int
@@ -73,20 +92,25 @@ type pbeParams struct {
7392func pbDecrypterFor (algorithm pkix.AlgorithmIdentifier , password []byte ) (cipher.BlockMode , int , error ) {
7493 var cipherType pbeCipher
7594
76- switch {
77- case algorithm .Algorithm .Equal (oidPBEWithSHAAnd3KeyTripleDESCBC ):
78- cipherType = shaWithTripleDESCBC {}
79- case algorithm .Algorithm .Equal (oidPBEWithSHAAnd40BitRC2CBC ):
80- cipherType = shaWith40BitRC2CBC {}
81- default :
82- return nil , 0 , NotImplementedError ("algorithm " + algorithm .Algorithm .String () + " is not supported" )
83- }
84-
8595 var params pbeParams
8696 if err := unmarshal (algorithm .Parameters .FullBytes , & params ); err != nil {
8797 return nil , 0 , err
8898 }
8999
100+ // Detect modern AES-256-CBC encryption by high iteration count
101+ if params .Iterations >= pbeIterationCountModern {
102+ cipherType = aes256CBC {}
103+ } else {
104+ switch {
105+ case algorithm .Algorithm .Equal (oidPBEWithSHAAnd3KeyTripleDESCBC ):
106+ cipherType = shaWithTripleDESCBC {}
107+ case algorithm .Algorithm .Equal (oidPBEWithSHAAnd40BitRC2CBC ):
108+ cipherType = shaWith40BitRC2CBC {}
109+ default :
110+ return nil , 0 , NotImplementedError ("algorithm " + algorithm .Algorithm .String () + " is not supported" )
111+ }
112+ }
113+
90114 key := cipherType .deriveKey (params .Salt , password , params .Iterations )
91115 iv := cipherType .deriveIV (params .Salt , password , params .Iterations )
92116
@@ -137,6 +161,8 @@ func pad(src []byte, blockSize int) []byte {
137161 return append (src , paddingText ... )
138162}
139163
164+ // pbEncrypt encrypts plainText using legacy Triple DES algorithm.
165+ // Deprecated: Use pbEncryptModern for AES-256-CBC encryption instead.
140166func pbEncrypt (plainText , salt , password []byte , iterations int ) (cipherText []byte , err error ) {
141167 if _ , err := io .ReadFull (rand .Reader , salt ); err != nil {
142168 return nil , errors .New ("pkcs12: failed to create a random salt value: " + err .Error ())
@@ -160,6 +186,33 @@ func pbEncrypt(plainText, salt, password []byte, iterations int) (cipherText []b
160186 return cipherText , nil
161187}
162188
189+ // pbEncryptModern encrypts plainText using modern AES-256-CBC algorithm with PBKDF2.
190+ // This provides much stronger security than the legacy Triple DES implementation.
191+ // Uses 100,000 iterations (OWASP 2021 baseline), providing strong security while
192+ // maintaining reasonable performance for ephemeral certificates.
193+ func pbEncryptModern (plainText , salt , password []byte , iterations int ) (cipherText []byte , err error ) {
194+ if _ , err := io .ReadFull (rand .Reader , salt ); err != nil {
195+ return nil , errors .New ("pkcs12: failed to create a random salt value: " + err .Error ())
196+ }
197+
198+ cipherType := aes256CBC {}
199+ key := cipherType .deriveKey (salt , password , iterations )
200+ iv := cipherType .deriveIV (salt , password , iterations )
201+
202+ block , err := cipherType .create (key )
203+ if err != nil {
204+ return nil , errors .New ("pkcs12: failed to create a block cipher: " + err .Error ())
205+ }
206+
207+ paddedPlainText := pad (plainText , block .BlockSize ())
208+
209+ encrypter := cipher .NewCBCEncrypter (block , iv )
210+ cipherText = make ([]byte , len (paddedPlainText ))
211+ encrypter .CryptBlocks (cipherText , paddedPlainText )
212+
213+ return cipherText , nil
214+ }
215+
163216// decryptable abstracts a object that contains ciphertext.
164217type decryptable interface {
165218 Algorithm () pkix.AlgorithmIdentifier
0 commit comments