-
Notifications
You must be signed in to change notification settings - Fork 0
/
forgewrap.js
204 lines (186 loc) · 4.82 KB
/
forgewrap.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// Library for forge and Buffer compatibility.
var Buffer = require('buffer/').Buffer;
var forge = require("node-forge");
/**
* Result of an AES Encryption operation
* @class
* @property {Buffer} enc Encrypted data
* @property {Buffer} tag Authentication tag
*/
class AESGCMEncryptionResult {
constructor(enc, tag) {
this.enc = enc;
this.tag = tag;
}
}
/**
* Converts Forge Buffer into Buffer.
* @param {forge.util.ByteStringBuffer} x Input
* @returns {Buffer} Output
*/
function fb2b(x) {
return Buffer.from(x.toHex(), "hex");
}
/**
* Converts Forge String into Buffer.
* @param {string} x Input
* @returns {Buffer} Output
*/
function fs2b(x) {
return Buffer.from(fs2fb(x).toHex(), "hex");
}
/**
* Converts Forge String into Forge Buffer.
* @param {string} x Input
* @returns {forge.util.ByteStringBuffer} Output
*/
function fs2fb(x) {
return forge.util.createBuffer(x);
}
/**
* Converts Forge Buffer into Forge String.
* @param {forge.util.ByteStringBuffer} x Input
* @returns {string} Output
*/
function fb2fs(x) {
return x.bytes();
}
/**
* Converts Buffer into Forge Buffer
* @param {Buffer} x Input
* @returns {forge.util.ByteStringBuffer} Output
*/
function b2fb(x) {
return forge.util.createBuffer(x);
}
/**
* Converts Buffer into Forge String
* @param {Buffer} x Input
* @returns {forge.util.ByteStringBuffer} Output
*/
function b2fs(x) {
return b2fb(x).bytes();
}
/**
* Encrypts data with RSA.
* Maximum plaintext length is (k.n.toString(2).length / 8) - 11
* @param {forge.pki.rsa.PublicKey} k Public key
* @param {Buffer} x Plaintext
* @returns {Buffer} Ciphertext
*/
function rsaEncrypt(k, x) {
return fs2b(k.encrypt(b2fs(x)));
}
/**
* Generates RSA keypair.
* NOTE: genKeyAsync is much much faster than this.
* @param {number} b Bits
* @param {number} e Exponent
* @returns {forge.pki.rsa.KeyPair} Keypair
*/
function rsaGenKey(b = 2048, e = 0x10001) {
return forge.pki.rsa.generateKeyPair({bits: b, e});
}
/**
* Generates RSA keypair.
* @async
* @param {number} b Bits
* @param {number} e Exponent
* @returns {Promise<forge.pki.rsa.KeyPair>} Keypair
*/
function rsaGenKeyAsync(b = 2048, e = 0x10001) {
return new Promise((resolve, reject) => {
forge.pki.rsa.generateKeyPair({bits: b, e}, (err, keypair) => {
if (err) reject(err);
else resolve(keypair);
});
});
}
/**
* Decrypts data with RSA.
* Maximum plaintext length is (k.n.toString(2).length / 8) - 11
* @param {forge.pki.rsa.PrivateKey} k Private key
* @param {Buffer} x Ciphertext
* @returns {Buffer} Plaintext
*/
function rsaDecrypt(k, x) {
return fs2b(k.decrypt(b2fs(x)));
}
/**
* Generates an IV for use with AES-GCM.
* @param {number} [l=12] IV length in bytes
* @returns {Buffer} IV
*/
function aesGenIV(l = 12) {
return fs2b(forge.random.getBytesSync(l));
}
/**
* Generates a key for use with AES-GCM.
* @param {number} [l=32] Key length in bytes
* @returns {Buffer} Key
*/
function aesGenKey(l = 32) {
return fs2b(forge.random.getBytesSync(l));
}
/**
* Encrypts data with AES-GCM.
* @param {Buffer} k Key
* @param {Buffer} iv IV
* @param {Buffer} x Plaintext
* @param {number} [tagLength=128] Tag length in bits
* @returns {AESGCMEncryptionResult} Ciphertext and Authentication Tag
*/
function aesEncrypt(k, iv, x, tagLength = 128) {
var cipher = forge.cipher.createCipher("AES-GCM", b2fb(k));
cipher.start({
iv: b2fb(iv),
tagLength
});
cipher.update(b2fb(x));
cipher.finish();
return new AESGCMEncryptionResult(fb2b(cipher.output), fb2b(cipher.mode.tag));
}
/**
* Decrypts data with AES-GCM.
* @param {Buffer} k Key
* @param {Buffer} iv IV
* @param {Buffer} tag Authentication Tag
* @param {Buffer} x Ciphertext
* @param {number} [tagLength=128]
* @returns {Buffer|null} Plaintext or null if authentication is invalid
*/
function aesDecrypt(k, iv, tag, x, tagLength = 128) {
var cipher = forge.cipher.createDecipher("AES-GCM", b2fb(k));
cipher.start({
iv: b2fb(iv),
tag: b2fb(tag),
tagLength
});
cipher.update(b2fb(x));
var pass = cipher.finish();
if (pass) return fb2b(cipher.output);
else return null;
}
module.exports = {
util: {
fb2b,
fs2b,
fs2fb,
fb2fs,
b2fb,
b2fs,
},
rsa: {
genKey: rsaGenKey,
genKeyAsync: rsaGenKeyAsync,
encrypt: rsaEncrypt,
decrypt: rsaDecrypt
},
aesgcm: {
AESGCMEncryptionResult: AESGCMEncryptionResult,
genIV: aesGenIV,
genKey: aesGenKey,
encrypt: aesEncrypt,
decrypt: aesDecrypt
}
}