Skip to content

Commit 256b727

Browse files
committed
fixup! crypto: add a generic MAC API
1 parent eb8c502 commit 256b727

6 files changed

Lines changed: 208 additions & 62 deletions

File tree

benchmark/crypto/mac.js

Lines changed: 106 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,19 @@ if (!hasOpenSSL(3) ||
1717
process.exit(0);
1818
}
1919

20-
const isTest = process.argv.includes('--test');
20+
const operations = [
21+
'get-macs-cold',
22+
'get-macs-warm',
23+
'create-cold',
24+
'create-warm',
25+
'hmac-lifecycle',
26+
'mac-lifecycle',
27+
'mac-stream-lifecycle',
28+
'update',
29+
'stream',
30+
'final-buffer',
31+
'final-hex',
32+
];
2133
const configurations = {
2234
'hmac-sha256': {
2335
algorithm: 'HMAC',
@@ -32,24 +44,12 @@ const configurations = {
3244
};
3345

3446
const bench = common.createBenchmark(main, {
35-
operation: [
36-
'get-macs-cold',
37-
'get-macs-warm',
38-
'create-cold',
39-
'create-warm',
40-
'create-hmac',
41-
'update',
42-
'stream',
43-
],
47+
operation: operations,
4448
algorithm: Object.keys(configurations),
4549
length: [0, 64, 4096],
4650
n: [1, 10_000, 20_000, 500_000],
4751
}, {
4852
combinationFilter({ operation, algorithm, length, n }) {
49-
if (isTest) {
50-
return algorithm === 'hmac-sha256' && length === 0 && n === 1;
51-
}
52-
5353
if (operation === 'get-macs-cold') {
5454
return algorithm === 'hmac-sha256' && length === 0 && n === 1;
5555
}
@@ -60,11 +60,25 @@ const bench = common.createBenchmark(main, {
6060
return length === 0 && n === 1;
6161
if (operation === 'create-warm')
6262
return length === 0 && n === 20_000;
63-
if (operation === 'create-hmac' && algorithm !== 'hmac-sha256')
64-
return false;
65-
return n === 10_000;
63+
if (operation === 'hmac-lifecycle') {
64+
return algorithm === 'hmac-sha256' && n === 10_000;
65+
}
66+
if (operation === 'mac-lifecycle' ||
67+
operation === 'mac-stream-lifecycle') {
68+
return n === 10_000;
69+
}
70+
if (operation === 'update' || operation === 'stream') {
71+
return length === 64 && n === 500_000;
72+
}
73+
if (operation === 'final-buffer' || operation === 'final-hex') {
74+
return algorithm === 'hmac-sha256' &&
75+
length === 64 &&
76+
n === 20_000;
77+
}
78+
return false;
6679
},
6780
test: {
81+
operation: ['get-macs-cold', 'create-cold'],
6882
algorithm: ['hmac-sha256'],
6983
length: [0],
7084
n: [1],
@@ -88,15 +102,27 @@ function main({ operation, algorithm, length, n }) {
88102
case 'create-warm':
89103
measureCreate(configuration, n, true);
90104
break;
91-
case 'create-hmac':
92-
measureCreateHmac(configuration, data, n);
105+
case 'hmac-lifecycle':
106+
measureHmacLifecycle(configuration, data, n);
107+
break;
108+
case 'mac-lifecycle':
109+
measureMacLifecycle(configuration, data, n);
110+
break;
111+
case 'mac-stream-lifecycle':
112+
measureMacStreamLifecycle(configuration, data, n);
93113
break;
94114
case 'update':
95115
measureUpdate(configuration, data, n);
96116
break;
97117
case 'stream':
98118
measureStream(configuration, data, n);
99119
break;
120+
case 'final-buffer':
121+
measureFinal(configuration, data, n);
122+
break;
123+
case 'final-hex':
124+
measureFinal(configuration, data, n, 'hex');
125+
break;
100126
default:
101127
throw new Error(`unknown operation: ${operation}`);
102128
}
@@ -128,7 +154,7 @@ function measureCreate({ algorithm, key, options }, n, warm) {
128154
assert.strictEqual(typeof contexts[n - 1], 'object');
129155
}
130156

131-
function measureCreateHmac({ key, options }, data, n) {
157+
function measureHmacLifecycle({ key, options }, data, n) {
132158
createHmac(options.digest, key).update(data).digest();
133159

134160
let result;
@@ -140,7 +166,7 @@ function measureCreateHmac({ key, options }, data, n) {
140166
assert(Buffer.isBuffer(result));
141167
}
142168

143-
function measureUpdate({ algorithm, key, options }, data, n) {
169+
function measureMacLifecycle({ algorithm, key, options }, data, n) {
144170
createMac(algorithm, key, options).update(data).final();
145171

146172
let result;
@@ -152,7 +178,7 @@ function measureUpdate({ algorithm, key, options }, data, n) {
152178
assert(Buffer.isBuffer(result));
153179
}
154180

155-
function measureStream({ algorithm, key, options }, data, n) {
181+
function measureMacStreamLifecycle({ algorithm, key, options }, data, n) {
156182
const warmup = createMac(algorithm, key, options);
157183
warmup.end(data);
158184
warmup.read();
@@ -168,3 +194,61 @@ function measureStream({ algorithm, key, options }, data, n) {
168194

169195
assert(Buffer.isBuffer(result));
170196
}
197+
198+
function measureUpdate({ algorithm, key, options }, data, n) {
199+
const warmup = createMac(algorithm, key, options);
200+
warmup.update(data).final();
201+
202+
const context = createMac(algorithm, key, options);
203+
bench.start();
204+
for (let i = 0; i < n; ++i)
205+
context.update(data);
206+
bench.end(n);
207+
208+
assert(Buffer.isBuffer(context.final()));
209+
}
210+
211+
function measureStream({ algorithm, key, options }, data, n) {
212+
const warmup = createMac(algorithm, key, options);
213+
warmup.end(data);
214+
warmup.read();
215+
216+
const context = createMac(algorithm, key, options);
217+
bench.start();
218+
for (let i = 0; i < n; ++i)
219+
context.write(data);
220+
bench.end(n);
221+
222+
context.end();
223+
assert(Buffer.isBuffer(context.read()));
224+
}
225+
226+
function measureFinal({ algorithm, key, options }, data, n, encoding) {
227+
const warmup = createMac(algorithm, key, options).update(data);
228+
if (encoding === undefined)
229+
warmup.final();
230+
else
231+
warmup.final(encoding);
232+
233+
const contexts = new Array(n);
234+
for (let i = 0; i < n; ++i)
235+
contexts[i] = createMac(algorithm, key, options).update(data);
236+
237+
let result;
238+
if (encoding === undefined) {
239+
bench.start();
240+
for (let i = 0; i < n; ++i)
241+
result = contexts[i].final();
242+
bench.end(n);
243+
} else {
244+
bench.start();
245+
for (let i = 0; i < n; ++i)
246+
result = contexts[i].final(encoding);
247+
bench.end(n);
248+
}
249+
250+
if (encoding === undefined)
251+
assert(Buffer.isBuffer(result));
252+
else
253+
assert.strictEqual(typeof result, 'string');
254+
}

lib/internal/crypto/provider_mac.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ const {
1313
} = internalBinding('crypto');
1414

1515
const {
16-
getArrayBufferOrView,
1716
getCachedMacId,
1817
getMacCache,
1918
kHandle,
@@ -69,7 +68,7 @@ function normalizeBytes(value, name) {
6968
throw new ERR_INVALID_ARG_TYPE(
7069
name, ['ArrayBuffer', 'Buffer', 'TypedArray', 'DataView'], value);
7170
}
72-
return getArrayBufferOrView(value, name);
71+
return value;
7372
}
7473

7574
function createHandle(algorithm, key, options) {
@@ -80,6 +79,7 @@ function createHandle(algorithm, key, options) {
8079
let customization;
8180
let salt;
8281
let outputLength;
82+
let hasExtendedOptions = false;
8383

8484
if (options !== undefined) {
8585
validateObject(options, 'options');
@@ -91,31 +91,39 @@ function createHandle(algorithm, key, options) {
9191
const cipherOption = options.cipher;
9292
if (cipherOption !== undefined) {
9393
cipher = validateName(cipherOption, 'options.cipher');
94+
hasExtendedOptions = true;
9495
}
9596
const ivOption = options.iv;
9697
if (ivOption !== undefined) {
9798
iv = normalizeBytes(ivOption, 'options.iv');
99+
hasExtendedOptions = true;
98100
}
99101
const customizationOption = options.customization;
100102
if (customizationOption !== undefined) {
101103
customization = normalizeBytes(
102104
customizationOption, 'options.customization');
105+
hasExtendedOptions = true;
103106
}
104107
const saltOption = options.salt;
105108
if (saltOption !== undefined) {
106109
salt = normalizeBytes(saltOption, 'options.salt');
110+
hasExtendedOptions = true;
107111
}
108112
const outputLengthOption = options.outputLength;
109113
if (outputLengthOption !== undefined) {
110114
outputLength = outputLengthOption;
111115
validateUint32(outputLength, 'options.outputLength');
112116
outputLength += 0;
117+
hasExtendedOptions = true;
113118
}
114119
}
115120

116121
key = normalizeKey(key);
117122
const id = getCachedMacId(name);
118123
const cache = getMacCache();
124+
if (!hasExtendedOptions) {
125+
return new _Mac(name, id, cache, key, digest);
126+
}
119127
return new _Mac(
120128
name,
121129
id,
@@ -142,7 +150,7 @@ function normalizeKey(key) {
142150
throw new ERR_INVALID_ARG_TYPE(
143151
'key', ['ArrayBuffer', 'Buffer', 'TypedArray', 'DataView', 'KeyObject'], key);
144152
}
145-
return getArrayBufferOrView(key, 'key');
153+
return key;
146154
}
147155

148156
function normalizeOutputEncoding(outputEncoding) {
@@ -167,10 +175,6 @@ function normalizeInputEncoding(data, inputEncoding) {
167175
return normalized;
168176
}
169177

170-
function encodeOutput(result, outputEncoding) {
171-
return outputEncoding === 'buffer' ? result : result.toString(outputEncoding);
172-
}
173-
174178
function updateHandle(mac, data, encoding) {
175179
const state = mac[kState];
176180
let updated;
@@ -186,10 +190,10 @@ function updateHandle(mac, data, encoding) {
186190
}
187191
}
188192

189-
function finalizeHandle(mac) {
193+
function finalizeHandle(mac, outputEncoding) {
190194
const state = mac[kState];
191195
state[kFinalized] = true;
192-
return mac[kHandle].final();
196+
return mac[kHandle].final(outputEncoding);
193197
}
194198

195199
function Mac(algorithm, key, options) {
@@ -249,7 +253,8 @@ Mac.prototype.final = function final(outputEncoding) {
249253
if (this[kState][kFinalized]) throw new ERR_CRYPTO_MAC_FINALIZED();
250254
if (outputEncoding === undefined) return finalizeHandle(this);
251255
outputEncoding = normalizeOutputEncoding(outputEncoding);
252-
return encodeOutput(finalizeHandle(this), outputEncoding);
256+
if (outputEncoding === 'buffer') return finalizeHandle(this);
257+
return finalizeHandle(this, outputEncoding);
253258
};
254259

255260
module.exports = {

0 commit comments

Comments
 (0)