-
Notifications
You must be signed in to change notification settings - Fork 37
/
common.js
127 lines (98 loc) · 3.55 KB
/
common.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
var crypto = require('crypto');
var assert = require('assert');
var SUPPORTED_ENCRYPTION_VERSION = 3;
var SALT_BYTES = 16;
var KEY_BIT_LEN = 256;
var BLOCK_BIT_LEN = 128;
var ALGO = {
SHA1: 'sha1',
SHA256: 'sha256'
};
var NoPadding = {
/*
* Literally does nothing...
*/
pad: function (dataBytes) {
return dataBytes;
},
unpad: function (dataBytes) {
return dataBytes;
}
};
var ZeroPadding = {
/*
* Fills remaining block space with 0x00 bytes
* May cause issues if data ends with any 0x00 bytes
*/
pad: function (dataBytes, nBytesPerBlock) {
var nPaddingBytes = nBytesPerBlock - dataBytes.length % nBytesPerBlock;
var zeroBytes = new Buffer(nPaddingBytes).fill(0x00);
return Buffer.concat([ dataBytes, zeroBytes ]);
},
unpad: function (dataBytes) {
var unpaddedHex = dataBytes.toString('hex').replace(/(00)+$/, '');
return new Buffer(unpaddedHex, 'hex');
}
};
var Iso10126 = {
/*
* Fills remaining block space with random byte values, except for the
* final byte, which denotes the byte length of the padding
*/
pad: function (dataBytes, nBytesPerBlock) {
var nPaddingBytes = nBytesPerBlock - dataBytes.length % nBytesPerBlock;
var paddingBytes = crypto.randomBytes(nPaddingBytes - 1);
var endByte = new Buffer([ nPaddingBytes ]);
return Buffer.concat([ dataBytes, paddingBytes, endByte ]);
},
unpad: function (dataBytes) {
var nPaddingBytes = dataBytes[dataBytes.length - 1];
return dataBytes.slice(0, -nPaddingBytes);
}
};
var Iso97971 = {
/*
* Fills remaining block space with 0x00 bytes following a 0x80 byte,
* which serves as a mark for where the padding begins
*/
pad: function (dataBytes, nBytesPerBlock) {
var withStartByte = Buffer.concat([ dataBytes, new Buffer([ 0x80 ]) ]);
return ZeroPadding.pad(withStartByte, nBytesPerBlock);
},
unpad: function (dataBytes) {
var zeroBytesRemoved = ZeroPadding.unpad(dataBytes);
return zeroBytesRemoved.slice(0, zeroBytesRemoved.length - 1);
}
};
var AES = {
CBC: 'aes-256-cbc',
OFB: 'aes-256-ofb',
ECB: 'aes-256-ecb',
/*
* Encrypt / Decrypt with aes-256
* - dataBytes, key, and salt are expected to be buffers
* - default options are mode=CBC and padding=auto (PKCS7)
*/
encrypt: function (dataBytes, key, salt, options) {
options = options || {};
assert(Buffer.isBuffer(dataBytes), 'expected `dataBytes` to be a Buffer');
assert(Buffer.isBuffer(key), 'expected `key` to be a Buffer');
assert(Buffer.isBuffer(salt) || salt === null, 'expected `salt` to be a Buffer or null');
var cipher = crypto.createCipheriv(options.mode || AES.CBC, key, salt || '');
cipher.setAutoPadding(!options.padding);
if (options.padding) dataBytes = options.padding.pad(dataBytes, BLOCK_BIT_LEN / 8);
var encryptedBytes = Buffer.concat([ cipher.update(dataBytes), cipher.final() ]);
return encryptedBytes;
},
decrypt: function (dataBytes, key, salt, options) {
options = options || {};
assert(Buffer.isBuffer(dataBytes), 'expected `dataBytes` to be a Buffer');
assert(Buffer.isBuffer(key), 'expected `key` to be a Buffer');
assert(Buffer.isBuffer(salt) || salt === null, 'expected `salt` to be a Buffer or null');
var decipher = crypto.createDecipheriv(options.mode || AES.CBC, key, salt || '');
decipher.setAutoPadding(!options.padding);
var decryptedBytes = Buffer.concat([ decipher.update(dataBytes), decipher.final() ]);
if (options.padding) decryptedBytes = options.padding.unpad(decryptedBytes);
return decryptedBytes;
}
};