@@ -6,18 +6,15 @@ package pkcs12
66
77import (
88 "bytes"
9- "crypto/aes"
109 "crypto/cipher"
1110 "crypto/des"
1211 "crypto/rand"
13- "crypto/sha256"
1412 "crypto/x509/pkix"
1513 "encoding/asn1"
1614 "errors"
1715 "io"
1816
1917 "github.com/hashicorp/packer-plugin-azure/builder/azure/pkcs12/rc2"
20- "golang.org/x/crypto/pbkdf2"
2118)
2219
2320const (
@@ -29,11 +26,6 @@ const (
2926var (
3027 oidPBEWithSHAAnd3KeyTripleDESCBC = asn1 .ObjectIdentifier ([]int {1 , 2 , 840 , 113549 , 1 , 12 , 1 , 3 })
3128 oidPBEWithSHAAnd40BitRC2CBC = asn1 .ObjectIdentifier ([]int {1 , 2 , 840 , 113549 , 1 , 12 , 1 , 6 })
32- // PBES2 (Password-Based Encryption Scheme 2) from PKCS#5 v2.0
33- oidPBES2 = asn1 .ObjectIdentifier ([]int {1 , 2 , 840 , 113549 , 1 , 5 , 13 })
34- oidPBKDF2 = asn1 .ObjectIdentifier ([]int {1 , 2 , 840 , 113549 , 1 , 5 , 12 })
35- oidHMACSHA256 = asn1 .ObjectIdentifier ([]int {1 , 2 , 840 , 113549 , 2 , 9 })
36- oidAES256CBC = asn1 .ObjectIdentifier ([]int {2 , 16 , 840 , 1 , 101 , 3 , 4 , 1 , 42 })
3729)
3830
3931// pbeCipher is an abstraction of a PKCS#12 cipher.
@@ -79,30 +71,7 @@ type pbeParams struct {
7971 Iterations int
8072}
8173
82- // PBES2 parameters as per PKCS#5 v2.0
83- type pbes2Params struct {
84- KeyDerivationFunc pkix.AlgorithmIdentifier
85- EncryptionScheme pkix.AlgorithmIdentifier
86- }
87-
88- type pbkdf2Params struct {
89- Salt []byte
90- IterationCount int
91- KeyLength int `asn1:"optional"`
92- PRF pkix.AlgorithmIdentifier `asn1:"optional"`
93- }
94-
95- type aes256CBCParams struct {
96- IV []byte
97- }
98-
9974func pbDecrypterFor (algorithm pkix.AlgorithmIdentifier , password []byte ) (cipher.BlockMode , int , error ) {
100- // Check if this is PBES2 (modern AES-256)
101- if algorithm .Algorithm .Equal (oidPBES2 ) {
102- return pbes2Decrypter (algorithm , password )
103- }
104-
105- // Legacy PBES1 algorithms
10675 var cipherType pbeCipher
10776
10877 var params pbeParams
@@ -130,46 +99,6 @@ func pbDecrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher
13099 return cipher .NewCBCDecrypter (block , iv ), block .BlockSize (), nil
131100}
132101
133- func pbes2Decrypter (algorithm pkix.AlgorithmIdentifier , password []byte ) (cipher.BlockMode , int , error ) {
134- var params pbes2Params
135- if err := unmarshal (algorithm .Parameters .FullBytes , & params ); err != nil {
136- return nil , 0 , errors .New ("pkcs12: invalid PBES2 parameters: " + err .Error ())
137- }
138-
139- // Verify we're using PBKDF2
140- if ! params .KeyDerivationFunc .Algorithm .Equal (oidPBKDF2 ) {
141- return nil , 0 , NotImplementedError ("only PBKDF2 is supported for PBES2" )
142- }
143-
144- // Parse PBKDF2 parameters
145- var kdfParams pbkdf2Params
146- if err := unmarshal (params .KeyDerivationFunc .Parameters .FullBytes , & kdfParams ); err != nil {
147- return nil , 0 , errors .New ("pkcs12: invalid PBKDF2 parameters: " + err .Error ())
148- }
149-
150- // Verify we're using AES-256-CBC
151- if ! params .EncryptionScheme .Algorithm .Equal (oidAES256CBC ) {
152- return nil , 0 , NotImplementedError ("only AES-256-CBC is supported for PBES2" )
153- }
154-
155- // Parse AES parameters (IV)
156- var aesParams aes256CBCParams
157- if err := unmarshal (params .EncryptionScheme .Parameters .FullBytes , & aesParams ); err != nil {
158- return nil , 0 , errors .New ("pkcs12: invalid AES parameters: " + err .Error ())
159- }
160-
161- // Derive key using PBKDF2
162- key := pbkdf2 .Key (password , kdfParams .Salt , kdfParams .IterationCount , 32 , sha256 .New )
163-
164- // Create AES cipher
165- block , err := aes .NewCipher (key )
166- if err != nil {
167- return nil , 0 , err
168- }
169-
170- return cipher .NewCBCDecrypter (block , aesParams .IV ), block .BlockSize (), nil
171- }
172-
173102func pbDecrypt (info decryptable , password []byte ) (decrypted []byte , err error ) {
174103 cbc , blockSize , err := pbDecrypterFor (info .Algorithm (), password )
175104 if err != nil {
@@ -234,30 +163,22 @@ func pbEncrypt(plainText, salt, password []byte, iterations int) (cipherText []b
234163 return cipherText , nil
235164}
236165
237- // pbEncryptModern encrypts plainText using AES-256-CBC with PBES2 (PKCS#5 v2.0).
238- // This provides modern encryption that is compatible with Windows and Azure while
239- // offering much stronger security than legacy Triple DES.
240- // Uses 100,000 iterations (OWASP 2021 baseline), providing strong security while
241- // maintaining reasonable performance for ephemeral certificates.
242- // Returns the ciphertext and the IV used (needed for PBES2 parameters).
243- func pbEncryptModern (plainText , salt , password []byte , iterations int ) (cipherText , iv []byte , err error ) {
166+ // pbEncryptModern encrypts plainText using Triple DES with a high iteration count.
167+ // While Triple DES is older, using 100,000+ iterations provides strong security through
168+ // key stretching and ensures maximum compatibility with Azure Key Vault and Windows.
169+ // This is the recommended approach for Azure as PBES2/AES is not widely supported.
170+ func pbEncryptModern (plainText , salt , password []byte , iterations int ) (cipherText []byte , err error ) {
244171 if _ , err := io .ReadFull (rand .Reader , salt ); err != nil {
245- return nil , nil , errors .New ("pkcs12: failed to create a random salt value: " + err .Error ())
246- }
247-
248- // Generate IV for AES-256-CBC
249- iv = make ([]byte , aes .BlockSize )
250- if _ , err := io .ReadFull (rand .Reader , iv ); err != nil {
251- return nil , nil , errors .New ("pkcs12: failed to create IV: " + err .Error ())
172+ return nil , errors .New ("pkcs12: failed to create a random salt value: " + err .Error ())
252173 }
253174
254- // Derive key using PBKDF2 with SHA-256
255- key := pbkdf2 .Key (password , salt , iterations , 32 , sha256 .New )
175+ cipherType := shaWithTripleDESCBC {}
176+ key := cipherType .deriveKey (salt , password , iterations )
177+ iv := cipherType .deriveIV (salt , password , iterations )
256178
257- // Create AES cipher
258- block , err := aes .NewCipher (key )
179+ block , err := cipherType .create (key )
259180 if err != nil {
260- return nil , nil , errors .New ("pkcs12: failed to create AES cipher: " + err .Error ())
181+ return nil , errors .New ("pkcs12: failed to create Triple DES cipher: " + err .Error ())
261182 }
262183
263184 paddedPlainText := pad (plainText , block .BlockSize ())
@@ -266,59 +187,7 @@ func pbEncryptModern(plainText, salt, password []byte, iterations int) (cipherTe
266187 cipherText = make ([]byte , len (paddedPlainText ))
267188 encrypter .CryptBlocks (cipherText , paddedPlainText )
268189
269- return cipherText , iv , nil
270- }
271-
272- // pbEncryptModernParams returns PBES2 algorithm parameters for AES-256-CBC encryption
273- func pbEncryptModernParams (salt , iv []byte , iterations int ) (asn1.RawValue , error ) {
274- // PBKDF2 parameters
275- pbkdf2Params := pbkdf2Params {
276- Salt : salt ,
277- IterationCount : iterations ,
278- KeyLength : 32 , // AES-256 requires 32 bytes
279- PRF : pkix.AlgorithmIdentifier {
280- Algorithm : oidHMACSHA256 ,
281- },
282- }
283-
284- pbkdf2ParamsBytes , err := asn1 .Marshal (pbkdf2Params )
285- if err != nil {
286- return asn1.RawValue {}, err
287- }
288-
289- var pbkdf2ParamsRaw asn1.RawValue
290- if _ , err := asn1 .Unmarshal (pbkdf2ParamsBytes , & pbkdf2ParamsRaw ); err != nil {
291- return asn1.RawValue {}, err
292- }
293-
294- // AES-256-CBC parameters (just the IV)
295- aesParams := aes256CBCParams {
296- IV : iv ,
297- }
298-
299- aesParamsBytes , err := asn1 .Marshal (aesParams )
300- if err != nil {
301- return asn1.RawValue {}, err
302- }
303-
304- var aesParamsRaw asn1.RawValue
305- if _ , err := asn1 .Unmarshal (aesParamsBytes , & aesParamsRaw ); err != nil {
306- return asn1.RawValue {}, err
307- }
308-
309- // PBES2 parameters
310- pbes2Params := pbes2Params {
311- KeyDerivationFunc : pkix.AlgorithmIdentifier {
312- Algorithm : oidPBKDF2 ,
313- Parameters : pbkdf2ParamsRaw ,
314- },
315- EncryptionScheme : pkix.AlgorithmIdentifier {
316- Algorithm : oidAES256CBC ,
317- Parameters : aesParamsRaw ,
318- },
319- }
320-
321- return convertToRawVal (pbes2Params )
190+ return cipherText , nil
322191}
323192
324193// decryptable abstracts a object that contains ciphertext.
0 commit comments