Skip to content
File

Blob: src/node/internal/crypto_hkdf.ts

typescript165 lines
1// Copyright (c) 2017-2023 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4//
5// Copyright Joyent, Inc. and other Node contributors.
6//
7// Permission is hereby granted, free of charge, to any person obtaining a
8// copy of this software and associated documentation files (the
9// "Software"), to deal in the Software without restriction, including
10// without limitation the rights to use, copy, modify, merge, publish,
11// distribute, sublicense, and/or sell copies of the Software, and to permit
12// persons to whom the Software is furnished to do so, subject to the
13// following conditions:
14//
15// The above copyright notice and this permission notice shall be included
16// in all copies or substantial portions of the Software.
17//
18// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
21// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
22// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24// USE OR OTHER DEALINGS IN THE SOFTWARE.
25 
26import { default as cryptoImpl } from 'node-internal:crypto';
27 
28import {
29 validateFunction,
30 validateInteger,
31 validateString,
32} from 'node-internal:validators';
33 
34import { KeyObject } from 'node-internal:crypto_keys';
35 
36type ArrayLike = cryptoImpl.ArrayLike;
37 
38import { kMaxLength } from 'node-internal:internal_buffer';
39 
40import { toBuf, validateByteSource } from 'node-internal:crypto_util';
41 
42import {
43 isAnyArrayBuffer,
44 isArrayBufferView,
45} from 'node-internal:internal_types';
46 
47import {
48 ERR_INVALID_ARG_TYPE,
49 ERR_OUT_OF_RANGE,
50} from 'node-internal:internal_errors';
51 
52function validateParameters(
53 hash: string,
54 key: ArrayLike | KeyObject,
55 salt: ArrayLike,
56 info: ArrayLike,
57 length: number
58): {
59 hash: string;
60 key: ArrayLike;
61 salt: ArrayLike;
62 info: ArrayLike;
63 length: number;
64} {
65 if (key instanceof KeyObject) {
66 key = key.export() as ArrayLike;
67 }
68 
69 validateString(hash, 'digest');
70 key = prepareKey(key as unknown as ArrayLike);
71 salt = validateByteSource(salt, 'salt');
72 info = validateByteSource(info, 'info');
73 
74 validateInteger(length, 'length', 0, kMaxLength);
75 
76 if (info.byteLength > 1024) {
77 throw new ERR_OUT_OF_RANGE(
78 'info',
79 'must not contain more than 1024 bytes',
80 info.byteLength
81 );
82 }
83 
84 return {
85 hash,
86 key,
87 salt,
88 info,
89 length,
90 };
91}
92 
93function prepareKey(key: ArrayLike): ArrayLike {
94 key = toBuf(key);
95 
96 if (!isAnyArrayBuffer(key) && !isArrayBufferView(key)) {
97 throw new ERR_INVALID_ARG_TYPE(
98 'ikm',
99 [
100 'string',
101 'SecretKeyObject',
102 'ArrayBuffer',
103 'TypedArray',
104 'DataView',
105 'Buffer',
106 ],
107 key
108 );
109 }
110 
111 return key;
112}
113 
114export function hkdf(
115 hash: string,
116 key: ArrayLike | KeyObject,
117 salt: ArrayLike,
118 info: ArrayLike,
119 length: number,
120 callback: (err: Error | null, derivedKey?: ArrayBuffer) => void
121): void {
122 ({ hash, key, salt, info, length } = validateParameters(
123 hash,
124 key,
125 salt,
126 info,
127 length
128 ));
129 
130 validateFunction(callback, 'callback');
131 
132 new Promise<ArrayBuffer>((res, rej) => {
133 try {
134 res(cryptoImpl.getHkdf(hash, key, salt, info, length));
135 } catch (err) {
136 rej(err as Error);
137 }
138 }).then(
139 (val: ArrayBuffer): void => {
140 callback(null, val);
141 },
142 (err: unknown): void => {
143 callback(err);
144 }
145 );
146}
147 
148export function hkdfSync(
149 hash: string,
150 key: ArrayLike | KeyObject,
151 salt: ArrayLike,
152 info: ArrayLike,
153 length: number
154): ArrayBuffer {
155 ({ hash, key, salt, info, length } = validateParameters(
156 hash,
157 key,
158 salt,
159 info,
160 length
161 ));
162 
163 return cryptoImpl.getHkdf(hash, key, salt, info, length);
164}