Skip to content

Commit 47e402f

Browse files
committed
chore: wip
1 parent 01542cd commit 47e402f

3 files changed

Lines changed: 118 additions & 79 deletions

File tree

src/pbe.ts

Lines changed: 95 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,19 @@ import type { BlockCipher } from './cipher'
2323
import type { MessageDigest } from './sha1'
2424
import { aes } from './aes'
2525
import { asn1 } from './asn1'
26+
import { wrapRsaPrivateKey, privateKeyToAsn1, privateKeyFromAsn1 } from './rsa'
2627
import { createCipher } from './cipher'
28+
import { sha1 } from './sha1'
2729
import { des } from './des'
2830
import { md5 } from './md5'
2931
import { oids } from './oids'
3032
import { pbkdf2 } from './pbkdf2'
3133
import { getBytesSync } from './random'
3234
import { rc2 } from './rc2'
35+
import { pki } from './pki'
3336
import { sha512 } from './sha512'
34-
import { ByteBuffer, createBuffer, hexToBytes } from './utils'
37+
import { ByteBuffer, bytesToHex, createBuffer, hexToBytes } from './utils'
38+
import { pem } from './pem'
3539

3640
// validator for an EncryptedPrivateKeyInfo structure
3741
// Note: Currently only works w/algorithm params
@@ -358,7 +362,7 @@ export function encryptPrivateKeyInfo(obj: any, password: any, options: any): Bu
358362
*
359363
* @return the ASN.1 PrivateKeyInfo on success, null on failure.
360364
*/
361-
pki.decryptPrivateKeyInfo = function (obj, password) {
365+
export function decryptPrivateKeyInfo(obj: any, password: any): any {
362366
let rval = null
363367

364368
// get PBE params
@@ -373,15 +377,14 @@ pki.decryptPrivateKeyInfo = function (obj, password) {
373377

374378
// get cipher
375379
const oid = asn1.derToOid(capture.encryptionOid)
376-
const cipher = pki.pbe.getCipher(oid, capture.encryptionParams, password)
380+
const cipher = getCipher(oid, capture.encryptionParams, password)
377381

378382
// get encrypted data
379383
const encrypted = createBuffer(capture.encryptedData)
380384

381385
cipher.update(encrypted)
382-
if (cipher.finish()) {
386+
if (cipher.finish())
383387
rval = asn1.fromDer(cipher.output)
384-
}
385388

386389
return rval
387390
}
@@ -394,13 +397,14 @@ pki.decryptPrivateKeyInfo = function (obj, password) {
394397
*
395398
* @return the PEM-formatted encrypted private key.
396399
*/
397-
pki.encryptedPrivateKeyToPem = function (epki, maxline) {
400+
export function encryptedPrivateKeyToPem(epki: any, maxline: number): string {
398401
// convert to DER, then PEM-encode
399402
const msg = {
400403
type: 'ENCRYPTED PRIVATE KEY',
401404
body: asn1.toDer(epki).getBytes(),
402405
}
403-
return forge.pem.encode(msg, { maxline })
406+
407+
return pem.encode(msg, { maxline })
404408
}
405409

406410
/**
@@ -411,8 +415,8 @@ pki.encryptedPrivateKeyToPem = function (epki, maxline) {
411415
*
412416
* @return the ASN.1 EncryptedPrivateKeyInfo.
413417
*/
414-
pki.encryptedPrivateKeyFromPem = function (pem) {
415-
const msg = forge.pem.decode(pem)[0]
418+
export function encryptedPrivateKeyFromPem(pem: string): any {
419+
const msg = pem.decode(pem)[0]
416420

417421
if (msg.type !== 'ENCRYPTED PRIVATE KEY') {
418422
const error = new Error('Could not convert encrypted private key from PEM; '
@@ -445,31 +449,31 @@ pki.encryptedPrivateKeyFromPem = function (pem) {
445449
*
446450
* @param rsaKey the RSA key to encrypt.
447451
* @param password the password to use.
448-
* @param options:
449-
* algorithm: the encryption algorithm to use
450-
* ('aes128', 'aes192', 'aes256', '3des', 'des').
451-
* count: the iteration count to use.
452-
* saltSize: the salt size to use.
453-
* legacy: output an old non-PKCS#8 PEM-encrypted+encapsulated
454-
* headers (DEK-Info) private key.
452+
* @param options options for the encryption
453+
* @param options.algorithm the encryption algorithm to use ('aes128', 'aes192', 'aes256', '3des', 'des').
454+
* @param options.count the iteration count to use.
455+
* @param options.saltSize the salt size to use.
456+
* @param options.legacy output an old non-PKCS#8 PEM-encrypted+encapsulated headers (DEK-Info) private key.
455457
*
456458
* @return the PEM-encoded ASN.1 EncryptedPrivateKeyInfo.
457459
*/
458-
pki.encryptRsaPrivateKey = function (rsaKey, password, options) {
460+
export function encryptRsaPrivateKey(rsaKey: any, password: any, options: any): string {
459461
// standard PKCS#8
460462
options = options || {}
461463
if (!options.legacy) {
462464
// encrypt PrivateKeyInfo
463-
let rval = pki.wrapRsaPrivateKey(pki.privateKeyToAsn1(rsaKey))
464-
rval = pki.encryptPrivateKeyInfo(rval, password, options)
465-
return pki.encryptedPrivateKeyToPem(rval)
465+
let rval = wrapRsaPrivateKey(privateKeyToAsn1(rsaKey))
466+
rval = encryptPrivateKeyInfo(rval, password, options)
467+
468+
return encryptedPrivateKeyToPem(rval)
466469
}
467470

468471
// legacy non-PKCS#8
469472
let algorithm
470473
let iv
471474
let dkLen
472475
let cipherFn
476+
473477
switch (options.algorithm) {
474478
case 'aes128':
475479
algorithm = 'AES-128-CBC'
@@ -512,7 +516,7 @@ pki.encryptRsaPrivateKey = function (rsaKey, password, options) {
512516
const dk = opensslDeriveBytes(password, iv.substr(0, 8), dkLen)
513517
const cipher = cipherFn(dk)
514518
cipher.start(iv)
515-
cipher.update(asn1.toDer(pki.privateKeyToAsn1(rsaKey)))
519+
cipher.update(asn1.toDer(privateKeyToAsn1(rsaKey)))
516520
cipher.finish()
517521

518522
const msg = {
@@ -523,11 +527,11 @@ pki.encryptRsaPrivateKey = function (rsaKey, password, options) {
523527
},
524528
dekInfo: {
525529
algorithm,
526-
parameters: forge.util.bytesToHex(iv).toUpperCase(),
530+
parameters: bytesToHex(iv).toUpperCase(),
527531
},
528-
body: cipher.output.getBytes(),
532+
body: cipher.output?.getBytes(),
529533
}
530-
return forge.pem.encode(msg)
534+
return pem.encode(msg)
531535
}
532536

533537
/**
@@ -538,10 +542,10 @@ pki.encryptRsaPrivateKey = function (rsaKey, password, options) {
538542
*
539543
* @return the RSA key on success, null on failure.
540544
*/
541-
pki.decryptRsaPrivateKey = function (pem, password) {
545+
export function decryptRsaPrivateKey(pem: string, password: string): any {
542546
let rval = null
543547

544-
const msg = forge.pem.decode(pem)[0]
548+
const msg = pem.decode(pem)[0]
545549

546550
if (msg.type !== 'ENCRYPTED PRIVATE KEY'
547551
&& msg.type !== 'PRIVATE KEY'
@@ -585,13 +589,13 @@ pki.decryptRsaPrivateKey = function (pem, password) {
585589
case 'RC2-64-CBC':
586590
dkLen = 8
587591
cipherFn = function (key) {
588-
return forge.rc2.createDecryptionCipher(key, 64)
592+
return rc2.createDecryptionCipher(key, 64)
589593
}
590594
break
591595
case 'RC2-128-CBC':
592596
dkLen = 16
593597
cipherFn = function (key) {
594-
return forge.rc2.createDecryptionCipher(key, 128)
598+
return rc2.createDecryptionCipher(key, 128)
595599
}
596600
break
597601
default:
@@ -607,28 +611,25 @@ pki.decryptRsaPrivateKey = function (pem, password) {
607611
const cipher = cipherFn(dk)
608612
cipher.start(iv)
609613
cipher.update(createBuffer(msg.body))
610-
if (cipher.finish()) {
611-
rval = cipher.output.getBytes()
612-
}
613-
else {
614+
615+
if (cipher.finish())
616+
rval = cipher.output?.getBytes()
617+
else
614618
return rval
615-
}
619+
}
616620
}
617621
else {
618622
rval = msg.body
619623
}
620624

621-
if (msg.type === 'ENCRYPTED PRIVATE KEY') {
622-
rval = pki.decryptPrivateKeyInfo(asn1.fromDer(rval), password)
623-
}
624-
else {
625+
if (msg.type === 'ENCRYPTED PRIVATE KEY')
626+
rval = decryptPrivateKeyInfo(asn1.fromDer(rval), password)
627+
else
625628
// decryption already performed above
626629
rval = asn1.fromDer(rval)
627-
}
628630

629-
if (rval !== null) {
630-
rval = pki.privateKeyFromAsn1(rval)
631-
}
631+
if (rval !== null)
632+
rval = privateKeyFromAsn1(rval)
632633

633634
return rval
634635
}
@@ -650,10 +651,10 @@ export function generatePkcs12Key(password: string, salt: string, id: number, it
650651
let j, l
651652

652653
if (typeof md === 'undefined' || md === null) {
653-
if (!('sha1' in forge.md)) {
654+
if (!('sha1' in md))
654655
throw new Error('"sha1" hash algorithm unavailable.')
655-
}
656-
md = forge.md.sha1.create()
656+
657+
md = sha1.create()
657658
}
658659

659660
const u = md.digestLength
@@ -663,51 +664,65 @@ export function generatePkcs12Key(password: string, salt: string, id: number, it
663664
/* Convert password to Unicode byte buffer + trailing 0-byte. */
664665
const passBuf = new ByteBuffer()
665666
if (password !== null && password !== undefined) {
666-
for (l = 0; l < password.length; l++) {
667+
for (l = 0; l < password.length; l++)
667668
passBuf.putInt16(password.charCodeAt(l))
668-
}
669+
669670
passBuf.putInt16(0)
670671
}
671672

672-
/* Length of salt and password in BYTES. */
673+
/**
674+
* Length of salt and password in BYTES.
675+
*/
673676
const p = passBuf.length()
674677
const s = salt.length()
675678

676-
/* 1. Construct a string, D (the "diversifier"), by concatenating
677-
v copies of ID. */
679+
/**
680+
* 1. Construct a string, D (the "diversifier"), by concatenating v copies of ID.
681+
*/
678682
const D = new ByteBuffer()
679683
D.fillWithByte(id, v)
680684

681-
/* 2. Concatenate copies of the salt together to create a string S of length
682-
v * ceil(s / v) bytes (the final copy of the salt may be trunacted
683-
to create S).
684-
Note that if the salt is the empty string, then so is S. */
685+
/**
686+
* 2. Concatenate copies of the salt together to create a string S of length
687+
* v * ceil(s / v) bytes (the final copy of the salt may be truncated to create S).
688+
* Note that if the salt is the empty string, then so is S.
689+
*/
685690
const Slen = v * Math.ceil(s / v)
686691
const S = new ByteBuffer()
687692
for (l = 0; l < Slen; l++) {
688693
S.putByte(salt.at(l % s))
689694
}
690695

691-
/* 3. Concatenate copies of the password together to create a string P of
692-
length v * ceil(p / v) bytes (the final copy of the password may be
693-
truncated to create P).
694-
Note that if the password is the empty string, then so is P. */
696+
/**
697+
* 3. Concatenate copies of the password together to create a string P of
698+
* length v * ceil(p / v) bytes (the final copy of the password may be
699+
* truncated to create P).
700+
* Note that if the password is the empty string, then so is P.
701+
*/
695702
const Plen = v * Math.ceil(p / v)
696703
const P = new ByteBuffer()
697704
for (l = 0; l < Plen; l++) {
698705
P.putByte(passBuf.at(l % p))
699706
}
700707

701-
/* 4. Set I=S||P to be the concatenation of S and P. */
708+
/**
709+
* 4. Set I=S||P to be the concatenation of S and P.
710+
*/
702711
let I = S
703712
I.putBuffer(P)
704713

705-
/* 5. Set c=ceil(n / u). */
714+
/**
715+
* 5. Set c=ceil(n / u).
716+
*/
706717
const c = Math.ceil(n / u)
707718

708-
/* 6. For i=1, 2, ..., c, do the following: */
719+
/**
720+
* 6. For i=1, 2, ..., c, do the following:
721+
*/
709722
for (let i = 1; i <= c; i++) {
710-
/* a) Set Ai=H^r(D||I). (l.e. the rth hash of D||I, H(H(H(...H(D||I)))) */
723+
/**
724+
* a) Set Ai=H^r(D||I). (l.e. the rth hash of D||I, H(H(H(...H(D||I))))
725+
*/
711726
let buf = new ByteBuffer()
712727
buf.putBytes(D.bytes())
713728
buf.putBytes(I.bytes())
@@ -717,16 +732,20 @@ export function generatePkcs12Key(password: string, salt: string, id: number, it
717732
buf = md.digest()
718733
}
719734

720-
/* b) Concatenate copies of Ai to create a string B of length v bytes (the
721-
final copy of Ai may be truncated to create B). */
735+
/**
736+
* b) Concatenate copies of Ai to create a string B of length v bytes (the
737+
* final copy of Ai may be truncated to create B).
738+
*/
722739
const B = new ByteBuffer()
723740
for (l = 0; l < v; l++) {
724741
B.putByte(buf.at(l % u))
725742
}
726743

727-
/* c) Treating I as a concatenation I0, I1, ..., Ik-1 of v-byte blocks,
728-
where k=ceil(s / v) + ceil(p / v), modify I by setting
729-
Ij=(Ij+B+1) mod 2v for each j. */
744+
/**
745+
* c) Treating I as a concatenation I0, I1, ..., Ik-1 of v-byte blocks,
746+
* where k=ceil(s / v) + ceil(p / v), modify I by setting
747+
* Ij=(Ij+B+1) mod 2v for each j.
748+
*/
730749
const k = Math.ceil(s / v) + Math.ceil(p / v)
731750
const Inew = new ByteBuffer()
732751
for (j = 0; j < k; j++) {
@@ -741,11 +760,14 @@ export function generatePkcs12Key(password: string, salt: string, id: number, it
741760
}
742761
I = Inew
743762

744-
/* Add Ai to A. */
763+
/**
764+
* Add Ai to A.
765+
*/
745766
result.putBuffer(buf)
746767
}
747768

748769
result.truncate(result.length() - n)
770+
749771
return result
750772
}
751773

@@ -954,9 +976,8 @@ export function opensslDeriveBytes(password: string, salt: string, dkLen: number
954976
md = md5.create()
955977
}
956978

957-
if (salt === null) {
979+
if (salt === null)
958980
salt = ''
959-
}
960981

961982
const digests = [hash(md, password + salt)]
962983

@@ -977,7 +998,6 @@ export function prfOidToMessageDigest(prfOid: string): MessageDigest {
977998
if (!prfOid) {
978999
prfAlgorithm = 'hmacWithSHA1'
9791000
}
980-
9811001
else {
9821002
prfAlgorithm = oids[asn1.derToOid(prfOid)]
9831003
if (!prfAlgorithm) {
@@ -993,6 +1013,7 @@ export function prfOidToMessageDigest(prfOid: string): MessageDigest {
9931013
throw error
9941014
}
9951015
}
1016+
9961017
return prfAlgorithmToMessageDigest(prfAlgorithm)
9971018
}
9981019

@@ -1020,9 +1041,10 @@ export function prfAlgorithmToMessageDigest(prfAlgorithm: string): MessageDigest
10201041
]
10211042
throw error
10221043
}
1023-
if (!factory || !(prfAlgorithm in factory)) {
1044+
1045+
if (!factory || !(prfAlgorithm in factory))
10241046
throw new Error(`Unknown hash algorithm: ${prfAlgorithm}`)
1025-
}
1047+
10261048
return factory[prfAlgorithm].create()
10271049
}
10281050

@@ -1035,6 +1057,7 @@ export function createPbkdf2Params(salt: string, countBytes: Buffer, dkLen: numb
10351057
false,
10361058
salt,
10371059
),
1060+
10381061
// iteration count
10391062
asn1.create(asn1.Class.UNIVERSAL, asn1.Type.INTEGER, false, countBytes.getBytes()),
10401063
])

0 commit comments

Comments
 (0)