@@ -21,6 +21,29 @@ var rfc4253 = require('./rfc4253');
2121
2222var errors = require ( '../errors' ) ;
2323
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+
2447/*
2548 * For reading we support both PKCS#1 and PKCS#8. If we find a private key,
2649 * we just take the public component of it and use that.
@@ -73,6 +96,10 @@ function read(buf, options, forceType) {
7396 headers [ m [ 1 ] . toLowerCase ( ) ] = m [ 2 ] ;
7497 }
7598
99+ /* Chop off the first and last lines */
100+ lines = lines . slice ( 0 , - 1 ) . join ( '' ) ;
101+ buf = Buffer . from ( lines , 'base64' ) ;
102+
76103 var cipher , key , iv ;
77104 if ( headers [ 'proc-type' ] ) {
78105 var parts = headers [ 'proc-type' ] . split ( ',' ) ;
@@ -95,9 +122,70 @@ function read(buf, options, forceType) {
95122 }
96123 }
97124
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+ }
101189
102190 if ( cipher && key && iv ) {
103191 var cipherStream = crypto . createDecipheriv ( cipher , key , iv ) ;
0 commit comments