@@ -21,6 +21,29 @@ var rfc4253 = require('./rfc4253');
21
21
22
22
var errors = require ( '../errors' ) ;
23
23
24
+ var OID_PBES2 = '1.2.840.113549.1.5.13' ;
25
+ var OID_PBKDF2 = '1.2.840.113549.1.5.12' ;
26
+
27
+ var OID_TO_CIPHER = {
28
+ '1.2.840.113549.3.7' : '3des-cbc' ,
29
+ '2.16.840.1.101.3.4.1.2' : 'aes128-cbc' ,
30
+ '2.16.840.1.101.3.4.1.42' : 'aes256-cbc'
31
+ } ;
32
+ var CIPHER_TO_OID = { } ;
33
+ Object . keys ( OID_TO_CIPHER ) . forEach ( function ( k ) {
34
+ CIPHER_TO_OID [ OID_TO_CIPHER [ k ] ] = k ;
35
+ } ) ;
36
+
37
+ var OID_TO_HASH = {
38
+ '1.2.840.113549.2.7' : 'sha1' ,
39
+ '1.2.840.113549.2.9' : 'sha256' ,
40
+ '1.2.840.113549.2.11' : 'sha512'
41
+ } ;
42
+ var HASH_TO_OID = { } ;
43
+ Object . keys ( OID_TO_HASH ) . forEach ( function ( k ) {
44
+ HASH_TO_OID [ OID_TO_HASH [ k ] ] = k ;
45
+ } ) ;
46
+
24
47
/*
25
48
* For reading we support both PKCS#1 and PKCS#8. If we find a private key,
26
49
* we just take the public component of it and use that.
@@ -73,6 +96,10 @@ function read(buf, options, forceType) {
73
96
headers [ m [ 1 ] . toLowerCase ( ) ] = m [ 2 ] ;
74
97
}
75
98
99
+ /* Chop off the first and last lines */
100
+ lines = lines . slice ( 0 , - 1 ) . join ( '' ) ;
101
+ buf = Buffer . from ( lines , 'base64' ) ;
102
+
76
103
var cipher , key , iv ;
77
104
if ( headers [ 'proc-type' ] ) {
78
105
var parts = headers [ 'proc-type' ] . split ( ',' ) ;
@@ -95,9 +122,70 @@ function read(buf, options, forceType) {
95
122
}
96
123
}
97
124
98
- /* Chop off the first and last lines */
99
- lines = lines . slice ( 0 , - 1 ) . join ( '' ) ;
100
- buf = Buffer . from ( lines , 'base64' ) ;
125
+ if ( alg && alg . toLowerCase ( ) === 'encrypted' ) {
126
+ var eder = new asn1 . BerReader ( buf ) ;
127
+ var pbesEnd ;
128
+ eder . readSequence ( ) ;
129
+
130
+ eder . readSequence ( ) ;
131
+ pbesEnd = eder . offset + eder . length ;
132
+
133
+ var method = eder . readOID ( ) ;
134
+ if ( method !== OID_PBES2 ) {
135
+ throw ( new Error ( 'Unsupported PEM/PKCS8 encryption ' +
136
+ 'scheme: ' + method ) ) ;
137
+ }
138
+
139
+ eder . readSequence ( ) ; /* PBES2-params */
140
+
141
+ eder . readSequence ( ) ; /* keyDerivationFunc */
142
+ var kdfEnd = eder . offset + eder . length ;
143
+ var kdfOid = eder . readOID ( ) ;
144
+ if ( kdfOid !== OID_PBKDF2 )
145
+ throw ( new Error ( 'Unsupported PBES2 KDF: ' + kdfOid ) ) ;
146
+ eder . readSequence ( ) ;
147
+ var salt = eder . readString ( asn1 . Ber . OctetString , true ) ;
148
+ var iterations = eder . readInt ( ) ;
149
+ var hashAlg = 'sha1' ;
150
+ if ( eder . offset < kdfEnd ) {
151
+ eder . readSequence ( ) ;
152
+ var hashAlgOid = eder . readOID ( ) ;
153
+ hashAlg = OID_TO_HASH [ hashAlgOid ] ;
154
+ if ( hashAlg === undefined ) {
155
+ throw ( new Error ( 'Unsupported PBKDF2 hash: ' +
156
+ hashAlgOid ) ) ;
157
+ }
158
+ }
159
+ eder . _offset = kdfEnd ;
160
+
161
+ eder . readSequence ( ) ; /* encryptionScheme */
162
+ var cipherOid = eder . readOID ( ) ;
163
+ cipher = OID_TO_CIPHER [ cipherOid ] ;
164
+ if ( cipher === undefined ) {
165
+ throw ( new Error ( 'Unsupported PBES2 cipher: ' +
166
+ cipherOid ) ) ;
167
+ }
168
+ iv = eder . readString ( asn1 . Ber . OctetString , true ) ;
169
+
170
+ eder . _offset = pbesEnd ;
171
+ buf = eder . readString ( asn1 . Ber . OctetString , true ) ;
172
+
173
+ if ( typeof ( options . passphrase ) === 'string' ) {
174
+ options . passphrase = Buffer . from (
175
+ options . passphrase , 'utf-8' ) ;
176
+ }
177
+ if ( ! Buffer . isBuffer ( options . passphrase ) ) {
178
+ throw ( new errors . KeyEncryptedError (
179
+ options . filename , 'PEM' ) ) ;
180
+ }
181
+
182
+ var cinfo = utils . opensshCipherInfo ( cipher ) ;
183
+
184
+ cipher = cinfo . opensslName ;
185
+ key = utils . pbkdf2 ( hashAlg , salt , iterations , cinfo . keySize ,
186
+ options . passphrase ) ;
187
+ alg = undefined ;
188
+ }
101
189
102
190
if ( cipher && key && iv ) {
103
191
var cipherStream = crypto . createDecipheriv ( cipher , key , iv ) ;
0 commit comments