Skip to content

Commit 6daebb2

Browse files
committed
test
1 parent a82c6a9 commit 6daebb2

4 files changed

Lines changed: 27 additions & 157 deletions

File tree

builder/azure/pkcs12/crypto.go

Lines changed: 12 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,15 @@ package pkcs12
66

77
import (
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

2320
const (
@@ -29,11 +26,6 @@ const (
2926
var (
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-
9974
func 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-
173102
func 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.

builder/azure/pkcs12/pkcs12.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ func makeContentInfos(derBytes []byte, privateKey interface{}, password []byte)
381381
return contentInfos, nil
382382
}
383383

384-
// makeShroudedKeyBagContentInfoModern creates content info using AES-256-CBC with PBES2.
384+
// makeShroudedKeyBagContentInfoModern creates content info using Triple DES with high iteration count.
385385
func makeShroudedKeyBagContentInfoModern(privateKey interface{}, password []byte) (*contentInfo, error) {
386386
shroudedKeyBagBytes, err := encodePkcs8ShroudedKeyBagModern(privateKey, password)
387387
if err != nil {
@@ -396,7 +396,7 @@ func makeShroudedKeyBagContentInfoModern(privateKey interface{}, password []byte
396396
return makeContentInfo(safeBags)
397397
}
398398

399-
// makeContentInfosModern creates content infos using AES-256-CBC with PBES2.
399+
// makeContentInfosModern creates content infos using Triple DES with high iteration count.
400400
func makeContentInfosModern(derBytes []byte, privateKey interface{}, password []byte) ([]contentInfo, error) {
401401
shroudedKeyContentInfo, err := makeShroudedKeyBagContentInfoModern(privateKey, password)
402402
if err != nil {
@@ -488,9 +488,10 @@ func Encode(derBytes []byte, privateKey interface{}, password string) (pfxBytes
488488
}
489489

490490
// EncodeModern converts a certificate and a private key to the PKCS#12 byte stream format
491-
// using AES-256-CBC encryption with PBES2 (PKCS#5 v2.0).
492-
// This provides modern, standards-compliant encryption that is fully compatible with
493-
// Windows and Azure while offering much stronger security than the legacy Triple DES.
491+
// using Triple DES encryption with a high iteration count (100,000 iterations).
492+
// While Triple DES is older, the high iteration count provides strong security through
493+
// key stretching and ensures maximum compatibility with Azure Key Vault and Windows.
494+
// This is more compatible than PBES2/AES which is not widely supported by Azure.
494495
//
495496
// derBytes is a DER encoded certificate.
496497
// privateKey is an RSA or ECDSA private key.

builder/azure/pkcs12/pkcs12_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func testPfxRoundTrip(t *testing.T, privateKey interface{}) interface{} {
9494
return key
9595
}
9696

97-
// TestEncodeModernRsa tests encoding with AES-256-CBC via PBES2
97+
// TestEncodeModernRsa tests encoding with Triple DES and high iteration count (100,000)
9898
func TestEncodeModernRsa(t *testing.T) {
9999
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
100100
if err != nil {
@@ -106,7 +106,7 @@ func TestEncodeModernRsa(t *testing.T) {
106106
t.Fatal(err.Error())
107107
}
108108

109-
// Test with EncodeModern (AES-256-CBC with PBES2)
109+
// Test with EncodeModern (Triple DES with 100,000 iterations)
110110
pfxBytes, err := EncodeModern(certificateBytes, privateKey, "testpassword")
111111
if err != nil {
112112
t.Fatalf("EncodeModern failed: %v", err)

builder/azure/pkcs12/safebags.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ func encodePkcs8ShroudedKeyBag(privateKey interface{}, password []byte) (bytes [
7070
return bytes, err
7171
}
7272

73-
// encodePkcs8ShroudedKeyBagModern encodes a private key using AES-256-CBC with PBES2.
74-
// This provides modern, standards-compliant encryption that is compatible with
75-
// Windows and Azure while offering much stronger security than legacy Triple DES.
73+
// encodePkcs8ShroudedKeyBagModern encodes a private key using Triple DES with high iteration count.
74+
// This provides stronger security than the legacy implementation through increased iterations (100,000)
75+
// while ensuring maximum compatibility with Azure Key Vault and Windows Certificate Store.
7676
func encodePkcs8ShroudedKeyBagModern(privateKey interface{}, password []byte) (bytes []byte, err error) {
7777
privateKeyBytes, err := marshalPKCS8PrivateKey(privateKey)
7878

@@ -85,20 +85,20 @@ func encodePkcs8ShroudedKeyBagModern(privateKey interface{}, password []byte) (b
8585
return nil, errors.New("pkcs12: error creating PKCS#8 salt: " + err.Error())
8686
}
8787

88-
pkData, iv, err := pbEncryptModern(privateKeyBytes, salt, password, pbeIterationCountModern)
88+
pkData, err := pbEncryptModern(privateKeyBytes, salt, password, pbeIterationCountModern)
8989
if err != nil {
9090
return nil, errors.New("pkcs12: error encoding PKCS#8 shrouded key bag when encrypting cert bag: " + err.Error())
9191
}
9292

93-
// Create PBES2 parameters
94-
params, err := pbEncryptModernParams(salt, iv, pbeIterationCountModern)
93+
// Create parameters with high iteration count
94+
params, err := getAlgorithmParams(salt, pbeIterationCountModern)
9595
if err != nil {
9696
return nil, errors.New("pkcs12: error encoding PKCS#8 shrouded key bag algorithm's parameters: " + err.Error())
9797
}
9898

9999
pkinfo := encryptedPrivateKeyInfo{
100100
AlgorithmIdentifier: pkix.AlgorithmIdentifier{
101-
Algorithm: oidPBES2,
101+
Algorithm: oidPBEWithSHAAnd3KeyTripleDESCBC,
102102
Parameters: params,
103103
},
104104
EncryptedData: pkData,

0 commit comments

Comments
 (0)