Skip to content
File

Blob: src/node/internal/crypto_pbkdf2.ts

typescript123 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 { Buffer } from 'node-internal:internal_buffer';
29 
30import {
31 validateInt32,
32 validateFunction,
33 validateString,
34} from 'node-internal:validators';
35 
36import { getArrayBufferOrView } from 'node-internal:crypto_util';
37 
38export type ArrayLike = cryptoImpl.ArrayLike;
39 
40export function pbkdf2Sync(
41 password: ArrayLike,
42 salt: ArrayLike,
43 iterations: number,
44 keylen: number,
45 digest: string
46): Buffer {
47 ({ password, salt, iterations, keylen, digest } = check(
48 password,
49 salt,
50 iterations,
51 keylen,
52 digest
53 ));
54 
55 const result = cryptoImpl.getPbkdf(
56 password,
57 salt,
58 iterations,
59 keylen,
60 digest
61 );
62 return Buffer.from(result);
63}
64 
65export type Pbkdf2Callback = (err?: Error | null, result?: Buffer) => void;
66export function pbkdf2(
67 password: ArrayLike,
68 salt: ArrayLike,
69 iterations: number,
70 keylen: number,
71 digest: string,
72 callback: Pbkdf2Callback
73): void {
74 if (typeof digest === 'function') {
75 // Appease node test cases
76 validateString(undefined, 'digest');
77 }
78 validateFunction(callback, 'callback');
79 ({ password, salt, iterations, keylen, digest } = check(
80 password,
81 salt,
82 iterations,
83 keylen,
84 digest
85 ));
86 
87 new Promise<ArrayBuffer>((res, rej) => {
88 try {
89 res(cryptoImpl.getPbkdf(password, salt, iterations, keylen, digest));
90 } catch (err) {
91 rej(err as Error);
92 }
93 }).then(
94 (val: ArrayBuffer): unknown => callback(null, Buffer.from(val)),
95 (err: unknown): unknown => callback(err as Error)
96 );
97}
98 
99function check(
100 password: ArrayLike | ArrayBufferView,
101 salt: ArrayLike | ArrayBufferView,
102 iterations: number,
103 keylen: number,
104 digest: string
105): {
106 password: ArrayLike | ArrayBufferView;
107 salt: ArrayLike | ArrayBufferView;
108 iterations: number;
109 keylen: number;
110 digest: string;
111} {
112 validateString(digest, 'digest');
113 
114 password = getArrayBufferOrView(password, 'password');
115 salt = getArrayBufferOrView(salt, 'salt');
116 // OpenSSL uses a signed int to represent these values, so we are restricted
117 // to the 31-bit range here (which is plenty).
118 validateInt32(iterations, 'iterations', 1);
119 validateInt32(keylen, 'keylen', 0);
120 
121 return { password, salt, iterations, keylen, digest };
122}