@reallyme/crypto 0.1.8 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +148 -18
- package/dist/aead.d.ts +4 -0
- package/dist/aead.js +40 -16
- package/dist/aesKw.d.ts +8 -2
- package/dist/aesKw.js +69 -12
- package/dist/algorithms.d.ts +12 -4
- package/dist/algorithms.js +8 -2
- package/dist/argon2id.d.ts +3 -0
- package/dist/argon2id.js +18 -3
- package/dist/cryptoFacade.d.ts +66 -5
- package/dist/cryptoFacade.js +99 -38
- package/dist/errors.d.ts +1 -1
- package/dist/hkdf.d.ts +1 -0
- package/dist/hkdf.js +5 -1
- package/dist/hmac.d.ts +3 -0
- package/dist/hmac.js +24 -3
- package/dist/hpke.d.ts +4 -1
- package/dist/hpke.js +45 -14
- package/dist/index.d.ts +14 -13
- package/dist/index.js +12 -10
- package/dist/jwaConcatKdf.js +8 -4
- package/dist/jwk.d.ts +2 -1
- package/dist/jwk.js +158 -122
- package/dist/kmac.d.ts +11 -0
- package/dist/kmac.js +49 -0
- package/dist/memory.d.ts +8 -0
- package/dist/memory.js +13 -0
- package/dist/mlDsa.d.ts +5 -0
- package/dist/mlDsa.js +43 -9
- package/dist/mlKem.d.ts +5 -2
- package/dist/mlKem.js +37 -26
- package/dist/operationResponse.d.ts +16 -0
- package/dist/operationResponse.js +46 -0
- package/dist/p256Ecdh.js +5 -1
- package/dist/p384Ecdh.js +5 -1
- package/dist/p521Ecdh.js +5 -1
- package/dist/pbkdf2.d.ts +6 -8
- package/dist/pbkdf2.js +12 -12
- package/dist/proto/generated/reallyme/crypto/v1/crypto_pb.d.ts +2859 -128
- package/dist/proto/generated/reallyme/crypto/v1/crypto_pb.js +992 -132
- package/dist/proto.d.ts +99 -7
- package/dist/proto.js +741 -16
- package/dist/rsa.d.ts +4 -1
- package/dist/rsa.js +23 -16
- package/dist/slhDsa.d.ts +5 -0
- package/dist/slhDsa.js +40 -9
- package/dist/validateBytes.d.ts +7 -1
- package/dist/validateBytes.js +63 -3
- package/dist/wasm/reallyme_crypto_wasm.js +77 -365
- package/dist/wasm/reallyme_crypto_wasm_bg.wasm +0 -0
- package/dist/wasmModuleTypes.d.ts +9 -21
- package/dist/wasmProvider.d.ts +12 -29
- package/dist/wasmProvider.js +25 -43
- package/dist/xWing.d.ts +5 -4
- package/dist/xWing.js +40 -40
- package/package.json +20 -2
- package/dist/codecs.d.ts +0 -35
- package/dist/codecs.js +0 -216
- package/dist/proto/generated/reallyme/codec/v1/codec_pb.d.ts +0 -253
- package/dist/proto/generated/reallyme/codec/v1/codec_pb.js +0 -160
package/dist/mlKem.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import { ReallyMeCryptoError } from "./errors.js";
|
|
5
|
-
import { ensureBytes,
|
|
5
|
+
import { ensureBytes, readIndependentByteArrayProperty, readIndependentProviderBytes, } from "./validateBytes.js";
|
|
6
6
|
import { requireReallyMeWasmProvider } from "./wasmProvider.js";
|
|
7
7
|
export const ML_KEM_512_PUBLIC_KEY_LENGTH = 800;
|
|
8
8
|
export const ML_KEM_512_CIPHERTEXT_LENGTH = 768;
|
|
@@ -11,10 +11,12 @@ export const ML_KEM_768_CIPHERTEXT_LENGTH = 1_088;
|
|
|
11
11
|
export const ML_KEM_1024_PUBLIC_KEY_LENGTH = 1_568;
|
|
12
12
|
export const ML_KEM_1024_CIPHERTEXT_LENGTH = 1_568;
|
|
13
13
|
export const ML_KEM_SECRET_KEY_LENGTH = 64;
|
|
14
|
-
export const ML_KEM_ENCAPSULATION_RANDOMNESS_LENGTH = 32;
|
|
15
14
|
export const ML_KEM_SHARED_SECRET_LENGTH = 32;
|
|
16
15
|
const mlKemSuite = (algorithm) => {
|
|
17
16
|
const provider = requireReallyMeWasmProvider();
|
|
17
|
+
return mlKemSuiteWithProvider(algorithm, provider);
|
|
18
|
+
};
|
|
19
|
+
const mlKemSuiteWithProvider = (algorithm, provider) => {
|
|
18
20
|
switch (algorithm) {
|
|
19
21
|
case "ML-KEM-512":
|
|
20
22
|
return {
|
|
@@ -23,7 +25,6 @@ const mlKemSuite = (algorithm) => {
|
|
|
23
25
|
generateKeyPair: provider.mlKem512GenerateKeypair,
|
|
24
26
|
deriveKeyPair: provider.mlKem512DeriveKeypair,
|
|
25
27
|
encapsulate: provider.mlKem512Encapsulate,
|
|
26
|
-
encapsulateDerand: provider.mlKem512EncapsulateDerand,
|
|
27
28
|
decapsulate: provider.mlKem512Decapsulate,
|
|
28
29
|
};
|
|
29
30
|
case "ML-KEM-768":
|
|
@@ -33,7 +34,6 @@ const mlKemSuite = (algorithm) => {
|
|
|
33
34
|
generateKeyPair: provider.mlKem768GenerateKeypair,
|
|
34
35
|
deriveKeyPair: provider.mlKem768DeriveKeypair,
|
|
35
36
|
encapsulate: provider.mlKem768Encapsulate,
|
|
36
|
-
encapsulateDerand: provider.mlKem768EncapsulateDerand,
|
|
37
37
|
decapsulate: provider.mlKem768Decapsulate,
|
|
38
38
|
};
|
|
39
39
|
case "ML-KEM-1024":
|
|
@@ -43,55 +43,66 @@ const mlKemSuite = (algorithm) => {
|
|
|
43
43
|
generateKeyPair: provider.mlKem1024GenerateKeypair,
|
|
44
44
|
deriveKeyPair: provider.mlKem1024DeriveKeypair,
|
|
45
45
|
encapsulate: provider.mlKem1024Encapsulate,
|
|
46
|
-
encapsulateDerand: provider.mlKem1024EncapsulateDerand,
|
|
47
46
|
decapsulate: provider.mlKem1024Decapsulate,
|
|
48
47
|
};
|
|
49
48
|
default:
|
|
50
49
|
throw new ReallyMeCryptoError("unsupported-algorithm");
|
|
51
50
|
}
|
|
52
51
|
};
|
|
53
|
-
const readKeyPair = (value, suite) =>
|
|
54
|
-
publicKey
|
|
55
|
-
secretKey
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
ensureBytes(value, ML_KEM_SHARED_SECRET_LENGTH);
|
|
66
|
-
return value;
|
|
52
|
+
const readKeyPair = (value, suite, inputs = []) => {
|
|
53
|
+
const publicKey = readIndependentByteArrayProperty(value, "publicKey", suite.publicKeyLength, inputs);
|
|
54
|
+
const secretKey = readIndependentByteArrayProperty(value, "secretKey", ML_KEM_SECRET_KEY_LENGTH, [...inputs, publicKey]);
|
|
55
|
+
return { publicKey, secretKey };
|
|
56
|
+
};
|
|
57
|
+
const readEncapsulation = (value, suite, inputs) => {
|
|
58
|
+
const ciphertext = readIndependentByteArrayProperty(value, "ciphertext", suite.ciphertextLength, inputs);
|
|
59
|
+
const sharedSecret = readIndependentByteArrayProperty(value, "sharedSecret", ML_KEM_SHARED_SECRET_LENGTH, [...inputs, ciphertext]);
|
|
60
|
+
return { ciphertext, sharedSecret };
|
|
61
|
+
};
|
|
62
|
+
const readSharedSecret = (value, inputs) => {
|
|
63
|
+
return readIndependentProviderBytes(value, ML_KEM_SHARED_SECRET_LENGTH, inputs);
|
|
67
64
|
};
|
|
68
65
|
export const ReallyMeMlKem = {
|
|
69
66
|
generateKeyPair(algorithm) {
|
|
70
67
|
const suite = mlKemSuite(algorithm);
|
|
71
68
|
return readKeyPair(suite.generateKeyPair(), suite);
|
|
72
69
|
},
|
|
70
|
+
generateKeyPairWithProvider(provider, algorithm) {
|
|
71
|
+
const suite = mlKemSuiteWithProvider(algorithm, provider);
|
|
72
|
+
return readKeyPair(suite.generateKeyPair(), suite);
|
|
73
|
+
},
|
|
73
74
|
deriveKeyPair(algorithm, secretKey) {
|
|
74
75
|
// Import an existing FIPS 203 seed-form secret and reconstruct its public
|
|
75
76
|
// key. Do not feed passwords or other low-entropy material here.
|
|
76
77
|
const suite = mlKemSuite(algorithm);
|
|
77
78
|
ensureBytes(secretKey, ML_KEM_SECRET_KEY_LENGTH);
|
|
78
|
-
return readKeyPair(suite.deriveKeyPair(secretKey), suite);
|
|
79
|
+
return readKeyPair(suite.deriveKeyPair(secretKey), suite, [secretKey]);
|
|
80
|
+
},
|
|
81
|
+
deriveKeyPairWithProvider(provider, algorithm, secretKey) {
|
|
82
|
+
const suite = mlKemSuiteWithProvider(algorithm, provider);
|
|
83
|
+
ensureBytes(secretKey, ML_KEM_SECRET_KEY_LENGTH);
|
|
84
|
+
return readKeyPair(suite.deriveKeyPair(secretKey), suite, [secretKey]);
|
|
79
85
|
},
|
|
80
86
|
encapsulate(algorithm, publicKey) {
|
|
81
87
|
const suite = mlKemSuite(algorithm);
|
|
82
88
|
ensureBytes(publicKey, suite.publicKeyLength);
|
|
83
|
-
return readEncapsulation(suite.encapsulate(publicKey), suite);
|
|
89
|
+
return readEncapsulation(suite.encapsulate(publicKey), suite, [publicKey]);
|
|
84
90
|
},
|
|
85
|
-
|
|
86
|
-
const suite =
|
|
91
|
+
encapsulateWithProvider(provider, algorithm, publicKey) {
|
|
92
|
+
const suite = mlKemSuiteWithProvider(algorithm, provider);
|
|
87
93
|
ensureBytes(publicKey, suite.publicKeyLength);
|
|
88
|
-
|
|
89
|
-
return readEncapsulation(suite.encapsulateDerand(publicKey, randomness), suite);
|
|
94
|
+
return readEncapsulation(suite.encapsulate(publicKey), suite, [publicKey]);
|
|
90
95
|
},
|
|
91
96
|
decapsulate(algorithm, ciphertext, secretKey) {
|
|
92
97
|
const suite = mlKemSuite(algorithm);
|
|
93
98
|
ensureBytes(ciphertext, suite.ciphertextLength);
|
|
94
99
|
ensureBytes(secretKey, ML_KEM_SECRET_KEY_LENGTH);
|
|
95
|
-
return readSharedSecret(suite.decapsulate(ciphertext, secretKey));
|
|
100
|
+
return readSharedSecret(suite.decapsulate(ciphertext, secretKey), [ciphertext, secretKey]);
|
|
101
|
+
},
|
|
102
|
+
decapsulateWithProvider(provider, algorithm, ciphertext, secretKey) {
|
|
103
|
+
const suite = mlKemSuiteWithProvider(algorithm, provider);
|
|
104
|
+
ensureBytes(ciphertext, suite.ciphertextLength);
|
|
105
|
+
ensureBytes(secretKey, ML_KEM_SECRET_KEY_LENGTH);
|
|
106
|
+
return readSharedSecret(suite.decapsulate(ciphertext, secretKey), [ciphertext, secretKey]);
|
|
96
107
|
},
|
|
97
108
|
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ReallyMeWasmProvider } from "./wasmProvider.js";
|
|
2
|
+
/**
|
|
3
|
+
* Execute one generated binary protobuf request.
|
|
4
|
+
*
|
|
5
|
+
* The returned bytes are always a generated `CryptoOperationResponse` with a
|
|
6
|
+
* typed `result` or typed `error` outcome.
|
|
7
|
+
*/
|
|
8
|
+
export declare const processOperationResponse: (requestBytes: Uint8Array) => Uint8Array;
|
|
9
|
+
export declare const processOperationResponseWithProvider: (provider: ReallyMeWasmProvider, requestBytes: Uint8Array) => Uint8Array;
|
|
10
|
+
/**
|
|
11
|
+
* Execute one permitted non-secret generated ProtoJSON request and return the
|
|
12
|
+
* same binary `CryptoOperationResponse` used by `processOperationResponse`.
|
|
13
|
+
* Secret-bearing selectors fail before JSON value deserialization.
|
|
14
|
+
*/
|
|
15
|
+
export declare const processOperationResponseJson: (requestJson: Uint8Array) => Uint8Array;
|
|
16
|
+
export declare const processOperationResponseJsonWithProvider: (provider: ReallyMeWasmProvider, requestJson: Uint8Array) => Uint8Array;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import { ReallyMeCryptoError } from "./errors.js";
|
|
5
|
+
import { ensureByteArray, ensureIndependentByteArray, } from "./validateBytes.js";
|
|
6
|
+
import { requireReallyMeWasmProvider } from "./wasmProvider.js";
|
|
7
|
+
const MAX_CRYPTO_OPERATION_RESPONSE_BYTES = 1_048_608;
|
|
8
|
+
const readOperationResponse = (value, request) => {
|
|
9
|
+
if (!(value instanceof Uint8Array)) {
|
|
10
|
+
throw new ReallyMeCryptoError("provider-failure");
|
|
11
|
+
}
|
|
12
|
+
ensureIndependentByteArray(value, [request]);
|
|
13
|
+
if (value.length === 0 ||
|
|
14
|
+
value.length > MAX_CRYPTO_OPERATION_RESPONSE_BYTES) {
|
|
15
|
+
value.fill(0);
|
|
16
|
+
throw new ReallyMeCryptoError("provider-failure");
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Execute one generated binary protobuf request.
|
|
22
|
+
*
|
|
23
|
+
* The returned bytes are always a generated `CryptoOperationResponse` with a
|
|
24
|
+
* typed `result` or typed `error` outcome.
|
|
25
|
+
*/
|
|
26
|
+
export const processOperationResponse = (requestBytes) => {
|
|
27
|
+
ensureByteArray(requestBytes);
|
|
28
|
+
return processOperationResponseWithProvider(requireReallyMeWasmProvider(), requestBytes);
|
|
29
|
+
};
|
|
30
|
+
export const processOperationResponseWithProvider = (provider, requestBytes) => {
|
|
31
|
+
ensureByteArray(requestBytes);
|
|
32
|
+
return readOperationResponse(provider.processOperationResponse(requestBytes), requestBytes);
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Execute one permitted non-secret generated ProtoJSON request and return the
|
|
36
|
+
* same binary `CryptoOperationResponse` used by `processOperationResponse`.
|
|
37
|
+
* Secret-bearing selectors fail before JSON value deserialization.
|
|
38
|
+
*/
|
|
39
|
+
export const processOperationResponseJson = (requestJson) => {
|
|
40
|
+
ensureByteArray(requestJson);
|
|
41
|
+
return processOperationResponseJsonWithProvider(requireReallyMeWasmProvider(), requestJson);
|
|
42
|
+
};
|
|
43
|
+
export const processOperationResponseJsonWithProvider = (provider, requestJson) => {
|
|
44
|
+
ensureByteArray(requestJson);
|
|
45
|
+
return readOperationResponse(provider.processOperationResponseJson(requestJson), requestJson);
|
|
46
|
+
};
|
package/dist/p256Ecdh.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import { p256 } from "@noble/curves/nist.js";
|
|
5
5
|
import { ReallyMeCryptoError } from "./errors.js";
|
|
6
|
+
import { bestEffortClear } from "./memory.js";
|
|
6
7
|
/**
|
|
7
8
|
* P-256 ECDH backed by @noble/curves.
|
|
8
9
|
*
|
|
@@ -44,7 +45,10 @@ export const ReallyMeP256Ecdh = {
|
|
|
44
45
|
throw new ReallyMeCryptoError("invalid-input");
|
|
45
46
|
}
|
|
46
47
|
try {
|
|
47
|
-
|
|
48
|
+
const uncompressed = p256.getSharedSecret(secretKey, publicKey, false);
|
|
49
|
+
const sharedSecret = uncompressed.slice(1, 33);
|
|
50
|
+
bestEffortClear(uncompressed);
|
|
51
|
+
return sharedSecret;
|
|
48
52
|
}
|
|
49
53
|
catch {
|
|
50
54
|
throw new ReallyMeCryptoError("invalid-input");
|
package/dist/p384Ecdh.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import { p384 } from "@noble/curves/nist.js";
|
|
5
5
|
import { ReallyMeCryptoError } from "./errors.js";
|
|
6
|
+
import { bestEffortClear } from "./memory.js";
|
|
6
7
|
/**
|
|
7
8
|
* P-384 ECDH backed by @noble/curves.
|
|
8
9
|
*
|
|
@@ -44,7 +45,10 @@ export const ReallyMeP384Ecdh = {
|
|
|
44
45
|
throw new ReallyMeCryptoError("invalid-input");
|
|
45
46
|
}
|
|
46
47
|
try {
|
|
47
|
-
|
|
48
|
+
const uncompressed = p384.getSharedSecret(secretKey, publicKey, false);
|
|
49
|
+
const sharedSecret = uncompressed.slice(1, 49);
|
|
50
|
+
bestEffortClear(uncompressed);
|
|
51
|
+
return sharedSecret;
|
|
48
52
|
}
|
|
49
53
|
catch {
|
|
50
54
|
throw new ReallyMeCryptoError("invalid-input");
|
package/dist/p521Ecdh.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
import { p521 } from "@noble/curves/nist.js";
|
|
5
5
|
import { ReallyMeCryptoError } from "./errors.js";
|
|
6
|
+
import { bestEffortClear } from "./memory.js";
|
|
6
7
|
/**
|
|
7
8
|
* P-521 ECDH backed by @noble/curves.
|
|
8
9
|
*
|
|
@@ -44,7 +45,10 @@ export const ReallyMeP521Ecdh = {
|
|
|
44
45
|
throw new ReallyMeCryptoError("invalid-input");
|
|
45
46
|
}
|
|
46
47
|
try {
|
|
47
|
-
|
|
48
|
+
const uncompressed = p521.getSharedSecret(secretKey, publicKey, false);
|
|
49
|
+
const sharedSecret = uncompressed.slice(1, 67);
|
|
50
|
+
bestEffortClear(uncompressed);
|
|
51
|
+
return sharedSecret;
|
|
48
52
|
}
|
|
49
53
|
catch {
|
|
50
54
|
throw new ReallyMeCryptoError("invalid-input");
|
package/dist/pbkdf2.d.ts
CHANGED
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
export declare const PBKDF2_MIN_INPUT_LENGTH = 1;
|
|
2
2
|
export declare const PBKDF2_MAX_INPUT_LENGTH = 4096;
|
|
3
|
-
export declare const PBKDF2_MIN_ITERATIONS =
|
|
3
|
+
export declare const PBKDF2_MIN_ITERATIONS = 100000;
|
|
4
|
+
export declare const PBKDF2_MAX_ITERATIONS = 10000000;
|
|
4
5
|
export declare const PBKDF2_MIN_OUTPUT_LENGTH = 1;
|
|
5
6
|
export declare const PBKDF2_MAX_OUTPUT_LENGTH = 4096;
|
|
6
7
|
/**
|
|
7
8
|
* OWASP Password Storage Cheat Sheet minimum iteration counts for deriving a
|
|
8
9
|
* *new* password key.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* pass at least the value for their PRF.
|
|
10
|
+
* These stronger profile recommendations remain above the enforced public
|
|
11
|
+
* baseline and should be selected when protocol latency budgets permit.
|
|
12
12
|
*/
|
|
13
13
|
export declare const PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA256 = 600000;
|
|
14
14
|
export declare const PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA512 = 220000;
|
|
15
15
|
export declare const ReallyMePbkdf2: {
|
|
16
16
|
/**
|
|
17
17
|
* PBKDF2-HMAC-SHA-256. For a new password key pass at least
|
|
18
|
-
* {@link PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA256} iterations
|
|
19
|
-
* are accepted only to verify hashes created elsewhere.
|
|
18
|
+
* {@link PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA256} iterations.
|
|
20
19
|
*/
|
|
21
20
|
readonly deriveHmacSha256: (password: Uint8Array, salt: Uint8Array, iterations: number, outputLength: number) => Uint8Array;
|
|
22
21
|
/**
|
|
23
22
|
* PBKDF2-HMAC-SHA-512. For a new password key pass at least
|
|
24
|
-
* {@link PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA512} iterations
|
|
25
|
-
* are accepted only to verify hashes created elsewhere.
|
|
23
|
+
* {@link PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA512} iterations.
|
|
26
24
|
*/
|
|
27
25
|
readonly deriveHmacSha512: (password: Uint8Array, salt: Uint8Array, iterations: number, outputLength: number) => Uint8Array;
|
|
28
26
|
};
|
package/dist/pbkdf2.js
CHANGED
|
@@ -6,27 +6,27 @@ import { sha256, sha512 } from "@noble/hashes/sha2.js";
|
|
|
6
6
|
import { ReallyMeCryptoError } from "./errors.js";
|
|
7
7
|
export const PBKDF2_MIN_INPUT_LENGTH = 1;
|
|
8
8
|
export const PBKDF2_MAX_INPUT_LENGTH = 4096;
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
// the
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
// Public derivation routes enforce a modern baseline. Historical hashes with a
|
|
10
|
+
// lower work factor require an explicit migration tool, not a silent downgrade
|
|
11
|
+
// in the v0.3 API.
|
|
12
|
+
export const PBKDF2_MIN_ITERATIONS = 100_000;
|
|
13
|
+
// Bound hostile work-factor inputs before the provider begins CPU-expensive
|
|
14
|
+
// derivation. This matches the Rust, Swift, and Kotlin public lanes.
|
|
15
|
+
export const PBKDF2_MAX_ITERATIONS = 10_000_000;
|
|
14
16
|
export const PBKDF2_MIN_OUTPUT_LENGTH = 1;
|
|
15
17
|
export const PBKDF2_MAX_OUTPUT_LENGTH = 4096;
|
|
16
18
|
/**
|
|
17
19
|
* OWASP Password Storage Cheat Sheet minimum iteration counts for deriving a
|
|
18
20
|
* *new* password key.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* pass at least the value for their PRF.
|
|
21
|
+
* These stronger profile recommendations remain above the enforced public
|
|
22
|
+
* baseline and should be selected when protocol latency budgets permit.
|
|
22
23
|
*/
|
|
23
24
|
export const PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA256 = 600_000;
|
|
24
25
|
export const PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA512 = 220_000;
|
|
25
26
|
export const ReallyMePbkdf2 = {
|
|
26
27
|
/**
|
|
27
28
|
* PBKDF2-HMAC-SHA-256. For a new password key pass at least
|
|
28
|
-
* {@link PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA256} iterations
|
|
29
|
-
* are accepted only to verify hashes created elsewhere.
|
|
29
|
+
* {@link PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA256} iterations.
|
|
30
30
|
*/
|
|
31
31
|
deriveHmacSha256(password, salt, iterations, outputLength) {
|
|
32
32
|
validate(password, salt, iterations, outputLength);
|
|
@@ -34,8 +34,7 @@ export const ReallyMePbkdf2 = {
|
|
|
34
34
|
},
|
|
35
35
|
/**
|
|
36
36
|
* PBKDF2-HMAC-SHA-512. For a new password key pass at least
|
|
37
|
-
* {@link PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA512} iterations
|
|
38
|
-
* are accepted only to verify hashes created elsewhere.
|
|
37
|
+
* {@link PBKDF2_RECOMMENDED_MIN_ITERATIONS_SHA512} iterations.
|
|
39
38
|
*/
|
|
40
39
|
deriveHmacSha512(password, salt, iterations, outputLength) {
|
|
41
40
|
validate(password, salt, iterations, outputLength);
|
|
@@ -49,6 +48,7 @@ function validate(password, salt, iterations, outputLength) {
|
|
|
49
48
|
salt.length > PBKDF2_MAX_INPUT_LENGTH ||
|
|
50
49
|
!Number.isInteger(iterations) ||
|
|
51
50
|
iterations < PBKDF2_MIN_ITERATIONS ||
|
|
51
|
+
iterations > PBKDF2_MAX_ITERATIONS ||
|
|
52
52
|
!Number.isInteger(outputLength) ||
|
|
53
53
|
outputLength < PBKDF2_MIN_OUTPUT_LENGTH ||
|
|
54
54
|
outputLength > PBKDF2_MAX_OUTPUT_LENGTH) {
|