Support crypto.createDiffieHellman and getDiffieHellman

crypto.createDiffieHellman, crypto.getDiffieHellman and
crypto.createDiffieHellmanGroup return native DiffieHellman and
DiffieHellmanGroup handles backed by mbedTLS bignums. generateKeys,
computeSecret, getPrime, getGenerator, getPublicKey, getPrivateKey,
setPublicKey, setPrivateKey and verifyError follow Node 24.22:

- the modp1, modp2, modp5 and modp14 through modp18 groups, with the
  private key widths of Node's OpenSSL 3 path (200 to 400 bits for
  modp5 and up, [2, p - 2] for modp1 and modp2);
- explicit primes and generators in every argument form and encoding,
  with keys of bits(p) - 2 bits, or below min(2^N, q) when the
  parameters equal an OpenSSL named group (RFC 3526, RFC 7919,
  RFC 5114);
- generated safe primes with OpenSSL's congruences for the generator;
- verifyError's DH_check bits, computed when it is first read;
- Node's argument, generator, modulus, key range, state and encoding
  errors, including the OpenSSL errors' library and reason properties.

Safe-prime generation sieves candidates with the odd primes below a
bound that grows with the prime's length and tests them with
Miller-Rabin rounds over a variable-time Montgomery exponentiation that
only reads public values; key and secret exponentiations stay on
mbedTLS's constant-time path. Primes longer than 8192 bits, property
reads other than verifyError, property writes, Object.prototype methods,
and calls whose output encoding is typed any or matches no @types/node
overload are refused.

The runtime unit scr_dh.c links, with the mbedTLS archive, only into
programs that use DiffieHellman. wasm32-wasi builds refuse it. The ECDH
unit's argument and encoding helpers move to scr_crypto_args.h, which
both units include.
This commit is contained in:
Chris Tate
2026-10-21 21:55:47 -05:00
parent 0e600da0a7
commit 283a504fe0
73 changed files with 3602 additions and 309 deletions
@@ -15,5 +15,11 @@
`createECDH` and `ECDH.convertKey` support prime192v1, secp224r1, prime256v1, secp384r1, secp521r1, secp192k1, secp224k1, secp256k1, brainpoolP256r1, brainpoolP384r1, and brainpoolP512r1, on native targets, through `generateKeys()`, `computeSecret()`, `getPublicKey()`, `getPrivateKey()`, `setPrivateKey()`, and `setPublicKey()`, in compressed, uncompressed, and hybrid forms; the other curves `crypto.getCurves()` lists and wasm32-wasi builds are refused.
A call on an ECDH value whose arguments no @types/node overload accepts (`getPublicKey("HEX")`) is refused at compile time, as is `computeSecret(view, encoding)`: Node reads that encoding as the input encoding and answers a Buffer where @types/node declares a string.
ECDH property reads and writes throw a coded SC2020 error.
`createDiffieHellman`, `getDiffieHellman`, and `createDiffieHellmanGroup` support the modp1, modp2, modp5, and modp14 through modp18 groups, explicit primes and generators, and generated safe primes, on native targets, through `generateKeys()`, `computeSecret()`, `getPrime()`, `getGenerator()`, `getPublicKey()`, `getPrivateKey()`, `setPublicKey()`, `setPrivateKey()`, and `verifyError`, with Node's private key lengths, DH_check results, and errors; wasm32-wasi builds are refused.
Primes longer than 8192 bits throw a coded SC2020 error; Node accepts primes up to 10000 bits for key generation and secrets.
A call on a DiffieHellman value whose arguments no @types/node overload accepts, or whose output encoding is typed `any`, is refused at compile time, as are its `Object.prototype` methods; other property reads, and property writes, throw a coded SC2020 error.
`Object.keys()` and `in` do not see a DiffieHellman's own `verifyError` property, and `JSON.stringify()` and `instanceof` are refused.
After `createDiffieHellman(primeLength)` throws `Invalid DH parameters`, the next OpenSSL error Node throws can list the failed generation's errors in `opensslErrorStack`; errors in a compiled binary list only their own.
`crypto.diffieHellman`, which takes asymmetric KeyObjects, and the `DiffieHellman` and `DiffieHellmanGroup` constructors are not available.
Other public-key operations remain unsupported.
Native derivations finish before their deferred callbacks, so computation blocks the caller.
+55 -55
View File
@@ -11177,9 +11177,9 @@
"inherited": true
},
"static": {
"status": "refused",
"detail": "Explicitly rejected by a named compiler diagnostic.",
"verification": "explicit-refusal"
"status": "partial",
"detail": "Supports the modp groups, explicit primes and generators, and generated safe primes up to 8192 bits with Node's argument, generator and modulus errors.",
"verification": "test-backed"
}
},
{
@@ -11200,9 +11200,9 @@
"inherited": true
},
"static": {
"status": "refused",
"detail": "Explicitly rejected by a named compiler diagnostic.",
"verification": "explicit-refusal"
"status": "partial",
"detail": "Supports the modp groups, explicit primes and generators, and generated safe primes up to 8192 bits with Node's argument, generator and modulus errors.",
"verification": "test-backed"
}
},
{
@@ -11223,9 +11223,9 @@
"inherited": true
},
"static": {
"status": "refused",
"detail": "Explicitly rejected by a named compiler diagnostic.",
"verification": "explicit-refusal"
"status": "partial",
"detail": "Supports the modp groups, explicit primes and generators, and generated safe primes up to 8192 bits with Node's argument, generator and modulus errors.",
"verification": "test-backed"
}
},
{
@@ -11247,7 +11247,7 @@
},
"static": {
"status": "partial",
"detail": "Implemented for the call shapes accepted by the compiler lowering.",
"detail": "Supports prime192v1, secp224r1, prime256v1, secp384r1, secp521r1, secp192k1, secp224k1, secp256k1, brainpoolP256r1, brainpoolP384r1 and brainpoolP512r1 with Node's curve, key, point, format and encoding errors; other curves Node knows are refused.",
"verification": "test-backed"
}
},
@@ -11729,9 +11729,9 @@
"inherited": true
},
"static": {
"status": "refused",
"detail": "Explicitly rejected by a named compiler diagnostic.",
"verification": "explicit-refusal"
"status": "partial",
"detail": "Supports the modp groups, explicit primes and generators, and generated safe primes up to 8192 bits with Node's argument, generator and modulus errors.",
"verification": "test-backed"
}
},
{
@@ -12856,9 +12856,9 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Matches Node's private key lengths, DH_check results, public key range checks, secret padding and errors; primes longer than 8192 bits, property writes and property reads other than verifyError are refused.",
"verification": "test-backed"
}
},
{
@@ -12879,9 +12879,9 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Matches Node's private key lengths, DH_check results, public key range checks, secret padding and errors; primes longer than 8192 bits, property writes and property reads other than verifyError are refused.",
"verification": "test-backed"
}
},
{
@@ -12902,9 +12902,9 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Matches Node's private key lengths, DH_check results, public key range checks, secret padding and errors; primes longer than 8192 bits, property writes and property reads other than verifyError are refused.",
"verification": "test-backed"
}
},
{
@@ -12925,9 +12925,9 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Matches Node's private key lengths, DH_check results, public key range checks, secret padding and errors; primes longer than 8192 bits, property writes and property reads other than verifyError are refused.",
"verification": "test-backed"
}
},
{
@@ -12948,9 +12948,9 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Matches Node's private key lengths, DH_check results, public key range checks, secret padding and errors; primes longer than 8192 bits, property writes and property reads other than verifyError are refused.",
"verification": "test-backed"
}
},
{
@@ -12971,9 +12971,9 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Matches Node's private key lengths, DH_check results, public key range checks, secret padding and errors; primes longer than 8192 bits, property writes and property reads other than verifyError are refused.",
"verification": "test-backed"
}
},
{
@@ -12994,9 +12994,9 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Matches Node's private key lengths, DH_check results, public key range checks, secret padding and errors; primes longer than 8192 bits, property writes and property reads other than verifyError are refused.",
"verification": "test-backed"
}
},
{
@@ -13017,9 +13017,9 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Matches Node's private key lengths, DH_check results, public key range checks, secret padding and errors; primes longer than 8192 bits, property writes and property reads other than verifyError are refused.",
"verification": "test-backed"
}
},
{
@@ -13040,9 +13040,9 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Matches Node's private key lengths, DH_check results, public key range checks, secret padding and errors; primes longer than 8192 bits, property writes and property reads other than verifyError are refused.",
"verification": "test-backed"
}
},
{
@@ -13063,9 +13063,9 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Matches Node's private key lengths, DH_check results, public key range checks, secret padding and errors; primes longer than 8192 bits, property writes and property reads other than verifyError are refused.",
"verification": "test-backed"
}
},
{
@@ -13086,9 +13086,9 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Matches Node's private key lengths, DH_check results, public key range checks, secret padding and errors; primes longer than 8192 bits, property writes and property reads other than verifyError are refused.",
"verification": "test-backed"
}
},
{
@@ -18880,9 +18880,9 @@
"anchor": "err_crypto_invalid_keylen",
"nodeStability": null,
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Implemented by a dedicated static compiler/runtime path.",
"verification": "test-backed"
}
},
{
@@ -19006,9 +19006,9 @@
"anchor": "err_crypto_invalid_state",
"nodeStability": null,
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Implemented by a dedicated static compiler/runtime path.",
"verification": "test-backed"
}
},
{
@@ -19276,9 +19276,9 @@
"anchor": "err_crypto_unknown_dh_group",
"nodeStability": null,
"static": {
"status": "not-implemented",
"detail": "No static compiler lowering is registered for this API yet.",
"verification": "registry-gap"
"status": "partial",
"detail": "Implemented by a dedicated static compiler/runtime path.",
"verification": "test-backed"
}
},
{
@@ -19313,11 +19313,18 @@
"tests/corpus/6703-ecdh-private-keys.ts",
"tests/corpus/6704-ecdh-set-public-key.cjs",
"tests/corpus/6705-ecdh-handles.ts",
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/corpus/node24-crypto-kdf-errors.ts",
"tests/corpus/node24-crypto-kdf-options.ts",
"tests/corpus/node24-crypto-kdf.ts",
"tests/corpus/node24-crypto-sha2.ts",
"tests/fixtures/node-types/cipher.ts",
"tests/fixtures/node-types/dh.ts",
"tests/fixtures/node-types/ecdh.ts",
"tests/harness/npm-static.test.ts"
]
@@ -19759,8 +19766,17 @@
"inherited": true
},
"static": {
"status": "refused",
"evidence": "surface-manifest:unsupported:node-builtin.crypto.createDiffieHellman"
"status": "partial",
"evidence": "surface-manifest:node-builtin.crypto.createDiffieHellman",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -19782,8 +19798,17 @@
"inherited": true
},
"static": {
"status": "refused",
"evidence": "surface-manifest:unsupported:node-builtin.crypto.createDiffieHellman"
"status": "partial",
"evidence": "surface-manifest:node-builtin.crypto.createDiffieHellman",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -19805,8 +19830,17 @@
"inherited": true
},
"static": {
"status": "refused",
"evidence": "surface-manifest:unsupported:node-builtin.crypto.createDiffieHellmanGroup"
"status": "partial",
"evidence": "surface-manifest:node-builtin.crypto.createDiffieHellmanGroup",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -20387,8 +20421,17 @@
"inherited": true
},
"static": {
"status": "refused",
"evidence": "surface-manifest:unsupported:node-builtin.crypto.getDiffieHellman"
"status": "partial",
"evidence": "surface-manifest:node-builtin.crypto.getDiffieHellman",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -22153,8 +22196,17 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"evidence": "compiler-unmatched:crypto"
"status": "partial",
"evidence": "compiler-dedicated:DiffieHellman",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -22176,8 +22228,17 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"evidence": "compiler-unmatched:crypto"
"status": "partial",
"evidence": "compiler-dedicated:diffieHellman.computeSecret",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -22199,8 +22260,17 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"evidence": "compiler-unmatched:crypto"
"status": "partial",
"evidence": "compiler-dedicated:diffieHellman.generateKeys",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -22222,8 +22292,17 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"evidence": "compiler-unmatched:crypto"
"status": "partial",
"evidence": "compiler-dedicated:diffieHellman.getGenerator",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -22245,8 +22324,17 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"evidence": "compiler-unmatched:crypto"
"status": "partial",
"evidence": "compiler-dedicated:diffieHellman.getPrime",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -22268,8 +22356,17 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"evidence": "compiler-unmatched:crypto"
"status": "partial",
"evidence": "compiler-dedicated:diffieHellman.getPrivateKey",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -22291,8 +22388,17 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"evidence": "compiler-unmatched:crypto"
"status": "partial",
"evidence": "compiler-dedicated:diffieHellman.getPublicKey",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -22314,8 +22420,17 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"evidence": "compiler-unmatched:crypto"
"status": "partial",
"evidence": "compiler-dedicated:diffieHellman.setPrivateKey",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -22337,8 +22452,17 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"evidence": "compiler-unmatched:crypto"
"status": "partial",
"evidence": "compiler-dedicated:diffieHellman.setPublicKey",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -22360,8 +22484,17 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"evidence": "compiler-unmatched:crypto"
"status": "partial",
"evidence": "compiler-dedicated:diffieHellman.verifyError",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -22383,8 +22516,17 @@
"inherited": true
},
"static": {
"status": "not-implemented",
"evidence": "compiler-unmatched:crypto"
"status": "partial",
"evidence": "compiler-dedicated:DiffieHellmanGroup",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -27448,8 +27590,17 @@
"anchor": "dep0167-weak-diffiehellmangroup-instances-modp1-modp2-modp5",
"nodeStability": null,
"static": {
"status": "not-applicable",
"evidence": "compiler-chapter-policy:deprecations"
"status": "partial",
"evidence": "compiler-dedicated:DiffieHellmanGroup",
"tests": [
"tests/corpus/6706-dh-groups.ts",
"tests/corpus/6707-dh-explicit-params.ts",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/6709-dh-generate.ts",
"tests/corpus/6710-dh-encodings.cjs",
"tests/corpus/6711-dh-handles.ts",
"tests/fixtures/node-types/dh.ts"
]
},
"anchorSource": "exact"
},
@@ -32191,6 +32342,7 @@
"evidence": "derived:descendants",
"tests": [
"tests/corpus/6702-ecdh-errors.js",
"tests/corpus/6708-dh-errors.js",
"tests/corpus/caught-system-error-fields.ts",
"tests/corpus/error-stack-frames.ts",
"tests/corpus/error-stack-limit.ts",
@@ -33601,8 +33753,11 @@
"anchor": "err_crypto_invalid_keylen",
"nodeStability": null,
"static": {
"status": "not-implemented",
"evidence": "compiler-unmatched:errors"
"status": "partial",
"evidence": "compiler-dedicated:ERR_CRYPTO_INVALID_KEYLEN",
"tests": [
"tests/corpus/6708-dh-errors.js"
]
},
"anchorSource": "exact"
},
@@ -33727,8 +33882,11 @@
"anchor": "err_crypto_invalid_state",
"nodeStability": null,
"static": {
"status": "not-implemented",
"evidence": "compiler-unmatched:errors"
"status": "partial",
"evidence": "compiler-dedicated:ERR_CRYPTO_INVALID_STATE",
"tests": [
"tests/corpus/6708-dh-errors.js"
]
},
"anchorSource": "exact"
},
@@ -33997,8 +34155,11 @@
"anchor": "err_crypto_unknown_dh_group",
"nodeStability": null,
"static": {
"status": "not-implemented",
"evidence": "compiler-unmatched:errors"
"status": "partial",
"evidence": "compiler-dedicated:ERR_CRYPTO_UNKNOWN_DH_GROUP",
"tests": [
"tests/corpus/6708-dh-errors.js"
]
},
"anchorSource": "exact"
},
+13 -3
View File
@@ -582,17 +582,27 @@ function publicDetail(tier) {
if (/^surface-manifest:node-builtin\.crypto\.create(?:Cipheriv|Decipheriv)$/.test(source)) {
return "Supports aes-128/192/256 in cbc, ctr, and gcm modes and chacha20-poly1305 with Node's argument, IV, tag-length, and key-length errors; other OpenSSL ciphers and KeyObject keys are refused.";
}
if (/^surface-manifest:node-builtin\.crypto\.createECDH$/.test(source)) {
return "Supports prime192v1, secp224r1, prime256v1, secp384r1, secp521r1, secp192k1, secp224k1, secp256k1, brainpoolP256r1, brainpoolP384r1 and brainpoolP512r1 with Node's curve, key, point, format and encoding errors; other curves Node knows are refused.";
}
if (
/^surface-manifest:node-builtin\.crypto\.(?:createDiffieHellman|createDiffieHellmanGroup|getDiffieHellman)$/.test(
source,
)
) {
return "Supports the modp groups, explicit primes and generators, and generated safe primes up to 8192 bits with Node's argument, generator and modulus errors.";
}
if (source.startsWith("surface-manifest:"))
return "Implemented for the call shapes accepted by the compiler lowering.";
if (/^compiler-dedicated:assert\.doesNot(?:Throw|Reject)$/.test(source)) {
return "Supports callbacks or native promises with messages, Error classes, regular expressions, and validators accepting unknown values; object expectations and complete AssertionError metadata remain unsupported.";
}
if (/^surface-manifest:node-builtin\.crypto\.createECDH$/.test(source)) {
return "Supports prime192v1, secp224r1, prime256v1, secp384r1, secp521r1, secp192k1, secp224k1, secp256k1, brainpoolP256r1, brainpoolP384r1 and brainpoolP512r1 with Node's curve, key, point, format and encoding errors; other curves Node knows are refused.";
}
if (/^compiler-dedicated:(?:ECDH|ecdh\.)/.test(source)) {
return "Matches Node's key formats, point encodings, private-key range checks, key-pair checks and errors on the supported curves; ECDH.convertKey is supported, and property reads and writes are refused.";
}
if (/^compiler-dedicated:(?:DiffieHellman|diffieHellman\.)/.test(source)) {
return "Matches Node's private key lengths, DH_check results, public key range checks, secret padding and errors; primes longer than 8192 bits, property writes and property reads other than verifyError are refused.";
}
if (/^compiler-dedicated:(?:Cipheriv|Decipheriv|cipher\.|decipher\.)/.test(source)) {
return "Matches Node's update() output lengths, padding, authentication tags, string encodings, and state errors for the supported ciphers; the stream.Transform interface is refused.";
}
@@ -44,6 +44,8 @@
"node-builtin.console": ["tests/corpus/console-imports.cjs", "tests/corpus/2440-console-inspect-args.ts", "tests/corpus/console-native-value.js", "tests/harness/npm-static.test.ts"],
"node-builtin.crypto.createCipheriv": ["tests/corpus/5250-cipher-aes-gcm.ts", "tests/corpus/5251-cipher-aes-cbc.ts", "tests/corpus/5252-cipher-aes-ctr.ts", "tests/corpus/5253-cipher-chacha20-poly1305.ts", "tests/corpus/5254-cipher-errors.js", "tests/corpus/5255-cipher-encodings.cjs", "tests/corpus/5256-cipher-deprecation.cjs", "tests/corpus/5257-cipher-vectors.ts", "tests/corpus/5258-cipher-handles.js", "tests/corpus/5259-cipher-chunked.ts", "tests/fixtures/node-types/cipher.ts"],
"node-builtin.crypto.createDecipheriv": ["tests/corpus/5250-cipher-aes-gcm.ts", "tests/corpus/5251-cipher-aes-cbc.ts", "tests/corpus/5252-cipher-aes-ctr.ts", "tests/corpus/5253-cipher-chacha20-poly1305.ts", "tests/corpus/5254-cipher-errors.js", "tests/corpus/5255-cipher-encodings.cjs", "tests/corpus/5256-cipher-deprecation.cjs", "tests/corpus/5257-cipher-vectors.ts", "tests/corpus/5258-cipher-handles.js", "tests/corpus/5259-cipher-chunked.ts", "tests/fixtures/node-types/cipher.ts"],
"node-builtin.crypto.createDiffieHellman": ["tests/corpus/6706-dh-groups.ts", "tests/corpus/6707-dh-explicit-params.ts", "tests/corpus/6708-dh-errors.js", "tests/corpus/6709-dh-generate.ts", "tests/corpus/6710-dh-encodings.cjs", "tests/corpus/6711-dh-handles.ts", "tests/fixtures/node-types/dh.ts"],
"node-builtin.crypto.createDiffieHellmanGroup": ["tests/corpus/6706-dh-groups.ts", "tests/corpus/6707-dh-explicit-params.ts", "tests/corpus/6708-dh-errors.js", "tests/corpus/6709-dh-generate.ts", "tests/corpus/6710-dh-encodings.cjs", "tests/corpus/6711-dh-handles.ts", "tests/fixtures/node-types/dh.ts"],
"node-builtin.crypto.createECDH": ["tests/corpus/6700-ecdh-shared-secret.ts", "tests/corpus/6701-ecdh-formats.ts", "tests/corpus/6702-ecdh-errors.js", "tests/corpus/6703-ecdh-private-keys.ts", "tests/corpus/6704-ecdh-set-public-key.cjs", "tests/corpus/6705-ecdh-handles.ts", "tests/fixtures/node-types/ecdh.ts"],
"node-builtin.crypto": ["tests/corpus/1358-crypto-random.ts", "tests/corpus/1534-crypto-hash-chain.ts", "tests/corpus/2556-crypto-introspection.ts", "tests/corpus/2890-crypto-static-utility.ts", "tests/harness/npm-static.test.ts", "tests/corpus/node24-crypto-sha2.ts", "tests/corpus/node24-crypto-kdf.ts", "tests/corpus/node24-crypto-kdf-errors.ts", "tests/corpus/node24-crypto-kdf-options.ts"],
"node-builtin.dgram": ["tests/corpus/2597-dgram-send-ladders.cjs"],
@@ -118,6 +120,7 @@
"node-builtin.os.version": ["tests/corpus/5140-os-host-facts.ts"],
"node-builtin.os.constants": ["tests/corpus/5141-os-constants.ts"],
"node-builtin.fs.constants": ["tests/corpus/6207-fs-constants-object.ts", "tests/corpus/6208-fs-constants-require.cjs"],
"node-builtin.crypto.getDiffieHellman": ["tests/corpus/6706-dh-groups.ts", "tests/corpus/6707-dh-explicit-params.ts", "tests/corpus/6708-dh-errors.js", "tests/corpus/6709-dh-generate.ts", "tests/corpus/6710-dh-encodings.cjs", "tests/corpus/6711-dh-handles.ts", "tests/fixtures/node-types/dh.ts"],
"node-builtin.crypto.getRandomValues": ["tests/corpus/6204-crypto-get-random-values.ts", "tests/corpus/6205-crypto-get-random-values.js"],
"node-builtin.url.parse": ["tests/corpus/5220-url-parse-warnings.ts", "tests/corpus/5221-url-parse-shapes.ts", "tests/corpus/5222-url-parse-hosts.ts", "tests/corpus/5223-url-parse-query.ts", "tests/corpus/5227-url-legacy-dependency/main.ts", "tests/corpus/5229-url-legacy-errors.cjs", "packages/runtime/test/url-legacy.test.ts", "tests/fixtures/node-types/url-legacy.ts"],
"node-builtin.url.format": ["tests/corpus/5224-url-format-objects.ts", "tests/corpus/5225-url-format-whatwg.ts", "tests/corpus/5227-url-legacy-dependency/main.ts", "tests/corpus/5229-url-legacy-errors.cjs", "packages/runtime/test/url-legacy.test.ts", "tests/fixtures/node-types/url-legacy.ts"],
@@ -414,6 +417,8 @@
{ "symbols": ["assert", "assert.ok", "assert.equal", "assert.notEqual", "assert.strictEqual", "assert.notStrictEqual", "assert.deepStrictEqual", "assert.notDeepStrictEqual", "assert.fail", "assert.match", "assert.doesNotMatch", "assert.throws", "assert.rejects", "assert.ifError"], "status": "partial", "evidence": ["tests/corpus/1600-assert-passing.ts", "tests/corpus/1604-assert-deep-structures.ts", "tests/corpus/1609-assert-async.ts", "tests/corpus/1721-assert-throws-regex-class.ts", "tests/corpus/2936-static-loose-equality.ts", "tests/corpus/5515-assert-deep-strict-typed-messages.ts"] },
{ "chapter": "crypto", "symbols": ["Cipheriv", "cipher.update", "cipher.final", "cipher.setAAD", "cipher.getAuthTag", "cipher.setAutoPadding", "Decipheriv", "decipher.update", "decipher.final", "decipher.setAAD", "decipher.setAuthTag", "decipher.setAutoPadding"], "status": "partial", "evidence": ["tests/corpus/5250-cipher-aes-gcm.ts", "tests/corpus/5251-cipher-aes-cbc.ts", "tests/corpus/5252-cipher-aes-ctr.ts", "tests/corpus/5253-cipher-chacha20-poly1305.ts", "tests/corpus/5254-cipher-errors.js", "tests/corpus/5255-cipher-encodings.cjs", "tests/corpus/5256-cipher-deprecation.cjs", "tests/corpus/5257-cipher-vectors.ts", "tests/corpus/5258-cipher-handles.js", "tests/corpus/5259-cipher-chunked.ts", "tests/fixtures/node-types/cipher.ts"] },
{ "chapter": "crypto", "symbols": ["ECDH", "ecdh.computeSecret", "ecdh.generateKeys", "ecdh.getPrivateKey", "ecdh.getPublicKey", "ecdh.setPrivateKey", "ecdh.setPublicKey"], "status": "partial", "evidence": ["tests/corpus/6700-ecdh-shared-secret.ts", "tests/corpus/6701-ecdh-formats.ts", "tests/corpus/6702-ecdh-errors.js", "tests/corpus/6703-ecdh-private-keys.ts", "tests/corpus/6704-ecdh-set-public-key.cjs", "tests/corpus/6705-ecdh-handles.ts", "tests/fixtures/node-types/ecdh.ts"] },
{ "chapter": "crypto", "symbols": ["DiffieHellman", "DiffieHellmanGroup", "diffieHellman.computeSecret", "diffieHellman.generateKeys", "diffieHellman.getGenerator", "diffieHellman.getPrime", "diffieHellman.getPrivateKey", "diffieHellman.getPublicKey", "diffieHellman.setPrivateKey", "diffieHellman.setPublicKey", "diffieHellman.verifyError"], "status": "partial", "evidence": ["tests/corpus/6706-dh-groups.ts", "tests/corpus/6707-dh-explicit-params.ts", "tests/corpus/6708-dh-errors.js", "tests/corpus/6709-dh-generate.ts", "tests/corpus/6710-dh-encodings.cjs", "tests/corpus/6711-dh-handles.ts", "tests/fixtures/node-types/dh.ts"] },
{ "chapter": "errors", "symbols": ["ERR_CRYPTO_UNKNOWN_DH_GROUP", "ERR_CRYPTO_INVALID_KEYLEN", "ERR_CRYPTO_INVALID_STATE"], "status": "partial", "evidence": ["tests/corpus/6708-dh-errors.js"] },
{ "chapter": "errors", "symbols": ["ERR_CRYPTO_ECDH_INVALID_FORMAT", "ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY"], "status": "partial", "evidence": ["tests/corpus/6702-ecdh-errors.js"] },
{ "symbols": ["crypto.createHash", "Hash", "hash.update", "hash.digest", "hash.copy", "crypto.createHmac", "Hmac", "hmac.update", "hmac.digest", "crypto.hash", "crypto.pbkdf2", "crypto.pbkdf2Sync"], "status": "partial", "evidence": ["tests/corpus/5760-crypto-hash-stream.ts", "tests/corpus/5768-crypto-hash-unknown.ts", "tests/corpus/5769-crypto-hash-unknown.cjs", "tests/corpus/5761-crypto-hash-stream-states.ts", "tests/corpus/5762-crypto-hash-stream.cjs", "tests/corpus/2890-crypto-static-utility.ts", "tests/corpus/node24-crypto-sha2.ts", "tests/corpus/5435-crypto-hash-algorithms.ts", "tests/corpus/5436-crypto-hash-names.js", "tests/corpus/5437-crypto-hmac-algorithms.ts", "tests/corpus/5438-crypto-kdf-digests.ts", "tests/corpus/5440-crypto-hash-encodings.js", "tests/corpus/5441-crypto-hash-output-length.ts", "tests/harness/npm-static.test.ts"] },
{ "symbols": ["crypto.randomFill", "crypto.randomFillSync", "crypto.randomUUID", "crypto.randomUUIDv7"], "status": "supported", "evidence": ["tests/corpus/5442-crypto-random-values.ts", "tests/corpus/5443-crypto-random-arguments.js", "tests/corpus/1358-crypto-random.ts"] },
+62
View File
@@ -2968,6 +2968,68 @@ declare module "crypto" {
setPrivateKey(privateKey: string, encoding: BinaryToTextEncoding): void;
}
export function createECDH(curveName: string): ECDH;
export class DiffieHellman {
private constructor();
generateKeys(): Buffer;
generateKeys(encoding: BinaryToTextEncoding): string;
computeSecret(
otherPublicKey: ArrayBufferView,
inputEncoding?: null,
outputEncoding?: null,
): Buffer;
computeSecret(
otherPublicKey: string,
inputEncoding: BinaryToTextEncoding,
outputEncoding?: null,
): Buffer;
computeSecret(
otherPublicKey: ArrayBufferView,
inputEncoding: null,
outputEncoding: BinaryToTextEncoding,
): string;
computeSecret(
otherPublicKey: string,
inputEncoding: BinaryToTextEncoding,
outputEncoding: BinaryToTextEncoding,
): string;
getPrime(): Buffer;
getPrime(encoding: BinaryToTextEncoding): string;
getGenerator(): Buffer;
getGenerator(encoding: BinaryToTextEncoding): string;
getPublicKey(): Buffer;
getPublicKey(encoding: BinaryToTextEncoding): string;
getPrivateKey(): Buffer;
getPrivateKey(encoding: BinaryToTextEncoding): string;
setPublicKey(publicKey: ArrayBufferView): void;
setPublicKey(publicKey: string, encoding: BufferEncoding): void;
setPrivateKey(privateKey: ArrayBufferView): void;
setPrivateKey(privateKey: string, encoding: BufferEncoding): void;
verifyError: number;
}
export type DiffieHellmanGroup = Omit<DiffieHellman, "setPublicKey" | "setPrivateKey">;
export function createDiffieHellman(primeLength: number, generator?: number): DiffieHellman;
export function createDiffieHellman(
prime: ArrayBuffer | ArrayBufferView,
generator?: number | ArrayBuffer | ArrayBufferView,
): DiffieHellman;
export function createDiffieHellman(
prime: ArrayBuffer | ArrayBufferView,
generator: string,
generatorEncoding: BinaryToTextEncoding,
): DiffieHellman;
export function createDiffieHellman(
prime: string,
primeEncoding: BinaryToTextEncoding,
generator?: number | ArrayBuffer | ArrayBufferView,
): DiffieHellman;
export function createDiffieHellman(
prime: string,
primeEncoding: BinaryToTextEncoding,
generator: string,
generatorEncoding: BinaryToTextEncoding,
): DiffieHellman;
export function getDiffieHellman(groupName: string): DiffieHellmanGroup;
export function createDiffieHellmanGroup(name: string): DiffieHellmanGroup;
export interface ScryptOptions {
N?: number;
r?: number;
@@ -56,6 +56,7 @@ export function executableLinkFeatures(mod: IrModule): NativeLinkFeatures {
tlsCa: features.tlsCa,
cipher: features.cipher,
ecdh: features.ecdh,
dh: features.dh,
webcrypto: features.webcrypto,
perfLoop: features.perfLoop,
};
@@ -60,6 +60,7 @@ export async function compilePackedLibrary(
tls: false,
cipher: false,
ecdh: false,
dh: false,
webcrypto: false,
perfLoop: false,
tlsCa: false,
@@ -577,6 +577,8 @@ export const LIB_FN_SYMS: Record<string, string> = {
"crypto.cipherNew": "scr_crypto_cipher_new",
"crypto.ecdhNew": "scr_crypto_ecdh_new",
"crypto.ecdhConvertKey": "scr_crypto_ecdh_convert_key",
"crypto.dhNew": "scr_crypto_dh_new",
"crypto.dhGroupNew": "scr_crypto_dh_group_new",
"crypto.hmacNewStr": "scr_crypto_hmac_new_str",
"crypto.hmacNewBytes": "scr_crypto_hmac_new_bytes",
"crypto.hashUpdateStr": "scr_crypto_hash_update_str",
@@ -90,6 +90,9 @@ export interface NativeLinkFeatures {
/** crypto.createECDH and ECDH.convertKey: scr_ecdh.c plus the mbedTLS
* archive. */
ecdh: boolean;
/** crypto.createDiffieHellman, getDiffieHellman and
* createDiffieHellmanGroup: scr_dh.c plus the mbedTLS archive. */
dh: boolean;
/** perf_hooks event-loop metrics: scr_perf_loop.c. */
perfLoop: boolean;
tlsCa: boolean;
@@ -249,6 +249,10 @@ export interface CcOptions {
/** crypto.createECDH and ECDH.convertKey: compiles scr_ecdh.c and links
* the mbedTLS archive (shared with tls). */
ecdh?: boolean;
/** crypto.createDiffieHellman, getDiffieHellman and
* createDiffieHellmanGroup: compiles scr_dh.c and links the mbedTLS
* archive (shared with tls). */
dh?: boolean;
/** crypto.subtle importKey/sign/verify/digest: compiles scr_webcrypto.c. */
webcrypto?: boolean;
/** perf_hooks event-loop metrics: compiles scr_perf_loop.c. */
@@ -114,6 +114,7 @@ interface RuntimeUnitContext {
tlsCa: boolean;
cipher: boolean;
ecdh: boolean;
dh: boolean;
lreObjects: readonly string[];
zlibObjects: readonly string[];
tlsArchive: string | null;
@@ -308,6 +309,7 @@ const RUNTIME_UNITS: readonly RuntimeUnit[] = [
...(u.tls ? [u.rt(join(u.rtDir, "scr_tls.c"))] : []),
...(u.cipher ? [u.rt(join(u.rtDir, "scr_cipher.c"))] : []),
...(u.ecdh ? [u.rt(join(u.rtDir, "scr_ecdh.c"))] : []),
...(u.dh ? [u.rt(join(u.rtDir, "scr_dh.c"))] : []),
u.tlsArchive,
// mbedTLS's win32 entropy poll is BCryptGenRandom (bcrypt.h).
// The unconditional win32 libs above do not carry it.
@@ -372,10 +374,12 @@ export async function compileCInternal(
const http = (opts.http ?? false) || nativeFetch;
const tls = (opts.tls ?? false) || nativeFetch;
const tlsCa = (opts.tlsCa ?? false) || tls;
// Symmetric ciphers and ECDH link the same mbedTLS archive as TLS.
// Symmetric ciphers, ECDH and DiffieHellman link the same mbedTLS
// archive as TLS.
const cipher = opts.cipher ?? false;
const ecdh = opts.ecdh ?? false;
const mbedtls = tls || cipher || ecdh;
const dh = opts.dh ?? false;
const mbedtls = tls || cipher || ecdh || dh;
const driver = resolveCc();
const darwinDebugSymbols = needsDarwinDebugSymbols(
targetPlatform(driver),
@@ -733,6 +737,7 @@ export async function compileCInternal(
tlsCa,
cipher,
ecdh,
dh,
lreObjects,
zlibObjects,
tlsArchive,
@@ -125,6 +125,7 @@ const features = {
tlsCa: false,
cipher: false,
ecdh: false,
dh: false,
webcrypto: false,
perfLoop: false,
};
@@ -61,6 +61,7 @@ const BASE: NativeLinkFeatures = {
tlsCa: false,
cipher: false,
ecdh: false,
dh: false,
webcrypto: false,
perfLoop: false,
};
@@ -215,6 +215,13 @@ export function moduleWasiUnavailableSurface(
};
return false;
}
if (node.fn === "crypto.dhNew" || node.fn === "crypto.dhGroupNew") {
found = {
surface: "DiffieHellman (the wasm32-wasi runtime does not include the mbedTLS library)",
loc,
};
return false;
}
if (node.fn === "os.networkInterfaces") {
found = {
surface: "network-interface enumeration (WASI Preview 1 has no interface API)",
@@ -67,6 +67,7 @@ export async function warmNativeCaches(
tls: false,
cipher: false,
ecdh: false,
dh: false,
webcrypto: false,
perfLoop: false,
tlsCa: false,
@@ -65,6 +65,7 @@ const native: EarlyExecutableNativeFeatures = {
tlsCa: false,
cipher: false,
ecdh: false,
dh: false,
webcrypto: false,
perfLoop: false,
};
@@ -96,6 +96,7 @@ export interface EarlyExecutableNativeFeatures {
tls: boolean;
cipher: boolean;
ecdh: boolean;
dh: boolean;
perfLoop: boolean;
tlsCa: boolean;
webcrypto: boolean;
@@ -228,6 +229,7 @@ const BOOLEAN_NATIVE_KEYS = [
"tlsCa",
"cipher",
"ecdh",
"dh",
"webcrypto",
"perfLoop",
] as const satisfies readonly (keyof EarlyExecutableNativeFeatures)[];
@@ -1,6 +1,7 @@
import { lowerBuiltinByteInput, errorFirstBytesCallback, errorFirstCallback } from "./arguments.js";
import { isKeyObjectValue } from "./key-object.js";
import { lowerCreateEcdh } from "./ecdh.js";
import { lowerCreateDiffieHellman, lowerGetDiffieHellman } from "./dh.js";
import { boolLit, dynUndefinedExpr, nodeThrowExpr, varRef } from "../../../ir/build.js";
import * as ts from "../../ts7/adapter.js";
import { type Lowerer, own } from "../lowerer.js";
@@ -410,6 +411,9 @@ export function lowerCryptoModuleCall(
};
}
if (bi.member === "createECDH") return lowerCreateEcdh(lowerer, expr);
if (bi.member === "createDiffieHellman") return lowerCreateDiffieHellman(lowerer, expr);
if (bi.member === "getDiffieHellman" || bi.member === "createDiffieHellmanGroup")
return lowerGetDiffieHellman(lowerer, expr);
if (bi.member === "createHmac") {
if (args.length < 1 || args.length > 3 || args.some(ts.isSpreadElement)) {
lowerer.noLowering(
@@ -0,0 +1,166 @@
import * as ts from "../../ts7/adapter.js";
import { nodeThrowExpr } from "../../../ir/build.js";
import { type Lowerer } from "../lowerer.js";
import { locOf } from "../../program.js";
import { DYN, type IrExpr, type IrStmt } from "../../../ir/ir.js";
import { v8CalleeText } from "./crypto.js";
import { dynArguments, refuseUnmatchedOverload } from "./ecdh.js";
/* node:crypto's DiffieHellman and DiffieHellmanGroup are native
* checked-dynamic handles (scr_dh.c): both types map to dyn, their methods
* dispatch through the handle, and these helpers lower
* createDiffieHellman, getDiffieHellman, createDiffieHellmanGroup and the
* method calls. The runtime applies Node's argument checks, so the
* constructors take any arguments; method calls are refused when their
* argument types leave the Buffer or string result undetermined. */
/** Whether a checker type is node:crypto's DiffieHellman class or its
* DiffieHellmanGroup alias, or a union of them. */
export function isDiffieHellmanType(lowerer: Lowerer, type: ts.Type): boolean {
if (type.isUnionType())
return ts.constituentTypes(type).every((part) => isDiffieHellmanType(lowerer, part));
const symbol = type.getAliasSymbol() ?? type.getSymbol();
if (!symbol || !lowerer.isStdlibSymbol(symbol)) return false;
const name = ts.symbolName(symbol);
return name === "DiffieHellman" || name === "DiffieHellmanGroup";
}
function isDiffieHellmanGroupType(type: ts.Type): boolean {
if (type.isUnionType()) return ts.constituentTypes(type).some(isDiffieHellmanGroupType);
const symbol = type.getAliasSymbol();
return !!symbol && ts.symbolName(symbol) === "DiffieHellmanGroup";
}
function newHandle(
lowerer: Lowerer,
call: ts.CallExpression,
fn: "crypto.dhNew" | "crypto.dhGroupNew",
): IrExpr {
const loc = locOf(call);
const stmts: IrStmt[] = [];
const values = dynArguments(lowerer, call, fn === "crypto.dhNew" ? 4 : 1, stmts, "%dhInput");
return {
kind: "seqExpr",
stmts,
result: { kind: "libCall", fn, args: values, type: DYN, loc },
type: DYN,
loc,
};
}
/** crypto.createDiffieHellman(sizeOrKey, keyEncoding, generator,
* generatorEncoding): a native DiffieHellman handle. */
export function lowerCreateDiffieHellman(lowerer: Lowerer, call: ts.CallExpression): IrExpr {
return newHandle(lowerer, call, "crypto.dhNew");
}
/** crypto.getDiffieHellman(groupName) and createDiffieHellmanGroup(name):
* a native DiffieHellmanGroup handle. */
export function lowerGetDiffieHellman(lowerer: Lowerer, call: ts.CallExpression): IrExpr {
return newHandle(lowerer, call, "crypto.dhGroupNew");
}
const DH_METHODS = new Set([
"generateKeys",
"computeSecret",
"getPrime",
"getGenerator",
"getPublicKey",
"getPrivateKey",
"setPublicKey",
"setPrivateKey",
]);
/** Object.prototype methods, which a DiffieHellman inherits. */
const OBJECT_METHODS = new Set([
"constructor",
"hasOwnProperty",
"isPrototypeOf",
"propertyIsEnumerable",
"toLocaleString",
"toString",
"valueOf",
]);
/** The argument that selects each method's Buffer or string result: the
* output encoding. */
const OUTPUT_ENCODING_ARG: Record<string, number> = {
generateKeys: 0,
computeSecret: 2,
getPrime: 0,
getGenerator: 0,
getPublicKey: 0,
getPrivateKey: 0,
};
/** An output encoding typed any: the checker's chosen overload then types
* the result as a Buffer or a string that Node may not answer, so the call
* is refused rather than checked against that type at run time. */
function refuseAnyOutputEncoding(lowerer: Lowerer, call: ts.CallExpression, name: string): void {
const index = OUTPUT_ENCODING_ARG[name];
const arg = index === undefined ? undefined : call.arguments.nodes[index];
if (!arg || (lowerer.typeOf(arg).flags & ts.TypeFlags.Any) === 0) return;
lowerer.noLowering(
`DiffieHellman.${name} with an output encoding typed any`,
arg,
"type the encoding as a BinaryToTextEncoding such as 'hex', or as null or undefined for a Buffer",
);
}
/** Calls on native DiffieHellman and DiffieHellmanGroup handles. Methods
* dispatch through the handle with checked-dynamic arguments. */
export function lowerDiffieHellmanCall(lowerer: Lowerer, call: ts.CallExpression): IrExpr | null {
if (call.questionDotToken || !ts.isPropertyAccessExpression(call.expression)) return null;
const access = call.expression;
if (access.questionDotToken) return null;
const receiver = lowerer.typeOf(access.expression);
if (!isDiffieHellmanType(lowerer, receiver)) return null;
const name = access.name.text;
const loc = locOf(call);
const setter = name === "setPublicKey" || name === "setPrivateKey";
if (!DH_METHODS.has(name) || (setter && isDiffieHellmanGroupType(receiver))) {
if (OBJECT_METHODS.has(name))
lowerer.noLowering(
`DiffieHellman.${name}`,
call,
"generateKeys(), computeSecret(), getPrime(), getGenerator(), getPublicKey(), getPrivateKey(), " +
"setPublicKey(), setPrivateKey() and verifyError are supported",
);
// Node reads the member as undefined (a DiffieHellmanGroup has no key
// setters) and throws a TypeError once the receiver and arguments are
// evaluated.
const evaluated = [access.expression, ...call.arguments.nodes].map((node): IrStmt => ({
kind: "exprStmt",
expr: lowerer.lowerExpr(node),
loc,
}));
return {
kind: "seqExpr",
stmts: evaluated,
result: nodeThrowExpr(1, "", `${v8CalleeText(access)} is not a function`, DYN, loc),
type: DYN,
loc,
};
}
if (call.arguments.nodes.some(ts.isSpreadElement))
lowerer.noLowering(`DiffieHellman.${name} with spread arguments`, call);
refuseAnyOutputEncoding(lowerer, call, name);
refuseUnmatchedOverload(lowerer, call, `DiffieHellman.${name}`);
const invoke: IrExpr = {
kind: "dynInvoke",
recv: lowerer.lowerExprExpecting(access.expression, DYN),
method: name,
calleeName: v8CalleeText(access),
args: call.arguments.nodes.map((arg) => lowerer.lowerExprExpecting(arg, DYN)),
type: DYN,
loc,
};
// setPublicKey and setPrivateKey answer the receiver where @types/node
// declares void. Other results take the static representation of the
// declared overload the arguments match.
if (setter) return invoke;
const result = lowerer.irTypeOf(call);
return result.kind === "bytes" || result.kind === "string"
? lowerer.coerceInto(call, invoke, result)
: invoke;
}
@@ -28,15 +28,16 @@ export function isEcdhType(lowerer: Lowerer, type: ts.Type): boolean {
return !!symbol && ts.symbolName(symbol) === "ECDH" && lowerer.isStdlibSymbol(symbol);
}
/** The call's arguments as checked-dynamic values in hidden locals, the
* first `count` of them padded with undefined, so every argument is
* evaluated left to right before the runtime checks them. Surplus
* arguments are evaluated and dropped. */
function dynArguments(
/** The call's arguments as checked-dynamic values in hidden locals named
* `local`, the first `count` of them padded with undefined, so every
* argument is evaluated left to right before the runtime checks them.
* Surplus arguments are evaluated and dropped. */
export function dynArguments(
lowerer: Lowerer,
call: ts.CallExpression,
count: number,
stmts: IrStmt[],
local = "%ecdhInput",
): IrExpr[] {
const args = call.arguments.nodes;
const loc = locOf(call);
@@ -45,7 +46,7 @@ function dynArguments(
const input: IrExpr = args[i]
? lowerer.lowerExprExpecting(args[i]!, DYN)
: dynUndefinedExpr(loc);
const saved = lowerer.declareHiddenLocal("%ecdhInput", DYN);
const saved = lowerer.declareHiddenLocal(local, DYN);
stmts.push({ kind: "varDecl", localId: saved.id, init: input, loc });
values.push(varRef(saved.id, DYN, loc));
}
@@ -137,7 +138,11 @@ function refuseViewKeyWithEncoding(lowerer: Lowerer, call: ts.CallExpression, na
* not follow (getPublicKey("HEX") answers a string where the encoding-less
* overload declares a Buffer), so the call is refused rather than checked
* against that type at run time. Arguments typed any are accepted. */
function refuseUnmatchedOverload(lowerer: Lowerer, call: ts.CallExpression, what: string): void {
export function refuseUnmatchedOverload(
lowerer: Lowerer,
call: ts.CallExpression,
what: string,
): void {
const signature = lowerer.checker.getResolvedSignature(call);
if (signature === undefined) return;
const params = signature.getParameters();
@@ -58,6 +58,7 @@ import { encodeBase64 } from "../../wasm/base64.js";
import { resolveRequireRuntime } from "../runtime-resolve.js";
import { lowerKeyObjectCall } from "./builtins/key-object.js";
import { isEcdhType, lowerEcdhCall } from "./builtins/ecdh.js";
import { isDiffieHellmanType, lowerDiffieHellmanCall } from "./builtins/dh.js";
import { fenceWebCryptoMember, lowerWebCryptoCall } from "./builtins/webcrypto.js";
import { hashStreamOf } from "./builtins/hash-stream.js";
import { lowerNetAddressCall, lowerNetAddressNew } from "./builtins/net-address.js";
@@ -3620,9 +3621,9 @@ export class Lowerer {
* is `unknown` or `object` (also with `null` or `undefined`, or an array
* of those), names checked protocol identity, is an owned runtime
* handle (a Worker or MessagePort, a fetch Headers/Request/Response, or
* a node:crypto ECDH), or is a WeakMap/WeakSet (native weak collections
* live in checked-dynamic storage, as locals of those types do); `any`
* fields stay refused. */
* a node:crypto ECDH, DiffieHellman or DiffieHellmanGroup), or is a
* WeakMap/WeakSet (native weak collections live in checked-dynamic
* storage, as locals of those types do); `any` fields stay refused. */
classFieldStoresDyn(type: ts.Type): boolean {
return (
this.opaqueValueType(type) ||
@@ -3630,7 +3631,10 @@ export class Lowerer {
isWorkerHandleType(type, this.typeCtx) ||
isFetchHandleType(type, this.typeCtx) ||
this.weakCollectionType(type) ||
this.stdlibHandleType(type, (part) => isEcdhType(this, part))
this.stdlibHandleType(
type,
(part) => isEcdhType(this, part) || isDiffieHellmanType(this, part),
)
);
}
@@ -12737,6 +12741,7 @@ export class Lowerer {
lowerWebCryptoCall(this, expr) ??
lowerKeyObjectCall(this, expr) ??
lowerEcdhCall(this, expr) ??
lowerDiffieHellmanCall(this, expr) ??
lowerNetAddressCall(this, expr) ??
lowerFetchElementMethodCall(this, expr) ??
lowerDynamicImportCall(this, expr) ??
@@ -1574,6 +1574,12 @@ export const BUILTIN_MODULE_FNS: Record<
// A checked-dynamic curve name; the result is a native ECDH handle
// (lowerCreateEcdh).
createECDH: { fn: "crypto.ecdhNew", params: [DYN], result: DYN },
// Checked-dynamic arguments; the result is a native DiffieHellman or
// DiffieHellmanGroup handle (lowerCreateDiffieHellman and
// lowerGetDiffieHellman).
createDiffieHellman: { fn: "crypto.dhNew", params: [DYN, DYN, DYN, DYN], result: DYN },
getDiffieHellman: { fn: "crypto.dhGroupNew", params: [DYN], result: DYN },
createDiffieHellmanGroup: { fn: "crypto.dhGroupNew", params: [DYN], result: DYN },
},
zlib: {
// The default-options convenience family is special-cased in
@@ -3063,10 +3069,6 @@ export const BUILTIN_MODULE_FENCE_HINTS: Record<
"createVerify",
"sign",
"verify",
"createDiffieHellman",
"createDiffieHellmanGroup",
"getDiffieHellman",
"diffieHellman",
"publicEncrypt",
"publicDecrypt",
"privateEncrypt",
@@ -3078,6 +3080,9 @@ export const BUILTIN_MODULE_FENCE_HINTS: Record<
"can be small; the lowered crypto surface is hashing, randomness, secret KeyObjects, and the introspection statics",
]),
),
diffieHellman:
"crypto.diffieHellman takes asymmetric KeyObjects, which the static runtime does not have; " +
"the objects of createDiffieHellman, getDiffieHellman and createECDH compute shared secrets",
...Object.fromEntries(
["getCipherInfo"].map((m) => [
m,
@@ -2973,6 +2973,23 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null {
) {
return DYN;
}
// node:crypto DiffieHellman values, and @types/node's DiffieHellmanGroup
// alias over them, are native handles carried by the checked-dynamic
// representation; lowerDiffieHellmanCall dispatches their methods.
{
const dhSym = widened.getAliasSymbol() ?? psym;
if (
dhSym !== undefined &&
(ts.symbolName(dhSym) === "DiffieHellman" || ts.symbolName(dhSym) === "DiffieHellmanGroup") &&
dhSym.declarations.some(
(d) =>
(ts.isClassDeclaration(d) || ts.isTypeAliasDeclaration(d)) &&
ctx.isStdlibFile(ts.getSourceFileOfNode(d)),
)
) {
return DYN;
}
}
// ReadonlyMap/ReadonlySet are the SAME runtime values as Map/Set — the
// readonly-ness is a checker-only view (no mutating members on the
// interface), so both map to the identical IR kinds and the read-side
+1
View File
@@ -620,6 +620,7 @@ async function compileExecutableNative(
tlsCa: features.tlsCa,
cipher: features.cipher,
ecdh: features.ecdh,
dh: features.dh,
webcrypto: features.webcrypto,
perfLoop: features.perfLoop,
...(onArtifactReady === undefined ? {} : { onArtifactReady }),
@@ -13,6 +13,9 @@ export const MAY_THROW_LIB_FNS: ReadonlySet<IrLibFn> = new Set([
// Node's curve, key, point, encoding and format errors.
"crypto.ecdhNew",
"crypto.ecdhConvertKey",
// Node's prime, generator, size, encoding and group-name errors.
"crypto.dhNew",
"crypto.dhGroupNew",
// node:test's { timeout } and { concurrency } range checks.
"test.register",
"test.registerEmpty",
@@ -2782,6 +2782,13 @@ export const LIB_FN_SIGS = defineLibFnSignatures({
/** ECDH.convertKey(key, curve, inputEncoding, outputEncoding, format):
* the converted point as a Buffer or string. */
"crypto.ecdhConvertKey": { argTypes: [DYN, DYN, DYN, DYN, DYN], result: DYN },
/** createDiffieHellman(sizeOrKey, keyEncoding, generator,
* generatorEncoding) over checked-dynamic arguments (scr_dh.c): a native
* DiffieHellman handle whose methods dispatch through dynInvoke. */
"crypto.dhNew": { argTypes: [DYN, DYN, DYN, DYN], result: DYN },
/** getDiffieHellman(groupName) and createDiffieHellmanGroup(name): a
* native DiffieHellmanGroup handle. */
"crypto.dhGroupNew": { argTypes: [DYN], result: DYN },
"crypto.hmacNewStr": { argTypes: [STRING, STRING], result: CRYPTOHMAC_T },
"crypto.hmacNewBytes": { argTypes: [STRING, BYTES_U8], result: CRYPTOHMAC_T },
"crypto.hashUpdateStr": { argTypes: [CRYPTOHASH_T, STRING], result: CRYPTOHASH_T },
@@ -744,6 +744,9 @@ const RUNTIME_FEATURE_RULES = {
* process-warning unit, and unknown encodings and formats render through
* the inspect unit. */
ecdh: rule({ fns: ["crypto.ecdhNew", "crypto.ecdhConvertKey"] }),
/** scr_dh.c over the mbedTLS archive; unknown encodings render through
* the inspect unit. */
dh: rule({ fns: ["crypto.dhNew", "crypto.dhGroupNew"] }),
emitter: rule({
initial: (mod) =>
mod.workers === true || (mod.classes ?? []).some((c) => c.name === RUNTIME_EMITTER_CLASS),
@@ -789,6 +792,8 @@ const RUNTIME_FEATURE_RULES = {
"crypto.cipherNew",
"crypto.ecdhNew",
"crypto.ecdhConvertKey",
"crypto.dhNew",
"crypto.dhGroupNew",
...BUILTIN_CLASS_LIB_FNS,
...UTIL_CALLABLE_LIB_FNS,
],
@@ -910,6 +915,7 @@ function noRuntimeFeatures(): RuntimeFeatures {
dynInvoke: false,
dynTier: false,
ecdh: false,
dh: false,
emitter: false,
eventTarget: false,
eventsOnceSignal: false,
@@ -52,6 +52,8 @@ const LIB_MODE_REFUSED_PREFIXES: readonly [string, string][] = [
["tls.", "the node:tls surface"],
["crypto.cipherNew", "crypto.createCipheriv and createDecipheriv"],
["crypto.ecdh", "crypto.createECDH and ECDH.convertKey"],
["crypto.dhNew", "crypto.createDiffieHellman"],
["crypto.dhGroupNew", "crypto.getDiffieHellman and createDiffieHellmanGroup"],
["webcrypto.", "WebCrypto (crypto.subtle)"],
["fs.watch", "fs.watch"],
["watcher.", "fs.watch"],
+1
View File
@@ -110,6 +110,7 @@ async function main(): Promise<number> {
tls: false,
cipher: false,
ecdh: false,
dh: false,
webcrypto: false,
perfLoop: false,
tlsCa: false,
+1
View File
@@ -161,6 +161,7 @@ function validFeatures(value: unknown): value is NativeLinkFeatures {
"tlsCa",
"cipher",
"ecdh",
"dh",
"webcrypto",
"perfLoop",
].every((name) => typeof features[name] === "boolean");
@@ -120,6 +120,7 @@ test.skipIf(process.platform !== "linux" && process.platform !== "darwin")(
tlsCa: false,
cipher: false,
ecdh: false,
dh: false,
webcrypto: false,
perfLoop: false,
nativeFetch: false,
+4 -10
View File
@@ -496,17 +496,13 @@
"id": "node-builtin.crypto.createDiffieHellman",
"kind": "node-builtin",
"name": "crypto.createDiffieHellman",
"status": "unsupported",
"code": "SC2020",
"note": "asymmetric-key operations need a public-key stack (bignum, RSA/EC/EdDSA math) and public and private KeyObjects — neither exists in the static runtime, so no faithful lowering can be small; the lowered crypto surface is hashing, randomness, secret KeyObjects, and the introspection statics"
"status": "static"
},
{
"id": "node-builtin.crypto.createDiffieHellmanGroup",
"kind": "node-builtin",
"name": "crypto.createDiffieHellmanGroup",
"status": "unsupported",
"code": "SC2020",
"note": "asymmetric-key operations need a public-key stack (bignum, RSA/EC/EdDSA math) and public and private KeyObjects — neither exists in the static runtime, so no faithful lowering can be small; the lowered crypto surface is hashing, randomness, secret KeyObjects, and the introspection statics"
"status": "static"
},
{
"id": "node-builtin.crypto.createECDH",
@@ -570,7 +566,7 @@
"name": "crypto.diffieHellman",
"status": "unsupported",
"code": "SC2020",
"note": "asymmetric-key operations need a public-key stack (bignum, RSA/EC/EdDSA math) and public and private KeyObjects — neither exists in the static runtime, so no faithful lowering can be small; the lowered crypto surface is hashing, randomness, secret KeyObjects, and the introspection statics"
"note": "crypto.diffieHellman takes asymmetric KeyObjects, which the static runtime does not have; the objects of createDiffieHellman, getDiffieHellman and createECDH compute shared secrets"
},
{
"id": "node-builtin.crypto.generateKey",
@@ -612,9 +608,7 @@
"id": "node-builtin.crypto.getDiffieHellman",
"kind": "node-builtin",
"name": "crypto.getDiffieHellman",
"status": "unsupported",
"code": "SC2020",
"note": "asymmetric-key operations need a public-key stack (bignum, RSA/EC/EdDSA math) and public and private KeyObjects — neither exists in the static runtime, so no faithful lowering can be small; the lowered crypto surface is hashing, randomness, secret KeyObjects, and the introspection statics"
"status": "static"
},
{
"id": "node-builtin.crypto.getRandomValues",
+5
View File
@@ -291,6 +291,11 @@ test.skipIf(!zigOnPath())(
options: { ecdh: true, dynAsync: true, dynInvoke: true, inspect: true },
call: "scr_dyn_release(scr_crypto_ecdh_new(scr_dyn_undefined()))",
},
{
name: "dh",
options: { dh: true, dynInvoke: true, inspect: true },
call: "scr_dyn_release(scr_crypto_dh_group_new(scr_dyn_undefined()))",
},
];
try {
await withCcEnv("zigcc", "x86_64-windows-gnu", async () => {
@@ -0,0 +1,6 @@
{
"order": [
"<repo>/tests/corpus/6706-dh-groups.ts"
],
"diags": []
}
@@ -0,0 +1,6 @@
{
"order": [
"<repo>/tests/corpus/6707-dh-explicit-params.ts"
],
"diags": []
}
@@ -0,0 +1,6 @@
{
"order": [
"<repo>/tests/corpus/6708-dh-errors.js"
],
"diags": []
}
@@ -0,0 +1,6 @@
{
"order": [
"<repo>/tests/corpus/6709-dh-generate.ts"
],
"diags": []
}
@@ -0,0 +1,6 @@
{
"order": [
"<repo>/tests/corpus/6710-dh-encodings.cjs"
],
"diags": []
}
@@ -0,0 +1,6 @@
{
"order": [
"<repo>/tests/corpus/6711-dh-handles.ts"
],
"diags": []
}
@@ -0,0 +1,6 @@
{
"order": [
"<repo>/tests/fixtures/node-types/dh.ts"
],
"diags": []
}
@@ -43,7 +43,7 @@ export const RUNTIME_PACK_MATRIX = withLibraryRuntimeFlavors(
{ id: "quickjs", predicate: false },
{ id: "libregexp", predicate: "regex" },
{ id: "zlib", predicate: "zlibEffective" },
{ id: "mbedtls", predicate: any("tlsEffective", "cipher", "ecdh") },
{ id: "mbedtls", predicate: any("tlsEffective", "cipher", "ecdh", "dh") },
],
system_libraries: [{ name: "System", predicate: true }],
}),
@@ -172,7 +172,8 @@ async function build() {
...(unit.source === "scr_regex.c" ? ["-I", quickjs] : []),
...(unit.source === "scr_tls.c" ||
unit.source === "scr_cipher.c" ||
unit.source === "scr_ecdh.c"
unit.source === "scr_ecdh.c" ||
unit.source === "scr_dh.c"
? ["-I", join(mbedtls, "include")]
: []),
...(unit.source === "scr_zlib.c" || unit.source === "scr_fetch.c"
@@ -149,6 +149,7 @@ export const OPTIONAL_RUNTIME_SOURCES = [
["scr_tls.c", "tlsEffective"],
["scr_cipher.c", "cipher"],
["scr_ecdh.c", "ecdh"],
["scr_dh.c", "dh"],
["scr_wasm.c", "wasm"],
["scr_webcrypto.c", "webcrypto"],
["scr_fetch.c", "nativeFetch"],
@@ -212,7 +213,7 @@ export function createRuntimePackMatrix({
{ id: "quickjs", predicate: false },
{ id: "libregexp", predicate: "regex" },
{ id: "zlib", predicate: "zlibEffective" },
{ id: "mbedtls", predicate: any("tlsEffective", "cipher", "ecdh") },
{ id: "mbedtls", predicate: any("tlsEffective", "cipher", "ecdh", "dh") },
];
const matrix = withLibraryRuntimeFlavors(
withWorkerRuntimeVariants({
@@ -223,7 +223,8 @@ async function build() {
...(unit.source === "scr_regex.c" ? ["-I", quickjs] : []),
...(unit.source === "scr_tls.c" ||
unit.source === "scr_cipher.c" ||
unit.source === "scr_ecdh.c"
unit.source === "scr_ecdh.c" ||
unit.source === "scr_dh.c"
? ["-I", join(mbedtls, "include")]
: []),
...(unit.source === "scr_zlib.c" || unit.source === "scr_fetch.c"
@@ -22,6 +22,7 @@ process.env.SCRIPTC_RUNTIME_PACK_CONFIG = JSON.stringify({
"scr_tls.c",
"scr_cipher.c",
"scr_ecdh.c",
"scr_dh.c",
"scr_wasm.c",
"scr_fetch.c",
],
+7
View File
@@ -94,6 +94,13 @@ ScrDyn *scr_crypto_cipher_new(bool decrypt, ScrDyn *cipher, ScrDyn *key, ScrDyn
* or result, or NULL with Node's error pending. */
ScrDyn *scr_crypto_ecdh_new(ScrDyn *curve);
ScrDyn *scr_crypto_ecdh_convert_key(ScrDyn *key, ScrDyn *curve, ScrDyn *in_enc, ScrDyn *out_enc, ScrDyn *format);
/* crypto.createDiffieHellman(sizeOrKey, keyEncoding, generator,
* generatorEncoding) and crypto.getDiffieHellman(groupName) over
* checked-dynamic arguments (scr_dh.c, linked with the vendored mbedTLS
* archive). +1 DiffieHellman or DiffieHellmanGroup handle, or NULL with
* Node's error pending. */
ScrDyn *scr_crypto_dh_new(ScrDyn *size_or_key, ScrDyn *key_encoding, ScrDyn *generator, ScrDyn *generator_encoding);
ScrDyn *scr_crypto_dh_group_new(ScrDyn *name);
ScrBytes *scr_crypto_pbkdf2(ScrBytes *password, ScrBytes *salt,
double iterations, double keylen, ScrStr *digest);
ScrBytes *scr_crypto_pbkdf2_job(ScrBytes *password, ScrBytes *salt, double iterations,
+181
View File
@@ -0,0 +1,181 @@
/* Argument and result handling shared by the checked-dynamic node:crypto
* key-exchange handles (scr_ecdh.c and scr_dh.c), as Node 24's
* lib/internal/crypto/diffiehellman.js and lib/internal/crypto/util.js
* read keys and encodings: getArrayBufferOrView for key inputs and
* encode() for Buffer results. `subject` names the value in the coded
* SC2020 error for encodings that have no lowering ("An ECDH encoding or
* format"). All arguments are borrowed. */
#ifndef SCR_CRYPTO_ARGS_H
#define SCR_CRYPTO_ARGS_H
#include "scr_runtime.h"
#include <string.h>
/* An object's toString the program defined, as an own or inherited
* function property. */
static bool ca_custom_to_string(ScrDyn *value) {
if (value->kind != SCR_DYN_OBJ && value->kind != SCR_DYN_TYPED_REF) return false;
ScrDyn *member = scr_dyn_obj_read(value, "toString", 8);
bool custom = member && member->kind == SCR_DYN_FUNC;
scr_dyn_release(member);
return custom;
}
/* Whether value is a class instance whose class defines toString. */
static bool ca_class_to_string(const ScrDyn *value) {
ScrStr *name = scr_str_new("toString", 8);
bool method = scr_dyn_typed_ref_class_has(value, name);
scr_str_release(name);
return method;
}
/* `prefix` and the value as util.format's %s renders it: strings and
* objects with a program-defined toString as String(value), numbers as
* util.inspect does, other values inspected at depth 0. Functions and
* class instances that define toString have no lowering. */
static void ca_throw_formatted(const char *subject, const char *code, const char *prefix, const ScrDyn *value) {
ScrDyn *v = (ScrDyn *)value;
if (v->kind == SCR_DYN_FUNC || ca_class_to_string(v)) {
ScrJsonBuf b;
scr_jb_init(&b);
scr_jb_puts(&b, subject);
scr_jb_puts(&b, " that is a function or an instance of a class defining toString has no lowering; "
"pass the name as a string");
ScrStr *message = scr_jb_finish(&b);
scr_throw_error_msg_code(SCR_ERR_ERROR, message->data, message->len, "SC2020");
scr_str_release(message);
return;
}
ScrStr *text;
if (v->kind == SCR_DYN_STR || ca_custom_to_string(v)) text = scr_dyn_string_coerce_js(v);
else if (v->kind == SCR_DYN_NUM) text = scr_insp_f64(v->v.num);
else text = scr_insp_dyn_s(v, 0);
if (!text) return;
ScrJsonBuf b;
scr_jb_init(&b);
scr_jb_puts(&b, prefix);
scr_jb_put_str(&b, text);
scr_str_release(text);
ScrStr *message = scr_jb_finish(&b);
scr_throw_error_msg_code(SCR_ERR_TYPE, message->data, message->len, code);
scr_str_release(message);
}
static bool ca_ascii_eq_ci(const char *a, size_t a_len, const char *b) {
size_t b_len = strlen(b);
if (a_len != b_len) return false;
for (size_t i = 0; i < a_len; i++) {
char x = a[i];
if (x >= 'A' && x <= 'Z') x = (char)(x - 'A' + 'a');
if (x != b[i]) return false;
}
return true;
}
static bool ca_str_is(const ScrStr *text, const char *literal) {
size_t len = strlen(literal);
return text->len == len && memcmp(text->data, literal, len) == 0;
}
/* Node's normalizeEncoding: the canonical name, or NULL. */
static const char *ca_normalize_encoding(const ScrStr *name) {
static const struct { const char *from; const char *to; } map[] = {
{"utf8", "utf8"}, {"utf-8", "utf8"}, {"hex", "hex"},
{"base64", "base64"}, {"base64url", "base64url"}, {"latin1", "latin1"},
{"binary", "latin1"}, {"ascii", "ascii"}, {"utf16le", "utf16le"},
{"utf-16le", "utf16le"}, {"ucs2", "utf16le"}, {"ucs-2", "utf16le"},
};
for (size_t i = 0; i < sizeof map / sizeof map[0]; i++)
if (ca_ascii_eq_ci(name->data, name->len, map[i].from)) return map[i].to;
return NULL;
}
/* The value a typed-ref box holds when it is a string, view, ArrayBuffer
* or native handle (+1). Other values are retained as passed, so argument
* errors describe the original value. NULL after throwing. */
static ScrDyn *ca_unbox(ScrDyn *value) {
if (value->kind != SCR_DYN_TYPED_REF) return scr_dyn_retain(value);
ScrDyn *view = scr_dyn_typed_ref_materialize(value);
if (!view) return NULL;
if (view->kind == SCR_DYN_STR || view->kind == SCR_DYN_BYTES || view->kind == SCR_DYN_HANDLE ||
scr_buffer_storage_is(view))
return view;
scr_dyn_release(view);
return scr_dyn_retain(value);
}
/* Buffer.from(text, encoding) as toBuf calls it: an encoding that is not
* a non-empty string, or is 'buffer', reads as utf8. +1 or NULL after
* throwing. */
static ScrBytes *ca_string_bytes(const char *subject, const ScrStr *text, const ScrDyn *encoding) {
const char *name = "utf8";
if (encoding->kind == SCR_DYN_STR && encoding->v.str->len > 0 && !ca_str_is(encoding->v.str, "buffer")) {
name = ca_normalize_encoding(encoding->v.str);
if (!name) {
ca_throw_formatted(subject, "ERR_UNKNOWN_ENCODING", "Unknown encoding: ", encoding);
return NULL;
}
}
ScrStr *canonical = scr_str_new(name, strlen(name));
ScrBytes *bytes = scr_bytes_from_str(text, canonical);
scr_str_release(canonical);
return bytes;
}
/* getArrayBufferOrView(key, 'key', encoding): a string is Buffer.from(key,
* encoding) with 'buffer' read as utf8; views and ArrayBuffers are their
* bytes. +1 or NULL after throwing. */
static ScrBytes *ca_key_bytes(const char *subject, const ScrDyn *key, const ScrDyn *encoding) {
if (key->kind == SCR_DYN_STR) return ca_string_bytes(subject, key->v.str, encoding);
if (key->kind == SCR_DYN_BYTES || scr_buffer_storage_is(key)) return scr_bytes_buffer_source(key);
scr_dyn_arg_type_fail("key", "of type string or an instance of ArrayBuffer, Buffer, TypedArray, or DataView", key);
return NULL;
}
/* encode(buffer, encoding): the Buffer, or buffer.toString(encoding) for
* a truthy encoding other than 'buffer'. Consumes bytes. */
static ScrDyn *ca_encode(const char *subject, ScrBytes *bytes, const ScrDyn *encoding) {
if (!scr_dyn_truthy(encoding) || (encoding->kind == SCR_DYN_STR && ca_str_is(encoding->v.str, "buffer"))) {
ScrDyn *result = scr_dyn_new_buffer(bytes);
scr_bytes_release(bytes);
return result;
}
/* toString answers "" for no bytes before it reads the encoding. */
ScrStr *text = NULL;
if (bytes->len == 0) {
text = scr_str_new("", 0);
} else {
/* getEncodingOps reads `encoding + ''`. */
ScrStr *name = encoding->kind == SCR_DYN_STR ? scr_str_retain(encoding->v.str) : NULL;
if (!name) {
if (encoding->kind == SCR_DYN_FUNC || ca_class_to_string(encoding)) {
ca_throw_formatted(subject, "ERR_UNKNOWN_ENCODING", "Unknown encoding: ", encoding);
scr_bytes_release(bytes);
return NULL;
}
name = scr_dyn_string_coerce_js(encoding);
if (!name) {
scr_bytes_release(bytes);
return NULL;
}
}
const char *canonical = ca_normalize_encoding(name);
scr_str_release(name);
if (!canonical) {
ca_throw_formatted(subject, "ERR_UNKNOWN_ENCODING", "Unknown encoding: ", encoding);
scr_bytes_release(bytes);
return NULL;
}
ScrStr *canonical_text = scr_str_new(canonical, strlen(canonical));
text = scr_bytes_to_str(bytes, canonical_text);
scr_str_release(canonical_text);
}
scr_bytes_release(bytes);
if (!text) return NULL;
ScrDyn *result = scr_dyn_new_str(text);
scr_str_release(text);
return result;
}
#endif
File diff suppressed because it is too large Load Diff
+557
View File
@@ -0,0 +1,557 @@
/* Diffie-Hellman group parameters, big-endian: the primes behind Node 24's
* crypto.getDiffieHellman groups (modp1 and modp2 from RFC 2409, modp5 and
* modp14 through modp18 from RFC 3526), and the RFC 7919 (ffdhe2048 through
* ffdhe8192) and RFC 5114 (dh_1024_160, dh_2048_224 and dh_2048_256)
* parameters OpenSSL 3.5 lists among its DH named groups
* (crypto/ffc/ffc_dh.c). Every group but RFC 5114's uses the generator 2
* and a safe prime. */
#ifndef SCR_DH_GROUPS_H
#define SCR_DH_GROUPS_H
static const unsigned char scr_dh_modp1_p[96] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x3a, 0x36, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const unsigned char scr_dh_modp2_p[128] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6,
0x49, 0x28, 0x66, 0x51, 0xec, 0xe6, 0x53, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const unsigned char scr_dh_modp5_p[192] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6,
0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05,
0x98, 0xda, 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f,
0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb,
0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04,
0xf1, 0x74, 0x6c, 0x08, 0xca, 0x23, 0x73, 0x27, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const unsigned char scr_dh_modp14_p[256] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6,
0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05,
0x98, 0xda, 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f,
0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb,
0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04,
0xf1, 0x74, 0x6c, 0x08, 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b,
0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2, 0xec, 0x07, 0xa2, 0x8f,
0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9, 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18,
0x39, 0x95, 0x49, 0x7c, 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10,
0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xac, 0xaa, 0x68, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const unsigned char scr_dh_modp15_p[384] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6,
0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05,
0x98, 0xda, 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f,
0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb,
0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04,
0xf1, 0x74, 0x6c, 0x08, 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b,
0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2, 0xec, 0x07, 0xa2, 0x8f,
0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9, 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18,
0x39, 0x95, 0x49, 0x7c, 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10,
0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xaa, 0xc4, 0x2d, 0xad, 0x33, 0x17, 0x0d, 0x04, 0x50, 0x7a, 0x33,
0xa8, 0x55, 0x21, 0xab, 0xdf, 0x1c, 0xba, 0x64, 0xec, 0xfb, 0x85, 0x04, 0x58, 0xdb, 0xef, 0x0a,
0x8a, 0xea, 0x71, 0x57, 0x5d, 0x06, 0x0c, 0x7d, 0xb3, 0x97, 0x0f, 0x85, 0xa6, 0xe1, 0xe4, 0xc7,
0xab, 0xf5, 0xae, 0x8c, 0xdb, 0x09, 0x33, 0xd7, 0x1e, 0x8c, 0x94, 0xe0, 0x4a, 0x25, 0x61, 0x9d,
0xce, 0xe3, 0xd2, 0x26, 0x1a, 0xd2, 0xee, 0x6b, 0xf1, 0x2f, 0xfa, 0x06, 0xd9, 0x8a, 0x08, 0x64,
0xd8, 0x76, 0x02, 0x73, 0x3e, 0xc8, 0x6a, 0x64, 0x52, 0x1f, 0x2b, 0x18, 0x17, 0x7b, 0x20, 0x0c,
0xbb, 0xe1, 0x17, 0x57, 0x7a, 0x61, 0x5d, 0x6c, 0x77, 0x09, 0x88, 0xc0, 0xba, 0xd9, 0x46, 0xe2,
0x08, 0xe2, 0x4f, 0xa0, 0x74, 0xe5, 0xab, 0x31, 0x43, 0xdb, 0x5b, 0xfc, 0xe0, 0xfd, 0x10, 0x8e,
0x4b, 0x82, 0xd1, 0x20, 0xa9, 0x3a, 0xd2, 0xca, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const unsigned char scr_dh_modp16_p[512] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6,
0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05,
0x98, 0xda, 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f,
0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb,
0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04,
0xf1, 0x74, 0x6c, 0x08, 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b,
0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2, 0xec, 0x07, 0xa2, 0x8f,
0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9, 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18,
0x39, 0x95, 0x49, 0x7c, 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10,
0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xaa, 0xc4, 0x2d, 0xad, 0x33, 0x17, 0x0d, 0x04, 0x50, 0x7a, 0x33,
0xa8, 0x55, 0x21, 0xab, 0xdf, 0x1c, 0xba, 0x64, 0xec, 0xfb, 0x85, 0x04, 0x58, 0xdb, 0xef, 0x0a,
0x8a, 0xea, 0x71, 0x57, 0x5d, 0x06, 0x0c, 0x7d, 0xb3, 0x97, 0x0f, 0x85, 0xa6, 0xe1, 0xe4, 0xc7,
0xab, 0xf5, 0xae, 0x8c, 0xdb, 0x09, 0x33, 0xd7, 0x1e, 0x8c, 0x94, 0xe0, 0x4a, 0x25, 0x61, 0x9d,
0xce, 0xe3, 0xd2, 0x26, 0x1a, 0xd2, 0xee, 0x6b, 0xf1, 0x2f, 0xfa, 0x06, 0xd9, 0x8a, 0x08, 0x64,
0xd8, 0x76, 0x02, 0x73, 0x3e, 0xc8, 0x6a, 0x64, 0x52, 0x1f, 0x2b, 0x18, 0x17, 0x7b, 0x20, 0x0c,
0xbb, 0xe1, 0x17, 0x57, 0x7a, 0x61, 0x5d, 0x6c, 0x77, 0x09, 0x88, 0xc0, 0xba, 0xd9, 0x46, 0xe2,
0x08, 0xe2, 0x4f, 0xa0, 0x74, 0xe5, 0xab, 0x31, 0x43, 0xdb, 0x5b, 0xfc, 0xe0, 0xfd, 0x10, 0x8e,
0x4b, 0x82, 0xd1, 0x20, 0xa9, 0x21, 0x08, 0x01, 0x1a, 0x72, 0x3c, 0x12, 0xa7, 0x87, 0xe6, 0xd7,
0x88, 0x71, 0x9a, 0x10, 0xbd, 0xba, 0x5b, 0x26, 0x99, 0xc3, 0x27, 0x18, 0x6a, 0xf4, 0xe2, 0x3c,
0x1a, 0x94, 0x68, 0x34, 0xb6, 0x15, 0x0b, 0xda, 0x25, 0x83, 0xe9, 0xca, 0x2a, 0xd4, 0x4c, 0xe8,
0xdb, 0xbb, 0xc2, 0xdb, 0x04, 0xde, 0x8e, 0xf9, 0x2e, 0x8e, 0xfc, 0x14, 0x1f, 0xbe, 0xca, 0xa6,
0x28, 0x7c, 0x59, 0x47, 0x4e, 0x6b, 0xc0, 0x5d, 0x99, 0xb2, 0x96, 0x4f, 0xa0, 0x90, 0xc3, 0xa2,
0x23, 0x3b, 0xa1, 0x86, 0x51, 0x5b, 0xe7, 0xed, 0x1f, 0x61, 0x29, 0x70, 0xce, 0xe2, 0xd7, 0xaf,
0xb8, 0x1b, 0xdd, 0x76, 0x21, 0x70, 0x48, 0x1c, 0xd0, 0x06, 0x91, 0x27, 0xd5, 0xb0, 0x5a, 0xa9,
0x93, 0xb4, 0xea, 0x98, 0x8d, 0x8f, 0xdd, 0xc1, 0x86, 0xff, 0xb7, 0xdc, 0x90, 0xa6, 0xc0, 0x8f,
0x4d, 0xf4, 0x35, 0xc9, 0x34, 0x06, 0x31, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const unsigned char scr_dh_modp17_p[768] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6,
0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05,
0x98, 0xda, 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f,
0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb,
0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04,
0xf1, 0x74, 0x6c, 0x08, 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b,
0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2, 0xec, 0x07, 0xa2, 0x8f,
0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9, 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18,
0x39, 0x95, 0x49, 0x7c, 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10,
0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xaa, 0xc4, 0x2d, 0xad, 0x33, 0x17, 0x0d, 0x04, 0x50, 0x7a, 0x33,
0xa8, 0x55, 0x21, 0xab, 0xdf, 0x1c, 0xba, 0x64, 0xec, 0xfb, 0x85, 0x04, 0x58, 0xdb, 0xef, 0x0a,
0x8a, 0xea, 0x71, 0x57, 0x5d, 0x06, 0x0c, 0x7d, 0xb3, 0x97, 0x0f, 0x85, 0xa6, 0xe1, 0xe4, 0xc7,
0xab, 0xf5, 0xae, 0x8c, 0xdb, 0x09, 0x33, 0xd7, 0x1e, 0x8c, 0x94, 0xe0, 0x4a, 0x25, 0x61, 0x9d,
0xce, 0xe3, 0xd2, 0x26, 0x1a, 0xd2, 0xee, 0x6b, 0xf1, 0x2f, 0xfa, 0x06, 0xd9, 0x8a, 0x08, 0x64,
0xd8, 0x76, 0x02, 0x73, 0x3e, 0xc8, 0x6a, 0x64, 0x52, 0x1f, 0x2b, 0x18, 0x17, 0x7b, 0x20, 0x0c,
0xbb, 0xe1, 0x17, 0x57, 0x7a, 0x61, 0x5d, 0x6c, 0x77, 0x09, 0x88, 0xc0, 0xba, 0xd9, 0x46, 0xe2,
0x08, 0xe2, 0x4f, 0xa0, 0x74, 0xe5, 0xab, 0x31, 0x43, 0xdb, 0x5b, 0xfc, 0xe0, 0xfd, 0x10, 0x8e,
0x4b, 0x82, 0xd1, 0x20, 0xa9, 0x21, 0x08, 0x01, 0x1a, 0x72, 0x3c, 0x12, 0xa7, 0x87, 0xe6, 0xd7,
0x88, 0x71, 0x9a, 0x10, 0xbd, 0xba, 0x5b, 0x26, 0x99, 0xc3, 0x27, 0x18, 0x6a, 0xf4, 0xe2, 0x3c,
0x1a, 0x94, 0x68, 0x34, 0xb6, 0x15, 0x0b, 0xda, 0x25, 0x83, 0xe9, 0xca, 0x2a, 0xd4, 0x4c, 0xe8,
0xdb, 0xbb, 0xc2, 0xdb, 0x04, 0xde, 0x8e, 0xf9, 0x2e, 0x8e, 0xfc, 0x14, 0x1f, 0xbe, 0xca, 0xa6,
0x28, 0x7c, 0x59, 0x47, 0x4e, 0x6b, 0xc0, 0x5d, 0x99, 0xb2, 0x96, 0x4f, 0xa0, 0x90, 0xc3, 0xa2,
0x23, 0x3b, 0xa1, 0x86, 0x51, 0x5b, 0xe7, 0xed, 0x1f, 0x61, 0x29, 0x70, 0xce, 0xe2, 0xd7, 0xaf,
0xb8, 0x1b, 0xdd, 0x76, 0x21, 0x70, 0x48, 0x1c, 0xd0, 0x06, 0x91, 0x27, 0xd5, 0xb0, 0x5a, 0xa9,
0x93, 0xb4, 0xea, 0x98, 0x8d, 0x8f, 0xdd, 0xc1, 0x86, 0xff, 0xb7, 0xdc, 0x90, 0xa6, 0xc0, 0x8f,
0x4d, 0xf4, 0x35, 0xc9, 0x34, 0x02, 0x84, 0x92, 0x36, 0xc3, 0xfa, 0xb4, 0xd2, 0x7c, 0x70, 0x26,
0xc1, 0xd4, 0xdc, 0xb2, 0x60, 0x26, 0x46, 0xde, 0xc9, 0x75, 0x1e, 0x76, 0x3d, 0xba, 0x37, 0xbd,
0xf8, 0xff, 0x94, 0x06, 0xad, 0x9e, 0x53, 0x0e, 0xe5, 0xdb, 0x38, 0x2f, 0x41, 0x30, 0x01, 0xae,
0xb0, 0x6a, 0x53, 0xed, 0x90, 0x27, 0xd8, 0x31, 0x17, 0x97, 0x27, 0xb0, 0x86, 0x5a, 0x89, 0x18,
0xda, 0x3e, 0xdb, 0xeb, 0xcf, 0x9b, 0x14, 0xed, 0x44, 0xce, 0x6c, 0xba, 0xce, 0xd4, 0xbb, 0x1b,
0xdb, 0x7f, 0x14, 0x47, 0xe6, 0xcc, 0x25, 0x4b, 0x33, 0x20, 0x51, 0x51, 0x2b, 0xd7, 0xaf, 0x42,
0x6f, 0xb8, 0xf4, 0x01, 0x37, 0x8c, 0xd2, 0xbf, 0x59, 0x83, 0xca, 0x01, 0xc6, 0x4b, 0x92, 0xec,
0xf0, 0x32, 0xea, 0x15, 0xd1, 0x72, 0x1d, 0x03, 0xf4, 0x82, 0xd7, 0xce, 0x6e, 0x74, 0xfe, 0xf6,
0xd5, 0x5e, 0x70, 0x2f, 0x46, 0x98, 0x0c, 0x82, 0xb5, 0xa8, 0x40, 0x31, 0x90, 0x0b, 0x1c, 0x9e,
0x59, 0xe7, 0xc9, 0x7f, 0xbe, 0xc7, 0xe8, 0xf3, 0x23, 0xa9, 0x7a, 0x7e, 0x36, 0xcc, 0x88, 0xbe,
0x0f, 0x1d, 0x45, 0xb7, 0xff, 0x58, 0x5a, 0xc5, 0x4b, 0xd4, 0x07, 0xb2, 0x2b, 0x41, 0x54, 0xaa,
0xcc, 0x8f, 0x6d, 0x7e, 0xbf, 0x48, 0xe1, 0xd8, 0x14, 0xcc, 0x5e, 0xd2, 0x0f, 0x80, 0x37, 0xe0,
0xa7, 0x97, 0x15, 0xee, 0xf2, 0x9b, 0xe3, 0x28, 0x06, 0xa1, 0xd5, 0x8b, 0xb7, 0xc5, 0xda, 0x76,
0xf5, 0x50, 0xaa, 0x3d, 0x8a, 0x1f, 0xbf, 0xf0, 0xeb, 0x19, 0xcc, 0xb1, 0xa3, 0x13, 0xd5, 0x5c,
0xda, 0x56, 0xc9, 0xec, 0x2e, 0xf2, 0x96, 0x32, 0x38, 0x7f, 0xe8, 0xd7, 0x6e, 0x3c, 0x04, 0x68,
0x04, 0x3e, 0x8f, 0x66, 0x3f, 0x48, 0x60, 0xee, 0x12, 0xbf, 0x2d, 0x5b, 0x0b, 0x74, 0x74, 0xd6,
0xe6, 0x94, 0xf9, 0x1e, 0x6d, 0xcc, 0x40, 0x24, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const unsigned char scr_dh_modp18_p[1024] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6,
0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05,
0x98, 0xda, 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f,
0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb,
0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04,
0xf1, 0x74, 0x6c, 0x08, 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b,
0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2, 0xec, 0x07, 0xa2, 0x8f,
0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9, 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18,
0x39, 0x95, 0x49, 0x7c, 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10,
0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xaa, 0xc4, 0x2d, 0xad, 0x33, 0x17, 0x0d, 0x04, 0x50, 0x7a, 0x33,
0xa8, 0x55, 0x21, 0xab, 0xdf, 0x1c, 0xba, 0x64, 0xec, 0xfb, 0x85, 0x04, 0x58, 0xdb, 0xef, 0x0a,
0x8a, 0xea, 0x71, 0x57, 0x5d, 0x06, 0x0c, 0x7d, 0xb3, 0x97, 0x0f, 0x85, 0xa6, 0xe1, 0xe4, 0xc7,
0xab, 0xf5, 0xae, 0x8c, 0xdb, 0x09, 0x33, 0xd7, 0x1e, 0x8c, 0x94, 0xe0, 0x4a, 0x25, 0x61, 0x9d,
0xce, 0xe3, 0xd2, 0x26, 0x1a, 0xd2, 0xee, 0x6b, 0xf1, 0x2f, 0xfa, 0x06, 0xd9, 0x8a, 0x08, 0x64,
0xd8, 0x76, 0x02, 0x73, 0x3e, 0xc8, 0x6a, 0x64, 0x52, 0x1f, 0x2b, 0x18, 0x17, 0x7b, 0x20, 0x0c,
0xbb, 0xe1, 0x17, 0x57, 0x7a, 0x61, 0x5d, 0x6c, 0x77, 0x09, 0x88, 0xc0, 0xba, 0xd9, 0x46, 0xe2,
0x08, 0xe2, 0x4f, 0xa0, 0x74, 0xe5, 0xab, 0x31, 0x43, 0xdb, 0x5b, 0xfc, 0xe0, 0xfd, 0x10, 0x8e,
0x4b, 0x82, 0xd1, 0x20, 0xa9, 0x21, 0x08, 0x01, 0x1a, 0x72, 0x3c, 0x12, 0xa7, 0x87, 0xe6, 0xd7,
0x88, 0x71, 0x9a, 0x10, 0xbd, 0xba, 0x5b, 0x26, 0x99, 0xc3, 0x27, 0x18, 0x6a, 0xf4, 0xe2, 0x3c,
0x1a, 0x94, 0x68, 0x34, 0xb6, 0x15, 0x0b, 0xda, 0x25, 0x83, 0xe9, 0xca, 0x2a, 0xd4, 0x4c, 0xe8,
0xdb, 0xbb, 0xc2, 0xdb, 0x04, 0xde, 0x8e, 0xf9, 0x2e, 0x8e, 0xfc, 0x14, 0x1f, 0xbe, 0xca, 0xa6,
0x28, 0x7c, 0x59, 0x47, 0x4e, 0x6b, 0xc0, 0x5d, 0x99, 0xb2, 0x96, 0x4f, 0xa0, 0x90, 0xc3, 0xa2,
0x23, 0x3b, 0xa1, 0x86, 0x51, 0x5b, 0xe7, 0xed, 0x1f, 0x61, 0x29, 0x70, 0xce, 0xe2, 0xd7, 0xaf,
0xb8, 0x1b, 0xdd, 0x76, 0x21, 0x70, 0x48, 0x1c, 0xd0, 0x06, 0x91, 0x27, 0xd5, 0xb0, 0x5a, 0xa9,
0x93, 0xb4, 0xea, 0x98, 0x8d, 0x8f, 0xdd, 0xc1, 0x86, 0xff, 0xb7, 0xdc, 0x90, 0xa6, 0xc0, 0x8f,
0x4d, 0xf4, 0x35, 0xc9, 0x34, 0x02, 0x84, 0x92, 0x36, 0xc3, 0xfa, 0xb4, 0xd2, 0x7c, 0x70, 0x26,
0xc1, 0xd4, 0xdc, 0xb2, 0x60, 0x26, 0x46, 0xde, 0xc9, 0x75, 0x1e, 0x76, 0x3d, 0xba, 0x37, 0xbd,
0xf8, 0xff, 0x94, 0x06, 0xad, 0x9e, 0x53, 0x0e, 0xe5, 0xdb, 0x38, 0x2f, 0x41, 0x30, 0x01, 0xae,
0xb0, 0x6a, 0x53, 0xed, 0x90, 0x27, 0xd8, 0x31, 0x17, 0x97, 0x27, 0xb0, 0x86, 0x5a, 0x89, 0x18,
0xda, 0x3e, 0xdb, 0xeb, 0xcf, 0x9b, 0x14, 0xed, 0x44, 0xce, 0x6c, 0xba, 0xce, 0xd4, 0xbb, 0x1b,
0xdb, 0x7f, 0x14, 0x47, 0xe6, 0xcc, 0x25, 0x4b, 0x33, 0x20, 0x51, 0x51, 0x2b, 0xd7, 0xaf, 0x42,
0x6f, 0xb8, 0xf4, 0x01, 0x37, 0x8c, 0xd2, 0xbf, 0x59, 0x83, 0xca, 0x01, 0xc6, 0x4b, 0x92, 0xec,
0xf0, 0x32, 0xea, 0x15, 0xd1, 0x72, 0x1d, 0x03, 0xf4, 0x82, 0xd7, 0xce, 0x6e, 0x74, 0xfe, 0xf6,
0xd5, 0x5e, 0x70, 0x2f, 0x46, 0x98, 0x0c, 0x82, 0xb5, 0xa8, 0x40, 0x31, 0x90, 0x0b, 0x1c, 0x9e,
0x59, 0xe7, 0xc9, 0x7f, 0xbe, 0xc7, 0xe8, 0xf3, 0x23, 0xa9, 0x7a, 0x7e, 0x36, 0xcc, 0x88, 0xbe,
0x0f, 0x1d, 0x45, 0xb7, 0xff, 0x58, 0x5a, 0xc5, 0x4b, 0xd4, 0x07, 0xb2, 0x2b, 0x41, 0x54, 0xaa,
0xcc, 0x8f, 0x6d, 0x7e, 0xbf, 0x48, 0xe1, 0xd8, 0x14, 0xcc, 0x5e, 0xd2, 0x0f, 0x80, 0x37, 0xe0,
0xa7, 0x97, 0x15, 0xee, 0xf2, 0x9b, 0xe3, 0x28, 0x06, 0xa1, 0xd5, 0x8b, 0xb7, 0xc5, 0xda, 0x76,
0xf5, 0x50, 0xaa, 0x3d, 0x8a, 0x1f, 0xbf, 0xf0, 0xeb, 0x19, 0xcc, 0xb1, 0xa3, 0x13, 0xd5, 0x5c,
0xda, 0x56, 0xc9, 0xec, 0x2e, 0xf2, 0x96, 0x32, 0x38, 0x7f, 0xe8, 0xd7, 0x6e, 0x3c, 0x04, 0x68,
0x04, 0x3e, 0x8f, 0x66, 0x3f, 0x48, 0x60, 0xee, 0x12, 0xbf, 0x2d, 0x5b, 0x0b, 0x74, 0x74, 0xd6,
0xe6, 0x94, 0xf9, 0x1e, 0x6d, 0xbe, 0x11, 0x59, 0x74, 0xa3, 0x92, 0x6f, 0x12, 0xfe, 0xe5, 0xe4,
0x38, 0x77, 0x7c, 0xb6, 0xa9, 0x32, 0xdf, 0x8c, 0xd8, 0xbe, 0xc4, 0xd0, 0x73, 0xb9, 0x31, 0xba,
0x3b, 0xc8, 0x32, 0xb6, 0x8d, 0x9d, 0xd3, 0x00, 0x74, 0x1f, 0xa7, 0xbf, 0x8a, 0xfc, 0x47, 0xed,
0x25, 0x76, 0xf6, 0x93, 0x6b, 0xa4, 0x24, 0x66, 0x3a, 0xab, 0x63, 0x9c, 0x5a, 0xe4, 0xf5, 0x68,
0x34, 0x23, 0xb4, 0x74, 0x2b, 0xf1, 0xc9, 0x78, 0x23, 0x8f, 0x16, 0xcb, 0xe3, 0x9d, 0x65, 0x2d,
0xe3, 0xfd, 0xb8, 0xbe, 0xfc, 0x84, 0x8a, 0xd9, 0x22, 0x22, 0x2e, 0x04, 0xa4, 0x03, 0x7c, 0x07,
0x13, 0xeb, 0x57, 0xa8, 0x1a, 0x23, 0xf0, 0xc7, 0x34, 0x73, 0xfc, 0x64, 0x6c, 0xea, 0x30, 0x6b,
0x4b, 0xcb, 0xc8, 0x86, 0x2f, 0x83, 0x85, 0xdd, 0xfa, 0x9d, 0x4b, 0x7f, 0xa2, 0xc0, 0x87, 0xe8,
0x79, 0x68, 0x33, 0x03, 0xed, 0x5b, 0xdd, 0x3a, 0x06, 0x2b, 0x3c, 0xf5, 0xb3, 0xa2, 0x78, 0xa6,
0x6d, 0x2a, 0x13, 0xf8, 0x3f, 0x44, 0xf8, 0x2d, 0xdf, 0x31, 0x0e, 0xe0, 0x74, 0xab, 0x6a, 0x36,
0x45, 0x97, 0xe8, 0x99, 0xa0, 0x25, 0x5d, 0xc1, 0x64, 0xf3, 0x1c, 0xc5, 0x08, 0x46, 0x85, 0x1d,
0xf9, 0xab, 0x48, 0x19, 0x5d, 0xed, 0x7e, 0xa1, 0xb1, 0xd5, 0x10, 0xbd, 0x7e, 0xe7, 0x4d, 0x73,
0xfa, 0xf3, 0x6b, 0xc3, 0x1e, 0xcf, 0xa2, 0x68, 0x35, 0x90, 0x46, 0xf4, 0xeb, 0x87, 0x9f, 0x92,
0x40, 0x09, 0x43, 0x8b, 0x48, 0x1c, 0x6c, 0xd7, 0x88, 0x9a, 0x00, 0x2e, 0xd5, 0xee, 0x38, 0x2b,
0xc9, 0x19, 0x0d, 0xa6, 0xfc, 0x02, 0x6e, 0x47, 0x95, 0x58, 0xe4, 0x47, 0x56, 0x77, 0xe9, 0xaa,
0x9e, 0x30, 0x50, 0xe2, 0x76, 0x56, 0x94, 0xdf, 0xc8, 0x1f, 0x56, 0xe8, 0x80, 0xb9, 0x6e, 0x71,
0x60, 0xc9, 0x80, 0xdd, 0x98, 0xed, 0xd3, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const unsigned char scr_dh_ffdhe2048_p[256] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, 0x9a,
0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95,
0xa9, 0xe1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9,
0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, 0xae, 0xc4, 0x61, 0x7a,
0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0,
0x85, 0x63, 0x65, 0x55, 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35,
0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, 0xf3, 0xef, 0xe8, 0x72,
0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a,
0xbc, 0x0a, 0xb1, 0x82, 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb,
0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, 0xde, 0x39, 0x4d, 0xf4,
0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70,
0x9e, 0x02, 0xfc, 0xe1, 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61,
0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, 0xee, 0xf2, 0x81, 0x83,
0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05,
0xc5, 0x8e, 0xf1, 0x83, 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa,
0x88, 0x6b, 0x42, 0x38, 0x61, 0x28, 0x5c, 0x97, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const unsigned char scr_dh_ffdhe3072_p[384] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, 0x9a,
0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95,
0xa9, 0xe1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9,
0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, 0xae, 0xc4, 0x61, 0x7a,
0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0,
0x85, 0x63, 0x65, 0x55, 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35,
0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, 0xf3, 0xef, 0xe8, 0x72,
0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a,
0xbc, 0x0a, 0xb1, 0x82, 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb,
0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, 0xde, 0x39, 0x4d, 0xf4,
0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70,
0x9e, 0x02, 0xfc, 0xe1, 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61,
0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, 0xee, 0xf2, 0x81, 0x83,
0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05,
0xc5, 0x8e, 0xf1, 0x83, 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa,
0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, 0x65, 0x19, 0x03, 0x5b,
0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, 0xc9, 0x07,
0x7a, 0xd9, 0x1d, 0x26, 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, 0x86, 0xd9, 0x1c,
0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, 0xbc, 0x43, 0x79, 0x44,
0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, 0x64, 0xf2, 0xe2, 0x1e, 0x71, 0xf5, 0x4b, 0xff,
0x5c, 0xae, 0x82, 0xab, 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d,
0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, 0xbf, 0x9a, 0x42, 0xd5, 0xc4, 0x48, 0x4e,
0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c,
0x25, 0xe4, 0x1d, 0x2b, 0x66, 0xc6, 0x2e, 0x37, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const unsigned char scr_dh_ffdhe4096_p[512] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, 0x9a,
0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95,
0xa9, 0xe1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9,
0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, 0xae, 0xc4, 0x61, 0x7a,
0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0,
0x85, 0x63, 0x65, 0x55, 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35,
0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, 0xf3, 0xef, 0xe8, 0x72,
0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a,
0xbc, 0x0a, 0xb1, 0x82, 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb,
0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, 0xde, 0x39, 0x4d, 0xf4,
0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70,
0x9e, 0x02, 0xfc, 0xe1, 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61,
0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, 0xee, 0xf2, 0x81, 0x83,
0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05,
0xc5, 0x8e, 0xf1, 0x83, 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa,
0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, 0x65, 0x19, 0x03, 0x5b,
0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, 0xc9, 0x07,
0x7a, 0xd9, 0x1d, 0x26, 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, 0x86, 0xd9, 0x1c,
0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, 0xbc, 0x43, 0x79, 0x44,
0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, 0x64, 0xf2, 0xe2, 0x1e, 0x71, 0xf5, 0x4b, 0xff,
0x5c, 0xae, 0x82, 0xab, 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d,
0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, 0xbf, 0x9a, 0x42, 0xd5, 0xc4, 0x48, 0x4e,
0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c,
0x25, 0xe4, 0x1d, 0x2b, 0x66, 0x9e, 0x1e, 0xf1, 0x6e, 0x6f, 0x52, 0xc3, 0x16, 0x4d, 0xf4, 0xfb,
0x79, 0x30, 0xe9, 0xe4, 0xe5, 0x88, 0x57, 0xb6, 0xac, 0x7d, 0x5f, 0x42, 0xd6, 0x9f, 0x6d, 0x18,
0x77, 0x63, 0xcf, 0x1d, 0x55, 0x03, 0x40, 0x04, 0x87, 0xf5, 0x5b, 0xa5, 0x7e, 0x31, 0xcc, 0x7a,
0x71, 0x35, 0xc8, 0x86, 0xef, 0xb4, 0x31, 0x8a, 0xed, 0x6a, 0x1e, 0x01, 0x2d, 0x9e, 0x68, 0x32,
0xa9, 0x07, 0x60, 0x0a, 0x91, 0x81, 0x30, 0xc4, 0x6d, 0xc7, 0x78, 0xf9, 0x71, 0xad, 0x00, 0x38,
0x09, 0x29, 0x99, 0xa3, 0x33, 0xcb, 0x8b, 0x7a, 0x1a, 0x1d, 0xb9, 0x3d, 0x71, 0x40, 0x00, 0x3c,
0x2a, 0x4e, 0xce, 0xa9, 0xf9, 0x8d, 0x0a, 0xcc, 0x0a, 0x82, 0x91, 0xcd, 0xce, 0xc9, 0x7d, 0xcf,
0x8e, 0xc9, 0xb5, 0x5a, 0x7f, 0x88, 0xa4, 0x6b, 0x4d, 0xb5, 0xa8, 0x51, 0xf4, 0x41, 0x82, 0xe1,
0xc6, 0x8a, 0x00, 0x7e, 0x5e, 0x65, 0x5f, 0x6a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const unsigned char scr_dh_ffdhe6144_p[768] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, 0x9a,
0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95,
0xa9, 0xe1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9,
0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, 0xae, 0xc4, 0x61, 0x7a,
0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0,
0x85, 0x63, 0x65, 0x55, 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35,
0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, 0xf3, 0xef, 0xe8, 0x72,
0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a,
0xbc, 0x0a, 0xb1, 0x82, 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb,
0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, 0xde, 0x39, 0x4d, 0xf4,
0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70,
0x9e, 0x02, 0xfc, 0xe1, 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61,
0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, 0xee, 0xf2, 0x81, 0x83,
0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05,
0xc5, 0x8e, 0xf1, 0x83, 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa,
0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, 0x65, 0x19, 0x03, 0x5b,
0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, 0xc9, 0x07,
0x7a, 0xd9, 0x1d, 0x26, 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, 0x86, 0xd9, 0x1c,
0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, 0xbc, 0x43, 0x79, 0x44,
0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, 0x64, 0xf2, 0xe2, 0x1e, 0x71, 0xf5, 0x4b, 0xff,
0x5c, 0xae, 0x82, 0xab, 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d,
0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, 0xbf, 0x9a, 0x42, 0xd5, 0xc4, 0x48, 0x4e,
0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c,
0x25, 0xe4, 0x1d, 0x2b, 0x66, 0x9e, 0x1e, 0xf1, 0x6e, 0x6f, 0x52, 0xc3, 0x16, 0x4d, 0xf4, 0xfb,
0x79, 0x30, 0xe9, 0xe4, 0xe5, 0x88, 0x57, 0xb6, 0xac, 0x7d, 0x5f, 0x42, 0xd6, 0x9f, 0x6d, 0x18,
0x77, 0x63, 0xcf, 0x1d, 0x55, 0x03, 0x40, 0x04, 0x87, 0xf5, 0x5b, 0xa5, 0x7e, 0x31, 0xcc, 0x7a,
0x71, 0x35, 0xc8, 0x86, 0xef, 0xb4, 0x31, 0x8a, 0xed, 0x6a, 0x1e, 0x01, 0x2d, 0x9e, 0x68, 0x32,
0xa9, 0x07, 0x60, 0x0a, 0x91, 0x81, 0x30, 0xc4, 0x6d, 0xc7, 0x78, 0xf9, 0x71, 0xad, 0x00, 0x38,
0x09, 0x29, 0x99, 0xa3, 0x33, 0xcb, 0x8b, 0x7a, 0x1a, 0x1d, 0xb9, 0x3d, 0x71, 0x40, 0x00, 0x3c,
0x2a, 0x4e, 0xce, 0xa9, 0xf9, 0x8d, 0x0a, 0xcc, 0x0a, 0x82, 0x91, 0xcd, 0xce, 0xc9, 0x7d, 0xcf,
0x8e, 0xc9, 0xb5, 0x5a, 0x7f, 0x88, 0xa4, 0x6b, 0x4d, 0xb5, 0xa8, 0x51, 0xf4, 0x41, 0x82, 0xe1,
0xc6, 0x8a, 0x00, 0x7e, 0x5e, 0x0d, 0xd9, 0x02, 0x0b, 0xfd, 0x64, 0xb6, 0x45, 0x03, 0x6c, 0x7a,
0x4e, 0x67, 0x7d, 0x2c, 0x38, 0x53, 0x2a, 0x3a, 0x23, 0xba, 0x44, 0x42, 0xca, 0xf5, 0x3e, 0xa6,
0x3b, 0xb4, 0x54, 0x32, 0x9b, 0x76, 0x24, 0xc8, 0x91, 0x7b, 0xdd, 0x64, 0xb1, 0xc0, 0xfd, 0x4c,
0xb3, 0x8e, 0x8c, 0x33, 0x4c, 0x70, 0x1c, 0x3a, 0xcd, 0xad, 0x06, 0x57, 0xfc, 0xcf, 0xec, 0x71,
0x9b, 0x1f, 0x5c, 0x3e, 0x4e, 0x46, 0x04, 0x1f, 0x38, 0x81, 0x47, 0xfb, 0x4c, 0xfd, 0xb4, 0x77,
0xa5, 0x24, 0x71, 0xf7, 0xa9, 0xa9, 0x69, 0x10, 0xb8, 0x55, 0x32, 0x2e, 0xdb, 0x63, 0x40, 0xd8,
0xa0, 0x0e, 0xf0, 0x92, 0x35, 0x05, 0x11, 0xe3, 0x0a, 0xbe, 0xc1, 0xff, 0xf9, 0xe3, 0xa2, 0x6e,
0x7f, 0xb2, 0x9f, 0x8c, 0x18, 0x30, 0x23, 0xc3, 0x58, 0x7e, 0x38, 0xda, 0x00, 0x77, 0xd9, 0xb4,
0x76, 0x3e, 0x4e, 0x4b, 0x94, 0xb2, 0xbb, 0xc1, 0x94, 0xc6, 0x65, 0x1e, 0x77, 0xca, 0xf9, 0x92,
0xee, 0xaa, 0xc0, 0x23, 0x2a, 0x28, 0x1b, 0xf6, 0xb3, 0xa7, 0x39, 0xc1, 0x22, 0x61, 0x16, 0x82,
0x0a, 0xe8, 0xdb, 0x58, 0x47, 0xa6, 0x7c, 0xbe, 0xf9, 0xc9, 0x09, 0x1b, 0x46, 0x2d, 0x53, 0x8c,
0xd7, 0x2b, 0x03, 0x74, 0x6a, 0xe7, 0x7f, 0x5e, 0x62, 0x29, 0x2c, 0x31, 0x15, 0x62, 0xa8, 0x46,
0x50, 0x5d, 0xc8, 0x2d, 0xb8, 0x54, 0x33, 0x8a, 0xe4, 0x9f, 0x52, 0x35, 0xc9, 0x5b, 0x91, 0x17,
0x8c, 0xcf, 0x2d, 0xd5, 0xca, 0xce, 0xf4, 0x03, 0xec, 0x9d, 0x18, 0x10, 0xc6, 0x27, 0x2b, 0x04,
0x5b, 0x3b, 0x71, 0xf9, 0xdc, 0x6b, 0x80, 0xd6, 0x3f, 0xdd, 0x4a, 0x8e, 0x9a, 0xdb, 0x1e, 0x69,
0x62, 0xa6, 0x95, 0x26, 0xd4, 0x31, 0x61, 0xc1, 0xa4, 0x1d, 0x57, 0x0d, 0x79, 0x38, 0xda, 0xd4,
0xa4, 0x0e, 0x32, 0x9c, 0xd0, 0xe4, 0x0e, 0x65, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const unsigned char scr_dh_ffdhe8192_p[1024] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, 0x9a,
0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95,
0xa9, 0xe1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9,
0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, 0xae, 0xc4, 0x61, 0x7a,
0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0,
0x85, 0x63, 0x65, 0x55, 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35,
0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, 0xf3, 0xef, 0xe8, 0x72,
0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a,
0xbc, 0x0a, 0xb1, 0x82, 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb,
0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, 0xde, 0x39, 0x4d, 0xf4,
0xae, 0x56, 0xed, 0xe7, 0x63, 0x72, 0xbb, 0x19, 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70,
0x9e, 0x02, 0xfc, 0xe1, 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61,
0x91, 0x72, 0xfe, 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, 0xee, 0xf2, 0x81, 0x83,
0xc3, 0xfe, 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05,
0xc5, 0x8e, 0xf1, 0x83, 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa,
0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, 0x65, 0x19, 0x03, 0x5b,
0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, 0xc9, 0x07,
0x7a, 0xd9, 0x1d, 0x26, 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, 0x86, 0xd9, 0x1c,
0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, 0xbc, 0x43, 0x79, 0x44,
0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, 0x64, 0xf2, 0xe2, 0x1e, 0x71, 0xf5, 0x4b, 0xff,
0x5c, 0xae, 0x82, 0xab, 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d,
0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, 0xbf, 0x9a, 0x42, 0xd5, 0xc4, 0x48, 0x4e,
0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c,
0x25, 0xe4, 0x1d, 0x2b, 0x66, 0x9e, 0x1e, 0xf1, 0x6e, 0x6f, 0x52, 0xc3, 0x16, 0x4d, 0xf4, 0xfb,
0x79, 0x30, 0xe9, 0xe4, 0xe5, 0x88, 0x57, 0xb6, 0xac, 0x7d, 0x5f, 0x42, 0xd6, 0x9f, 0x6d, 0x18,
0x77, 0x63, 0xcf, 0x1d, 0x55, 0x03, 0x40, 0x04, 0x87, 0xf5, 0x5b, 0xa5, 0x7e, 0x31, 0xcc, 0x7a,
0x71, 0x35, 0xc8, 0x86, 0xef, 0xb4, 0x31, 0x8a, 0xed, 0x6a, 0x1e, 0x01, 0x2d, 0x9e, 0x68, 0x32,
0xa9, 0x07, 0x60, 0x0a, 0x91, 0x81, 0x30, 0xc4, 0x6d, 0xc7, 0x78, 0xf9, 0x71, 0xad, 0x00, 0x38,
0x09, 0x29, 0x99, 0xa3, 0x33, 0xcb, 0x8b, 0x7a, 0x1a, 0x1d, 0xb9, 0x3d, 0x71, 0x40, 0x00, 0x3c,
0x2a, 0x4e, 0xce, 0xa9, 0xf9, 0x8d, 0x0a, 0xcc, 0x0a, 0x82, 0x91, 0xcd, 0xce, 0xc9, 0x7d, 0xcf,
0x8e, 0xc9, 0xb5, 0x5a, 0x7f, 0x88, 0xa4, 0x6b, 0x4d, 0xb5, 0xa8, 0x51, 0xf4, 0x41, 0x82, 0xe1,
0xc6, 0x8a, 0x00, 0x7e, 0x5e, 0x0d, 0xd9, 0x02, 0x0b, 0xfd, 0x64, 0xb6, 0x45, 0x03, 0x6c, 0x7a,
0x4e, 0x67, 0x7d, 0x2c, 0x38, 0x53, 0x2a, 0x3a, 0x23, 0xba, 0x44, 0x42, 0xca, 0xf5, 0x3e, 0xa6,
0x3b, 0xb4, 0x54, 0x32, 0x9b, 0x76, 0x24, 0xc8, 0x91, 0x7b, 0xdd, 0x64, 0xb1, 0xc0, 0xfd, 0x4c,
0xb3, 0x8e, 0x8c, 0x33, 0x4c, 0x70, 0x1c, 0x3a, 0xcd, 0xad, 0x06, 0x57, 0xfc, 0xcf, 0xec, 0x71,
0x9b, 0x1f, 0x5c, 0x3e, 0x4e, 0x46, 0x04, 0x1f, 0x38, 0x81, 0x47, 0xfb, 0x4c, 0xfd, 0xb4, 0x77,
0xa5, 0x24, 0x71, 0xf7, 0xa9, 0xa9, 0x69, 0x10, 0xb8, 0x55, 0x32, 0x2e, 0xdb, 0x63, 0x40, 0xd8,
0xa0, 0x0e, 0xf0, 0x92, 0x35, 0x05, 0x11, 0xe3, 0x0a, 0xbe, 0xc1, 0xff, 0xf9, 0xe3, 0xa2, 0x6e,
0x7f, 0xb2, 0x9f, 0x8c, 0x18, 0x30, 0x23, 0xc3, 0x58, 0x7e, 0x38, 0xda, 0x00, 0x77, 0xd9, 0xb4,
0x76, 0x3e, 0x4e, 0x4b, 0x94, 0xb2, 0xbb, 0xc1, 0x94, 0xc6, 0x65, 0x1e, 0x77, 0xca, 0xf9, 0x92,
0xee, 0xaa, 0xc0, 0x23, 0x2a, 0x28, 0x1b, 0xf6, 0xb3, 0xa7, 0x39, 0xc1, 0x22, 0x61, 0x16, 0x82,
0x0a, 0xe8, 0xdb, 0x58, 0x47, 0xa6, 0x7c, 0xbe, 0xf9, 0xc9, 0x09, 0x1b, 0x46, 0x2d, 0x53, 0x8c,
0xd7, 0x2b, 0x03, 0x74, 0x6a, 0xe7, 0x7f, 0x5e, 0x62, 0x29, 0x2c, 0x31, 0x15, 0x62, 0xa8, 0x46,
0x50, 0x5d, 0xc8, 0x2d, 0xb8, 0x54, 0x33, 0x8a, 0xe4, 0x9f, 0x52, 0x35, 0xc9, 0x5b, 0x91, 0x17,
0x8c, 0xcf, 0x2d, 0xd5, 0xca, 0xce, 0xf4, 0x03, 0xec, 0x9d, 0x18, 0x10, 0xc6, 0x27, 0x2b, 0x04,
0x5b, 0x3b, 0x71, 0xf9, 0xdc, 0x6b, 0x80, 0xd6, 0x3f, 0xdd, 0x4a, 0x8e, 0x9a, 0xdb, 0x1e, 0x69,
0x62, 0xa6, 0x95, 0x26, 0xd4, 0x31, 0x61, 0xc1, 0xa4, 0x1d, 0x57, 0x0d, 0x79, 0x38, 0xda, 0xd4,
0xa4, 0x0e, 0x32, 0x9c, 0xcf, 0xf4, 0x6a, 0xaa, 0x36, 0xad, 0x00, 0x4c, 0xf6, 0x00, 0xc8, 0x38,
0x1e, 0x42, 0x5a, 0x31, 0xd9, 0x51, 0xae, 0x64, 0xfd, 0xb2, 0x3f, 0xce, 0xc9, 0x50, 0x9d, 0x43,
0x68, 0x7f, 0xeb, 0x69, 0xed, 0xd1, 0xcc, 0x5e, 0x0b, 0x8c, 0xc3, 0xbd, 0xf6, 0x4b, 0x10, 0xef,
0x86, 0xb6, 0x31, 0x42, 0xa3, 0xab, 0x88, 0x29, 0x55, 0x5b, 0x2f, 0x74, 0x7c, 0x93, 0x26, 0x65,
0xcb, 0x2c, 0x0f, 0x1c, 0xc0, 0x1b, 0xd7, 0x02, 0x29, 0x38, 0x88, 0x39, 0xd2, 0xaf, 0x05, 0xe4,
0x54, 0x50, 0x4a, 0xc7, 0x8b, 0x75, 0x82, 0x82, 0x28, 0x46, 0xc0, 0xba, 0x35, 0xc3, 0x5f, 0x5c,
0x59, 0x16, 0x0c, 0xc0, 0x46, 0xfd, 0x82, 0x51, 0x54, 0x1f, 0xc6, 0x8c, 0x9c, 0x86, 0xb0, 0x22,
0xbb, 0x70, 0x99, 0x87, 0x6a, 0x46, 0x0e, 0x74, 0x51, 0xa8, 0xa9, 0x31, 0x09, 0x70, 0x3f, 0xee,
0x1c, 0x21, 0x7e, 0x6c, 0x38, 0x26, 0xe5, 0x2c, 0x51, 0xaa, 0x69, 0x1e, 0x0e, 0x42, 0x3c, 0xfc,
0x99, 0xe9, 0xe3, 0x16, 0x50, 0xc1, 0x21, 0x7b, 0x62, 0x48, 0x16, 0xcd, 0xad, 0x9a, 0x95, 0xf9,
0xd5, 0xb8, 0x01, 0x94, 0x88, 0xd9, 0xc0, 0xa0, 0xa1, 0xfe, 0x30, 0x75, 0xa5, 0x77, 0xe2, 0x31,
0x83, 0xf8, 0x1d, 0x4a, 0x3f, 0x2f, 0xa4, 0x57, 0x1e, 0xfc, 0x8c, 0xe0, 0xba, 0x8a, 0x4f, 0xe8,
0xb6, 0x85, 0x5d, 0xfe, 0x72, 0xb0, 0xa6, 0x6e, 0xde, 0xd2, 0xfb, 0xab, 0xfb, 0xe5, 0x8a, 0x30,
0xfa, 0xfa, 0xbe, 0x1c, 0x5d, 0x71, 0xa8, 0x7e, 0x2f, 0x74, 0x1e, 0xf8, 0xc1, 0xfe, 0x86, 0xfe,
0xa6, 0xbb, 0xfd, 0xe5, 0x30, 0x67, 0x7f, 0x0d, 0x97, 0xd1, 0x1d, 0x49, 0xf7, 0xa8, 0x44, 0x3d,
0x08, 0x22, 0xe5, 0x06, 0xa9, 0xf4, 0x61, 0x4e, 0x01, 0x1e, 0x2a, 0x94, 0x83, 0x8f, 0xf8, 0x8c,
0xd6, 0x8c, 0x8b, 0xb7, 0xc5, 0xc6, 0x42, 0x4c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
static const unsigned char scr_dh_dh_1024_160_p[128] = {
0xb1, 0x0b, 0x8f, 0x96, 0xa0, 0x80, 0xe0, 0x1d, 0xde, 0x92, 0xde, 0x5e, 0xae, 0x5d, 0x54, 0xec,
0x52, 0xc9, 0x9f, 0xbc, 0xfb, 0x06, 0xa3, 0xc6, 0x9a, 0x6a, 0x9d, 0xca, 0x52, 0xd2, 0x3b, 0x61,
0x60, 0x73, 0xe2, 0x86, 0x75, 0xa2, 0x3d, 0x18, 0x98, 0x38, 0xef, 0x1e, 0x2e, 0xe6, 0x52, 0xc0,
0x13, 0xec, 0xb4, 0xae, 0xa9, 0x06, 0x11, 0x23, 0x24, 0x97, 0x5c, 0x3c, 0xd4, 0x9b, 0x83, 0xbf,
0xac, 0xcb, 0xdd, 0x7d, 0x90, 0xc4, 0xbd, 0x70, 0x98, 0x48, 0x8e, 0x9c, 0x21, 0x9a, 0x73, 0x72,
0x4e, 0xff, 0xd6, 0xfa, 0xe5, 0x64, 0x47, 0x38, 0xfa, 0xa3, 0x1a, 0x4f, 0xf5, 0x5b, 0xcc, 0xc0,
0xa1, 0x51, 0xaf, 0x5f, 0x0d, 0xc8, 0xb4, 0xbd, 0x45, 0xbf, 0x37, 0xdf, 0x36, 0x5c, 0x1a, 0x65,
0xe6, 0x8c, 0xfd, 0xa7, 0x6d, 0x4d, 0xa7, 0x08, 0xdf, 0x1f, 0xb2, 0xbc, 0x2e, 0x4a, 0x43, 0x71,
};
static const unsigned char scr_dh_dh_1024_160_g[128] = {
0xa4, 0xd1, 0xcb, 0xd5, 0xc3, 0xfd, 0x34, 0x12, 0x67, 0x65, 0xa4, 0x42, 0xef, 0xb9, 0x99, 0x05,
0xf8, 0x10, 0x4d, 0xd2, 0x58, 0xac, 0x50, 0x7f, 0xd6, 0x40, 0x6c, 0xff, 0x14, 0x26, 0x6d, 0x31,
0x26, 0x6f, 0xea, 0x1e, 0x5c, 0x41, 0x56, 0x4b, 0x77, 0x7e, 0x69, 0x0f, 0x55, 0x04, 0xf2, 0x13,
0x16, 0x02, 0x17, 0xb4, 0xb0, 0x1b, 0x88, 0x6a, 0x5e, 0x91, 0x54, 0x7f, 0x9e, 0x27, 0x49, 0xf4,
0xd7, 0xfb, 0xd7, 0xd3, 0xb9, 0xa9, 0x2e, 0xe1, 0x90, 0x9d, 0x0d, 0x22, 0x63, 0xf8, 0x0a, 0x76,
0xa6, 0xa2, 0x4c, 0x08, 0x7a, 0x09, 0x1f, 0x53, 0x1d, 0xbf, 0x0a, 0x01, 0x69, 0xb6, 0xa2, 0x8a,
0xd6, 0x62, 0xa4, 0xd1, 0x8e, 0x73, 0xaf, 0xa3, 0x2d, 0x77, 0x9d, 0x59, 0x18, 0xd0, 0x8b, 0xc8,
0x85, 0x8f, 0x4d, 0xce, 0xf9, 0x7c, 0x2a, 0x24, 0x85, 0x5e, 0x6e, 0xeb, 0x22, 0xb3, 0xb2, 0xe5,
};
static const unsigned char scr_dh_dh_1024_160_q[20] = {
0xf5, 0x18, 0xaa, 0x87, 0x81, 0xa8, 0xdf, 0x27, 0x8a, 0xba, 0x4e, 0x7d, 0x64, 0xb7, 0xcb, 0x9d,
0x49, 0x46, 0x23, 0x53,
};
static const unsigned char scr_dh_dh_2048_224_p[256] = {
0xad, 0x10, 0x7e, 0x1e, 0x91, 0x23, 0xa9, 0xd0, 0xd6, 0x60, 0xfa, 0xa7, 0x95, 0x59, 0xc5, 0x1f,
0xa2, 0x0d, 0x64, 0xe5, 0x68, 0x3b, 0x9f, 0xd1, 0xb5, 0x4b, 0x15, 0x97, 0xb6, 0x1d, 0x0a, 0x75,
0xe6, 0xfa, 0x14, 0x1d, 0xf9, 0x5a, 0x56, 0xdb, 0xaf, 0x9a, 0x3c, 0x40, 0x7b, 0xa1, 0xdf, 0x15,
0xeb, 0x3d, 0x68, 0x8a, 0x30, 0x9c, 0x18, 0x0e, 0x1d, 0xe6, 0xb8, 0x5a, 0x12, 0x74, 0xa0, 0xa6,
0x6d, 0x3f, 0x81, 0x52, 0xad, 0x6a, 0xc2, 0x12, 0x90, 0x37, 0xc9, 0xed, 0xef, 0xda, 0x4d, 0xf8,
0xd9, 0x1e, 0x8f, 0xef, 0x55, 0xb7, 0x39, 0x4b, 0x7a, 0xd5, 0xb7, 0xd0, 0xb6, 0xc1, 0x22, 0x07,
0xc9, 0xf9, 0x8d, 0x11, 0xed, 0x34, 0xdb, 0xf6, 0xc6, 0xba, 0x0b, 0x2c, 0x8b, 0xbc, 0x27, 0xbe,
0x6a, 0x00, 0xe0, 0xa0, 0xb9, 0xc4, 0x97, 0x08, 0xb3, 0xbf, 0x8a, 0x31, 0x70, 0x91, 0x88, 0x36,
0x81, 0x28, 0x61, 0x30, 0xbc, 0x89, 0x85, 0xdb, 0x16, 0x02, 0xe7, 0x14, 0x41, 0x5d, 0x93, 0x30,
0x27, 0x82, 0x73, 0xc7, 0xde, 0x31, 0xef, 0xdc, 0x73, 0x10, 0xf7, 0x12, 0x1f, 0xd5, 0xa0, 0x74,
0x15, 0x98, 0x7d, 0x9a, 0xdc, 0x0a, 0x48, 0x6d, 0xcd, 0xf9, 0x3a, 0xcc, 0x44, 0x32, 0x83, 0x87,
0x31, 0x5d, 0x75, 0xe1, 0x98, 0xc6, 0x41, 0xa4, 0x80, 0xcd, 0x86, 0xa1, 0xb9, 0xe5, 0x87, 0xe8,
0xbe, 0x60, 0xe6, 0x9c, 0xc9, 0x28, 0xb2, 0xb9, 0xc5, 0x21, 0x72, 0xe4, 0x13, 0x04, 0x2e, 0x9b,
0x23, 0xf1, 0x0b, 0x0e, 0x16, 0xe7, 0x97, 0x63, 0xc9, 0xb5, 0x3d, 0xcf, 0x4b, 0xa8, 0x0a, 0x29,
0xe3, 0xfb, 0x73, 0xc1, 0x6b, 0x8e, 0x75, 0xb9, 0x7e, 0xf3, 0x63, 0xe2, 0xff, 0xa3, 0x1f, 0x71,
0xcf, 0x9d, 0xe5, 0x38, 0x4e, 0x71, 0xb8, 0x1c, 0x0a, 0xc4, 0xdf, 0xfe, 0x0c, 0x10, 0xe6, 0x4f,
};
static const unsigned char scr_dh_dh_2048_224_g[256] = {
0xac, 0x40, 0x32, 0xef, 0x4f, 0x2d, 0x9a, 0xe3, 0x9d, 0xf3, 0x0b, 0x5c, 0x8f, 0xfd, 0xac, 0x50,
0x6c, 0xde, 0xbe, 0x7b, 0x89, 0x99, 0x8c, 0xaf, 0x74, 0x86, 0x6a, 0x08, 0xcf, 0xe4, 0xff, 0xe3,
0xa6, 0x82, 0x4a, 0x4e, 0x10, 0xb9, 0xa6, 0xf0, 0xdd, 0x92, 0x1f, 0x01, 0xa7, 0x0c, 0x4a, 0xfa,
0xab, 0x73, 0x9d, 0x77, 0x00, 0xc2, 0x9f, 0x52, 0xc5, 0x7d, 0xb1, 0x7c, 0x62, 0x0a, 0x86, 0x52,
0xbe, 0x5e, 0x90, 0x01, 0xa8, 0xd6, 0x6a, 0xd7, 0xc1, 0x76, 0x69, 0x10, 0x19, 0x99, 0x02, 0x4a,
0xf4, 0xd0, 0x27, 0x27, 0x5a, 0xc1, 0x34, 0x8b, 0xb8, 0xa7, 0x62, 0xd0, 0x52, 0x1b, 0xc9, 0x8a,
0xe2, 0x47, 0x15, 0x04, 0x22, 0xea, 0x1e, 0xd4, 0x09, 0x93, 0x9d, 0x54, 0xda, 0x74, 0x60, 0xcd,
0xb5, 0xf6, 0xc6, 0xb2, 0x50, 0x71, 0x7c, 0xbe, 0xf1, 0x80, 0xeb, 0x34, 0x11, 0x8e, 0x98, 0xd1,
0x19, 0x52, 0x9a, 0x45, 0xd6, 0xf8, 0x34, 0x56, 0x6e, 0x30, 0x25, 0xe3, 0x16, 0xa3, 0x30, 0xef,
0xbb, 0x77, 0xa8, 0x6f, 0x0c, 0x1a, 0xb1, 0x5b, 0x05, 0x1a, 0xe3, 0xd4, 0x28, 0xc8, 0xf8, 0xac,
0xb7, 0x0a, 0x81, 0x37, 0x15, 0x0b, 0x8e, 0xeb, 0x10, 0xe1, 0x83, 0xed, 0xd1, 0x99, 0x63, 0xdd,
0xd9, 0xe2, 0x63, 0xe4, 0x77, 0x05, 0x89, 0xef, 0x6a, 0xa2, 0x1e, 0x7f, 0x5f, 0x2f, 0xf3, 0x81,
0xb5, 0x39, 0xcc, 0xe3, 0x40, 0x9d, 0x13, 0xcd, 0x56, 0x6a, 0xfb, 0xb4, 0x8d, 0x6c, 0x01, 0x91,
0x81, 0xe1, 0xbc, 0xfe, 0x94, 0xb3, 0x02, 0x69, 0xed, 0xfe, 0x72, 0xfe, 0x9b, 0x6a, 0xa4, 0xbd,
0x7b, 0x5a, 0x0f, 0x1c, 0x71, 0xcf, 0xff, 0x4c, 0x19, 0xc4, 0x18, 0xe1, 0xf6, 0xec, 0x01, 0x79,
0x81, 0xbc, 0x08, 0x7f, 0x2a, 0x70, 0x65, 0xb3, 0x84, 0xb8, 0x90, 0xd3, 0x19, 0x1f, 0x2b, 0xfa,
};
static const unsigned char scr_dh_dh_2048_224_q[28] = {
0x80, 0x1c, 0x0d, 0x34, 0xc5, 0x8d, 0x93, 0xfe, 0x99, 0x71, 0x77, 0x10, 0x1f, 0x80, 0x53, 0x5a,
0x47, 0x38, 0xce, 0xbc, 0xbf, 0x38, 0x9a, 0x99, 0xb3, 0x63, 0x71, 0xeb,
};
static const unsigned char scr_dh_dh_2048_256_p[256] = {
0x87, 0xa8, 0xe6, 0x1d, 0xb4, 0xb6, 0x66, 0x3c, 0xff, 0xbb, 0xd1, 0x9c, 0x65, 0x19, 0x59, 0x99,
0x8c, 0xee, 0xf6, 0x08, 0x66, 0x0d, 0xd0, 0xf2, 0x5d, 0x2c, 0xee, 0xd4, 0x43, 0x5e, 0x3b, 0x00,
0xe0, 0x0d, 0xf8, 0xf1, 0xd6, 0x19, 0x57, 0xd4, 0xfa, 0xf7, 0xdf, 0x45, 0x61, 0xb2, 0xaa, 0x30,
0x16, 0xc3, 0xd9, 0x11, 0x34, 0x09, 0x6f, 0xaa, 0x3b, 0xf4, 0x29, 0x6d, 0x83, 0x0e, 0x9a, 0x7c,
0x20, 0x9e, 0x0c, 0x64, 0x97, 0x51, 0x7a, 0xbd, 0x5a, 0x8a, 0x9d, 0x30, 0x6b, 0xcf, 0x67, 0xed,
0x91, 0xf9, 0xe6, 0x72, 0x5b, 0x47, 0x58, 0xc0, 0x22, 0xe0, 0xb1, 0xef, 0x42, 0x75, 0xbf, 0x7b,
0x6c, 0x5b, 0xfc, 0x11, 0xd4, 0x5f, 0x90, 0x88, 0xb9, 0x41, 0xf5, 0x4e, 0xb1, 0xe5, 0x9b, 0xb8,
0xbc, 0x39, 0xa0, 0xbf, 0x12, 0x30, 0x7f, 0x5c, 0x4f, 0xdb, 0x70, 0xc5, 0x81, 0xb2, 0x3f, 0x76,
0xb6, 0x3a, 0xca, 0xe1, 0xca, 0xa6, 0xb7, 0x90, 0x2d, 0x52, 0x52, 0x67, 0x35, 0x48, 0x8a, 0x0e,
0xf1, 0x3c, 0x6d, 0x9a, 0x51, 0xbf, 0xa4, 0xab, 0x3a, 0xd8, 0x34, 0x77, 0x96, 0x52, 0x4d, 0x8e,
0xf6, 0xa1, 0x67, 0xb5, 0xa4, 0x18, 0x25, 0xd9, 0x67, 0xe1, 0x44, 0xe5, 0x14, 0x05, 0x64, 0x25,
0x1c, 0xca, 0xcb, 0x83, 0xe6, 0xb4, 0x86, 0xf6, 0xb3, 0xca, 0x3f, 0x79, 0x71, 0x50, 0x60, 0x26,
0xc0, 0xb8, 0x57, 0xf6, 0x89, 0x96, 0x28, 0x56, 0xde, 0xd4, 0x01, 0x0a, 0xbd, 0x0b, 0xe6, 0x21,
0xc3, 0xa3, 0x96, 0x0a, 0x54, 0xe7, 0x10, 0xc3, 0x75, 0xf2, 0x63, 0x75, 0xd7, 0x01, 0x41, 0x03,
0xa4, 0xb5, 0x43, 0x30, 0xc1, 0x98, 0xaf, 0x12, 0x61, 0x16, 0xd2, 0x27, 0x6e, 0x11, 0x71, 0x5f,
0x69, 0x38, 0x77, 0xfa, 0xd7, 0xef, 0x09, 0xca, 0xdb, 0x09, 0x4a, 0xe9, 0x1e, 0x1a, 0x15, 0x97,
};
static const unsigned char scr_dh_dh_2048_256_g[256] = {
0x3f, 0xb3, 0x2c, 0x9b, 0x73, 0x13, 0x4d, 0x0b, 0x2e, 0x77, 0x50, 0x66, 0x60, 0xed, 0xbd, 0x48,
0x4c, 0xa7, 0xb1, 0x8f, 0x21, 0xef, 0x20, 0x54, 0x07, 0xf4, 0x79, 0x3a, 0x1a, 0x0b, 0xa1, 0x25,
0x10, 0xdb, 0xc1, 0x50, 0x77, 0xbe, 0x46, 0x3f, 0xff, 0x4f, 0xed, 0x4a, 0xac, 0x0b, 0xb5, 0x55,
0xbe, 0x3a, 0x6c, 0x1b, 0x0c, 0x6b, 0x47, 0xb1, 0xbc, 0x37, 0x73, 0xbf, 0x7e, 0x8c, 0x6f, 0x62,
0x90, 0x12, 0x28, 0xf8, 0xc2, 0x8c, 0xbb, 0x18, 0xa5, 0x5a, 0xe3, 0x13, 0x41, 0x00, 0x0a, 0x65,
0x01, 0x96, 0xf9, 0x31, 0xc7, 0x7a, 0x57, 0xf2, 0xdd, 0xf4, 0x63, 0xe5, 0xe9, 0xec, 0x14, 0x4b,
0x77, 0x7d, 0xe6, 0x2a, 0xaa, 0xb8, 0xa8, 0x62, 0x8a, 0xc3, 0x76, 0xd2, 0x82, 0xd6, 0xed, 0x38,
0x64, 0xe6, 0x79, 0x82, 0x42, 0x8e, 0xbc, 0x83, 0x1d, 0x14, 0x34, 0x8f, 0x6f, 0x2f, 0x91, 0x93,
0xb5, 0x04, 0x5a, 0xf2, 0x76, 0x71, 0x64, 0xe1, 0xdf, 0xc9, 0x67, 0xc1, 0xfb, 0x3f, 0x2e, 0x55,
0xa4, 0xbd, 0x1b, 0xff, 0xe8, 0x3b, 0x9c, 0x80, 0xd0, 0x52, 0xb9, 0x85, 0xd1, 0x82, 0xea, 0x0a,
0xdb, 0x2a, 0x3b, 0x73, 0x13, 0xd3, 0xfe, 0x14, 0xc8, 0x48, 0x4b, 0x1e, 0x05, 0x25, 0x88, 0xb9,
0xb7, 0xd2, 0xbb, 0xd2, 0xdf, 0x01, 0x61, 0x99, 0xec, 0xd0, 0x6e, 0x15, 0x57, 0xcd, 0x09, 0x15,
0xb3, 0x35, 0x3b, 0xbb, 0x64, 0xe0, 0xec, 0x37, 0x7f, 0xd0, 0x28, 0x37, 0x0d, 0xf9, 0x2b, 0x52,
0xc7, 0x89, 0x14, 0x28, 0xcd, 0xc6, 0x7e, 0xb6, 0x18, 0x4b, 0x52, 0x3d, 0x1d, 0xb2, 0x46, 0xc3,
0x2f, 0x63, 0x07, 0x84, 0x90, 0xf0, 0x0e, 0xf8, 0xd6, 0x47, 0xd1, 0x48, 0xd4, 0x79, 0x54, 0x51,
0x5e, 0x23, 0x27, 0xcf, 0xef, 0x98, 0xc5, 0x82, 0x66, 0x4b, 0x4c, 0x0f, 0x6c, 0xc4, 0x16, 0x59,
};
static const unsigned char scr_dh_dh_2048_256_q[32] = {
0x8c, 0xf8, 0x36, 0x42, 0xa7, 0x09, 0xa0, 0x97, 0xb4, 0x47, 0x99, 0x76, 0x40, 0x12, 0x9d, 0xa2,
0x99, 0xb1, 0xa4, 0x7d, 0x1e, 0xb3, 0x75, 0x0b, 0xa3, 0x08, 0xb0, 0xfe, 0x64, 0xf5, 0xfb, 0xd3,
};
#endif
+2
View File
@@ -155,6 +155,8 @@ typedef enum {
X(DATE, 30) /* JavaScript Date with stable native identity */ \
X(DECIPHER, 46) /* node:crypto Decipheriv (scr_cipher.c) */ \
X(DGRAM_SOCKET, 62) /* dgram.Socket (scr_dgram.c) */ \
X(DIFFIE_HELLMAN, 65) /* node:crypto DiffieHellman (scr_dh.c) */ \
X(DIFFIE_HELLMAN_GROUP, 66) /* node:crypto DiffieHellmanGroup (scr_dh.c) */ \
X(DIR, 44) /* fs.Dir (scr_lib.c) */ \
X(DISPOSABLE_STACK, 49) /* DisposableStack (scr_symbol.c) */ \
X(ECDH, 64) /* node:crypto ECDH (scr_ecdh.c) */ \
+19 -173
View File
@@ -21,6 +21,7 @@
#include "mbedtls/ecp.h"
#include "mbedtls/platform_util.h"
#include "scr_crypto_args.h"
#include "scr_ecdh_names.h"
typedef struct {
@@ -73,6 +74,9 @@ static int se_random(void *state, unsigned char *out, size_t len) {
return 0;
}
/* The value the SC2020 error for an unlowered encoding or format names. */
#define SE_SUBJECT "An ECDH encoding or format"
/* ── errors ───────────────────────────────────────────────────────────── */
static void se_throw(int kind, const char *code, const char *message) {
@@ -83,51 +87,6 @@ static void se_operation_failed(const char *message) {
se_throw(SCR_ERR_ERROR, "ERR_CRYPTO_OPERATION_FAILED", message);
}
/* An object's toString the program defined, as an own or inherited
* function property. */
static bool se_custom_to_string(ScrDyn *value) {
if (value->kind != SCR_DYN_OBJ && value->kind != SCR_DYN_TYPED_REF) return false;
ScrDyn *member = scr_dyn_obj_read(value, "toString", 8);
bool custom = member && member->kind == SCR_DYN_FUNC;
scr_dyn_release(member);
return custom;
}
/* Whether value is a class instance whose class defines toString. */
static bool se_class_to_string(const ScrDyn *value) {
ScrStr *name = scr_str_new("toString", 8);
bool method = scr_dyn_typed_ref_class_has(value, name);
scr_str_release(name);
return method;
}
/* `prefix` and the value as util.format's %s renders it: strings and
* objects with a program-defined toString as String(value), numbers as
* util.inspect does, other values inspected at depth 0. Functions and
* class instances that define toString have no lowering. */
static void se_throw_formatted(const char *code, const char *prefix, const ScrDyn *value) {
ScrDyn *v = (ScrDyn *)value;
if (v->kind == SCR_DYN_FUNC || se_class_to_string(v)) {
static const char message[] = "An ECDH encoding or format that is a function or an instance of a class "
"defining toString has no lowering; pass the name as a string";
scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020");
return;
}
ScrStr *text;
if (v->kind == SCR_DYN_STR || se_custom_to_string(v)) text = scr_dyn_string_coerce_js(v);
else if (v->kind == SCR_DYN_NUM) text = scr_insp_f64(v->v.num);
else text = scr_insp_dyn_s(v, 0);
if (!text) return;
ScrJsonBuf b;
scr_jb_init(&b);
scr_jb_puts(&b, prefix);
scr_jb_put_str(&b, text);
scr_str_release(text);
ScrStr *message = scr_jb_finish(&b);
scr_throw_error_msg_code(SCR_ERR_TYPE, message->data, message->len, code);
scr_str_release(message);
}
/* ── names and encodings ──────────────────────────────────────────────── */
static int se_name_cmp(const void *key, const void *entry) {
@@ -198,129 +157,16 @@ static bool se_load_group(const ScrStr *name, mbedtls_ecp_group *grp, const char
return false;
}
static bool se_ascii_eq_ci(const char *a, size_t a_len, const char *b) {
size_t b_len = strlen(b);
if (a_len != b_len) return false;
for (size_t i = 0; i < a_len; i++) {
char x = a[i];
if (x >= 'A' && x <= 'Z') x = (char)(x - 'A' + 'a');
if (x != b[i]) return false;
}
return true;
}
static bool se_str_is(const ScrStr *text, const char *literal) {
size_t len = strlen(literal);
return text->len == len && memcmp(text->data, literal, len) == 0;
}
/* Node's normalizeEncoding: the canonical name, or NULL. */
static const char *se_normalize_encoding(const ScrStr *name) {
static const struct { const char *from; const char *to; } map[] = {
{"utf8", "utf8"}, {"utf-8", "utf8"}, {"hex", "hex"},
{"base64", "base64"}, {"base64url", "base64url"}, {"latin1", "latin1"},
{"binary", "latin1"}, {"ascii", "ascii"}, {"utf16le", "utf16le"},
{"utf-16le", "utf16le"}, {"ucs2", "utf16le"}, {"ucs-2", "utf16le"},
};
for (size_t i = 0; i < sizeof map / sizeof map[0]; i++)
if (se_ascii_eq_ci(name->data, name->len, map[i].from)) return map[i].to;
return NULL;
}
/* The value a typed-ref box holds when it is a string, view, ArrayBuffer
* or native handle (+1). Other values are retained as passed, so argument
* errors describe the original value. NULL after throwing. */
static ScrDyn *se_unbox(ScrDyn *value) {
if (value->kind != SCR_DYN_TYPED_REF) return scr_dyn_retain(value);
ScrDyn *view = scr_dyn_typed_ref_materialize(value);
if (!view) return NULL;
if (view->kind == SCR_DYN_STR || view->kind == SCR_DYN_BYTES || view->kind == SCR_DYN_HANDLE ||
scr_buffer_storage_is(view))
return view;
scr_dyn_release(view);
return scr_dyn_retain(value);
}
/* getArrayBufferOrView(key, 'key', encoding): a string is Buffer.from(key,
* encoding) with 'buffer' read as utf8; views and ArrayBuffers are their
* bytes. +1 or NULL after throwing. */
static ScrBytes *se_key_bytes(const ScrDyn *key, const ScrDyn *encoding) {
if (key->kind == SCR_DYN_STR) {
/* Buffer.from(string, encoding): an encoding that is not a non-empty
* string reads as utf8. */
const char *name = "utf8";
if (encoding->kind == SCR_DYN_STR && encoding->v.str->len > 0 && !se_str_is(encoding->v.str, "buffer")) {
name = se_normalize_encoding(encoding->v.str);
if (!name) {
se_throw_formatted("ERR_UNKNOWN_ENCODING", "Unknown encoding: ", encoding);
return NULL;
}
}
ScrStr *canonical = scr_str_new(name, strlen(name));
ScrBytes *bytes = scr_bytes_from_str(key->v.str, canonical);
scr_str_release(canonical);
return bytes;
}
if (key->kind == SCR_DYN_BYTES || scr_buffer_storage_is(key)) return scr_bytes_buffer_source(key);
scr_dyn_arg_type_fail("key", "of type string or an instance of ArrayBuffer, Buffer, TypedArray, or DataView", key);
return NULL;
}
/* encode(buffer, encoding): the Buffer, or buffer.toString(encoding) for
* a truthy encoding other than 'buffer'. Consumes bytes. */
static ScrDyn *se_encode(ScrBytes *bytes, const ScrDyn *encoding) {
if (!scr_dyn_truthy(encoding) || (encoding->kind == SCR_DYN_STR && se_str_is(encoding->v.str, "buffer"))) {
ScrDyn *result = scr_dyn_new_buffer(bytes);
scr_bytes_release(bytes);
return result;
}
/* toString answers "" for no bytes before it reads the encoding. */
ScrStr *text = NULL;
if (bytes->len == 0) {
text = scr_str_new("", 0);
} else {
/* getEncodingOps reads `encoding + ''`. */
ScrStr *name = encoding->kind == SCR_DYN_STR ? scr_str_retain(encoding->v.str) : NULL;
if (!name) {
if (encoding->kind == SCR_DYN_FUNC || se_class_to_string(encoding)) {
se_throw_formatted("ERR_UNKNOWN_ENCODING", "Unknown encoding: ", encoding);
scr_bytes_release(bytes);
return NULL;
}
name = scr_dyn_string_coerce_js(encoding);
if (!name) {
scr_bytes_release(bytes);
return NULL;
}
}
const char *canonical = se_normalize_encoding(name);
scr_str_release(name);
if (!canonical) {
se_throw_formatted("ERR_UNKNOWN_ENCODING", "Unknown encoding: ", encoding);
scr_bytes_release(bytes);
return NULL;
}
ScrStr *canonical_text = scr_str_new(canonical, strlen(canonical));
text = scr_bytes_to_str(bytes, canonical_text);
scr_str_release(canonical_text);
}
scr_bytes_release(bytes);
if (!text) return NULL;
ScrDyn *result = scr_dyn_new_str(text);
scr_str_release(text);
return result;
}
/* getFormat: a falsy format is uncompressed; other values must be
* 'compressed', 'hybrid' or 'uncompressed'. 0 after throwing. */
static int se_format(const ScrDyn *format) {
if (!scr_dyn_truthy(format)) return SE_UNCOMPRESSED;
if (format->kind == SCR_DYN_STR) {
if (se_str_is(format->v.str, "compressed")) return SE_COMPRESSED;
if (se_str_is(format->v.str, "hybrid")) return SE_HYBRID;
if (se_str_is(format->v.str, "uncompressed")) return SE_UNCOMPRESSED;
if (ca_str_is(format->v.str, "compressed")) return SE_COMPRESSED;
if (ca_str_is(format->v.str, "hybrid")) return SE_HYBRID;
if (ca_str_is(format->v.str, "uncompressed")) return SE_UNCOMPRESSED;
}
se_throw_formatted("ERR_CRYPTO_ECDH_INVALID_FORMAT", "Invalid ECDH format: ", format);
ca_throw_formatted(SE_SUBJECT, "ERR_CRYPTO_ECDH_INVALID_FORMAT", "Invalid ECDH format: ", format);
return 0;
}
@@ -516,7 +362,7 @@ static ScrDyn *se_new(const ScrDyn *curve) {
}
ScrDyn *scr_crypto_ecdh_new(ScrDyn *curve) {
ScrDyn *unboxed = se_unbox(curve);
ScrDyn *unboxed = ca_unbox(curve);
if (!unboxed) return NULL;
ScrDyn *result = se_new(unboxed);
scr_dyn_release(unboxed);
@@ -530,7 +376,7 @@ static ScrDyn *se_convert_key(const ScrDyn *key, const ScrDyn *curve, const ScrD
scr_dyn_arg_type_fail("curve", "of type string", curve);
return NULL;
}
ScrBytes *bytes = se_key_bytes(key, in_enc);
ScrBytes *bytes = ca_key_bytes(SE_SUBJECT, key, in_enc);
if (!bytes) return NULL;
int form = se_format(format);
if (!form) {
@@ -557,7 +403,7 @@ static ScrDyn *se_convert_key(const ScrDyn *key, const ScrDyn *curve, const ScrD
} else {
ScrBytes *out = se_write_point(&grp, &pt, form);
if (!out) se_operation_failed("Failed to convert EC_POINT to Buffer");
else result = se_encode(out, out_enc);
else result = ca_encode(SE_SUBJECT, out, out_enc);
}
}
mbedtls_ecp_point_free(&pt);
@@ -571,7 +417,7 @@ ScrDyn *scr_crypto_ecdh_convert_key(ScrDyn *key, ScrDyn *curve, ScrDyn *in_enc,
ScrDyn *unboxed[5] = {NULL, NULL, NULL, NULL, NULL};
ScrDyn *result = NULL;
for (size_t i = 0; i < 5; i++)
if (!(unboxed[i] = se_unbox(args[i]))) goto done;
if (!(unboxed[i] = ca_unbox(args[i]))) goto done;
result = se_convert_key(unboxed[0], unboxed[1], unboxed[2], unboxed[3], unboxed[4]);
done:
for (size_t i = 0; i < 5; i++) scr_dyn_release(unboxed[i]);
@@ -597,7 +443,7 @@ static ScrDyn *se_get_public_key(ScEcdh *e, const ScrDyn *encoding, const ScrDyn
se_operation_failed("Failed to get ECDH public key");
return NULL;
}
return se_encode(out, encoding);
return ca_encode(SE_SUBJECT, out, encoding);
}
static ScrDyn *se_generate_keys(ScEcdh *e, const ScrDyn *encoding, const ScrDyn *format) {
@@ -628,12 +474,12 @@ static ScrDyn *se_get_private_key(ScEcdh *e, const ScrDyn *encoding) {
se_operation_failed("Failed to get ECDH private key");
return NULL;
}
return se_encode(out, encoding);
return ca_encode(SE_SUBJECT, out, encoding);
}
/* setPrivateKey(key, encoding): 1 <= d < n, and the public key d·G. */
static ScrDyn *se_set_private_key(ScEcdh *e, ScrDyn *self, const ScrDyn *key, const ScrDyn *encoding) {
ScrBytes *bytes = se_key_bytes(key, encoding);
ScrBytes *bytes = ca_key_bytes(SE_SUBJECT, key, encoding);
if (!bytes) return NULL;
mbedtls_mpi d;
mbedtls_ecp_point q;
@@ -680,7 +526,7 @@ static void se_dep0031(void) {
static ScrDyn *se_set_public_key(ScEcdh *e, ScrDyn *self, const ScrDyn *key, const ScrDyn *encoding) {
se_dep0031();
ScrBytes *bytes = se_key_bytes(key, encoding);
ScrBytes *bytes = ca_key_bytes(SE_SUBJECT, key, encoding);
if (!bytes) return NULL;
mbedtls_ecp_point q;
mbedtls_ecp_point_init(&q);
@@ -716,7 +562,7 @@ static bool se_pair_valid(ScEcdh *e) {
/* computeSecret(key, inputEncoding, outputEncoding): the x coordinate of
* d·P, padded to the field size as ECDH_compute_key writes it. */
static ScrDyn *se_compute_secret(ScEcdh *e, const ScrDyn *key, const ScrDyn *in_enc, const ScrDyn *out_enc) {
ScrBytes *bytes = se_key_bytes(key, in_enc);
ScrBytes *bytes = ca_key_bytes(SE_SUBJECT, key, in_enc);
if (!bytes) return NULL;
ScrDyn *result = NULL;
mbedtls_ecp_point pub;
@@ -737,7 +583,7 @@ static ScrDyn *se_compute_secret(ScEcdh *e, const ScrDyn *key, const ScrDyn *in_
scr_bytes_release(out);
se_operation_failed("Failed to compute ECDH key");
} else {
result = se_encode(out, out_enc);
result = ca_encode(SE_SUBJECT, out, out_enc);
}
}
mbedtls_mpi_free(&z);
@@ -776,7 +622,7 @@ static ScrDyn *se_invoke(void *h, ScrDyn *self, const char *method, ScrDyn *cons
size_t count = argc < 3 ? argc : 3;
ScrDyn *result = NULL;
for (size_t i = 0; i < count; i++)
if (!(unboxed[i] = se_unbox(args[i]))) goto done;
if (!(unboxed[i] = ca_unbox(args[i]))) goto done;
result = se_dispatch(h, self, method, unboxed, count, what);
done:
for (size_t i = 0; i < count; i++) scr_dyn_release(unboxed[i]);
+85
View File
@@ -0,0 +1,85 @@
import { execFile } from "node:child_process";
import { mkdir } from "node:fs/promises";
import { join } from "node:path";
import { promisify } from "node:util";
import { beforeAll, expect, test } from "vitest";
const execFileAsync = promisify(execFile);
const testDir = import.meta.dirname;
const bin = join(testDir, "build", "test_dh");
const mbedtls = join(testDir, "../vendor/mbedtls");
const runtimeSources = [
"scr_shared.c",
"scr_bytes.c",
"scr_bytes.test.c",
"scr_bytes_io.c",
"scr_fs_cp.c",
"scr_zlib.c",
"scr_lib.c",
"scr_hash.c",
"scr_string.c",
"scr_array.c",
"scr_map.c",
"scr_exception.c",
"scr_error.c",
"scr_number.c",
"scr_console.c",
"scr_closure.c",
"scr_ffi.c",
"scr_object.c",
"scr_union.c",
"scr_cycle.c",
"scr_alloc.c",
"scr_json.c",
"scr_inspect.c",
"scr_bigint.c",
"scr_async.c",
"scr_async_dyn.c",
"scr_child.c",
"scr_path.c",
"scr_url.c",
"scr_url_params.c",
];
// The bignum modules scr_dh.c uses.
const mbedtlsSources = ["bignum.c", "bignum_core.c", "constant_time.c", "platform_util.c"];
// Compiled once with ASan, UBSan and the RC audit. test_dh.c includes
// scr_dh.c and checks the primality tests' Montgomery exponentiation
// against mbedTLS's, the primality test on primes, Carmichael numbers and
// strong pseudoprimes, exponents past mbedTLS's 8192-bit limit, DH_check
// results, and generated safe primes.
beforeAll(async () => {
await mkdir(join(testDir, "build"), { recursive: true });
await execFileAsync("clang", [
"-std=c11",
"-O1",
"-Wall",
"-Wextra",
"-Wno-missing-field-initializers",
"-fsanitize=address,undefined",
"-DSCR_RC_AUDIT",
"-I",
join(testDir, "../src"),
"-I",
join(mbedtls, "include"),
"-I",
join(mbedtls, "library"),
"-o",
bin,
join(testDir, "test_dh.c"),
...runtimeSources.map((source) => join(testDir, "../src", source)),
...mbedtlsSources.map((source) => join(mbedtls, "library", source)),
"-Wno-deprecated-declarations",
"-lz",
...(process.platform === "linux" ? ["-D_GNU_SOURCE", "-lm"] : []),
]);
}, 300_000);
test("DiffieHellman runtime: exponentiation, primality and safe primes", async () => {
const { stderr } = await execFileAsync(bin, [], {
env: { ...process.env, UBSAN_OPTIONS: "halt_on_error=1" },
});
expect(stderr.trim().split("\n").pop()).toMatch(/^(\d+)\/\1 cases passed$/);
}, 300_000);
+228
View File
@@ -0,0 +1,228 @@
/* Unit tests for the DiffieHellman runtime's arithmetic (scr_dh.c), built
* with ASan and UBSan by dh.test.ts. The unit is included directly so the
* tests can compare the Montgomery exponentiation the primality tests use
* with mbedTLS's, run the primality test on primes, Carmichael numbers and
* strong pseudoprimes to small bases, split exponents past mbedTLS's limit,
* and check generated safe primes and DH_check results. */
#include "../src/scr_dh.c"
#include <stdio.h>
#include <string.h>
static long total = 0, failed = 0;
static void check(bool ok, const char *what) {
total++;
if (!ok) {
failed++;
fprintf(stderr, "FAIL: %s\n", what);
}
}
static void from_hex(mbedtls_mpi *x, const char *hex) {
if (mbedtls_mpi_read_string(x, 16, hex) != 0) scr_trap("bad hex\n");
}
/* The Montgomery exponentiation, with the base 2 and with general bases,
* against mbedtls_mpi_exp_mod for moduli of one to 64 limbs. */
static void test_mont_pow(void) {
#if SD_MONT
static const size_t sizes[] = {3, 64, 65, 127, 128, 129, 512, 1000, 2048, 4096};
mbedtls_mpi n, base, e, two, got, want;
mbedtls_mpi_init(&n);
mbedtls_mpi_init(&base);
mbedtls_mpi_init(&e);
mbedtls_mpi_init(&two);
mbedtls_mpi_init(&got);
mbedtls_mpi_init(&want);
mbedtls_mpi_lset(&two, 2);
for (size_t s = 0; s < sizeof sizes / sizeof sizes[0]; s++) {
for (int trial = 0; trial < 6; trial++) {
size_t bits = sizes[s];
sd_random_bits(&n, bits, true);
if (mbedtls_mpi_cmp_int(&n, 3) <= 0) mbedtls_mpi_lset(&n, 7);
sd_random_bits(&base, bits > 2 ? bits - 1 : 1, false);
size_t ebits = trial == 0 ? 1 : trial == 1 ? bits + 70 : (bits * (size_t)trial) / 5 + 1;
sd_random_bits(&e, ebits, false);
if (trial == 0) mbedtls_mpi_lset(&e, 0);
ScDhMont m;
bool ready = sd_mont_init(&m, &n);
check(ready, "sd_mont_init");
char what[96];
snprintf(what, sizeof what, "base^e mod n for %zu bits, trial %d", bits, trial);
bool ok = ready && sd_mont_pow(&m, &got, &base, &e) && mbedtls_mpi_exp_mod(&want, &base, &e, &n, NULL) == 0;
check(ok && mbedtls_mpi_cmp_mpi(&got, &want) == 0, what);
snprintf(what, sizeof what, "2^e mod n for %zu bits, trial %d", bits, trial);
ok = ready && sd_mont_pow(&m, &got, NULL, &e) && mbedtls_mpi_exp_mod(&want, &two, &e, &n, NULL) == 0;
check(ok && mbedtls_mpi_cmp_mpi(&got, &want) == 0, what);
sd_mont_free(&m);
}
}
mbedtls_mpi_free(&n);
mbedtls_mpi_free(&base);
mbedtls_mpi_free(&e);
mbedtls_mpi_free(&two);
mbedtls_mpi_free(&got);
mbedtls_mpi_free(&want);
#endif
}
/* BN_check_prime's answers for small values, Mersenne numbers, Carmichael
* numbers and strong pseudoprimes to small prime bases. */
static void test_is_prime(void) {
static const struct {
const char *hex;
bool prime;
} cases[] = {
{"0", false},
{"1", false},
{"2", true},
{"3", true},
{"4", false},
{"5", true},
{"9", false},
{"231", false}, /* 561, a Carmichael number */
{"451", false}, /* 1105, a Carmichael number */
{"7ff", false}, /* 2047, a strong pseudoprime to the base 2 */
{"45c5", false}, /* 17861 = 53 · 337 */
{"45c7", true}, /* 17863, the largest trial-division prime */
{"bfa17dc7", false}, /* 3215031751, to the bases 2, 3, 5 and 7 */
{"351591274f9af9fb", false}, /* 3825123056546413051, to the bases up to 23 */
{"437ae92817f9fc85b7e5", false}, /* to the prime bases up to 37 */
{"2be6951adc5b22410a5fd", false}, /* to the prime bases up to 41 */
{"1fffffffffffffff", true}, /* 2^61 - 1 */
{"1ffffffffffffffffffffff", true}, /* 2^89 - 1 */
{"7fffffffffffffffffffffffffffffff", true}, /* 2^127 - 1 */
{"100000000000000000000000000000001", false}, /* 2^128 + 1 */
};
ScDhSmallPrimes *small = sd_small_primes();
mbedtls_mpi x;
mbedtls_mpi_init(&x);
for (size_t i = 0; i < sizeof cases / sizeof cases[0]; i++) {
from_hex(&x, cases[i].hex);
char what[96];
snprintf(what, sizeof what, "is_prime(0x%s) == %d", cases[i].hex, cases[i].prime);
check(sd_is_prime(small, &x) == cases[i].prime, what);
}
/* The modp groups' primes are safe primes. */
for (size_t i = 0; i < 4; i++) {
mbedtls_mpi_read_binary(&x, sd_groups[i].p, sd_groups[i].p_len);
check(sd_is_prime(small, &x), "a modp prime is prime");
mbedtls_mpi_shift_r(&x, 1);
check(sd_is_prime(small, &x), "half a modp prime is prime");
mbedtls_mpi_add_int(&x, &x, 2);
check(!sd_is_prime(small, &x), "half a modp prime plus 2 is composite");
}
mbedtls_mpi_free(&x);
free(small);
}
/* DH_check bits for small and composite primes, the Pocklington path for
* safe primes, and a generator at p - 1. */
static void test_check_params(void) {
static const struct {
const char *p;
int g;
int codes;
} cases[] = {
{"0", 2, 137}, {"1", 2, 137}, {"2", 2, 139}, {"3", 2, 138}, {"5", 2, 128}, {"5", 5, 136},
{"7", 2, 128}, {"9", 2, 129}, {"f", 2, 129}, {"11", 2, 130}, {"17", 2, 128}, {"17", 22, 136},
{"18", 2, 129}, {"231", 2, 129}, {"7ff", 2, 129},
};
mbedtls_mpi p, g;
mbedtls_mpi_init(&p);
mbedtls_mpi_init(&g);
for (size_t i = 0; i < sizeof cases / sizeof cases[0]; i++) {
from_hex(&p, cases[i].p);
mbedtls_mpi_lset(&g, cases[i].g);
char what[96];
int codes = sd_check_params(&p, &g);
snprintf(what, sizeof what, "check(0x%s, %d) == %d (got %d)", cases[i].p, cases[i].g, cases[i].codes, codes);
check(codes == cases[i].codes, what);
}
mbedtls_mpi_read_binary(&p, sd_groups[1].p, sd_groups[1].p_len);
mbedtls_mpi_lset(&g, 2);
check(sd_check_params(&p, &g) == 0, "check(modp2, 2) == 0");
mbedtls_mpi_sub_int(&g, &p, 1);
check(sd_check_params(&p, &g) == SD_NOT_SUITABLE_GENERATOR, "check(modp2, p - 1) == 8");
mbedtls_mpi_lset(&g, 2);
mbedtls_mpi_add_int(&p, &p, 2);
check(sd_check_params(&p, &g) == SD_P_NOT_PRIME, "check(modp2 + 2, 2) == 1");
mbedtls_mpi_free(&p);
mbedtls_mpi_free(&g);
}
/* Exponents past 8192 bits, split into digits, against the exponent
* reduced modulo p - 1 (Fermat) for a prime p. */
static void test_long_exponent(void) {
mbedtls_mpi p, p1, base, e, reduced, got, want;
mbedtls_mpi_init(&p);
mbedtls_mpi_init(&p1);
mbedtls_mpi_init(&base);
mbedtls_mpi_init(&e);
mbedtls_mpi_init(&reduced);
mbedtls_mpi_init(&got);
mbedtls_mpi_init(&want);
mbedtls_mpi_read_binary(&p, sd_groups[0].p, sd_groups[0].p_len);
mbedtls_mpi_sub_int(&p1, &p, 1);
mbedtls_mpi_lset(&base, 5);
static const size_t sizes[] = {8192, 8193, 16382, 16383, 20000};
for (size_t i = 0; i < sizeof sizes / sizeof sizes[0]; i++) {
sd_random_bits(&e, sizes[i], false);
mbedtls_mpi_mod_mpi(&reduced, &e, &p1);
bool ok = sd_exp(&got, &base, &e, &p) && mbedtls_mpi_exp_mod(&want, &base, &reduced, &p, NULL) == 0;
char what[64];
snprintf(what, sizeof what, "5^e mod p for a %zu-bit e", sizes[i]);
check(ok && mbedtls_mpi_cmp_mpi(&got, &want) == 0, what);
}
mbedtls_mpi_lset(&p, 24);
check(!sd_exp(&got, &base, &e, &p), "an even modulus fails");
mbedtls_mpi_lset(&p, 1);
check(!sd_exp(&got, &base, &e, &p), "the modulus 1 fails");
mbedtls_mpi_free(&p);
mbedtls_mpi_free(&p1);
mbedtls_mpi_free(&base);
mbedtls_mpi_free(&e);
mbedtls_mpi_free(&reduced);
mbedtls_mpi_free(&got);
mbedtls_mpi_free(&want);
}
/* Generated safe primes have the requested length and congruence, and
* mbedTLS's own primality test accepts p and (p - 1) / 2. */
static void test_generate(void) {
static const unsigned adds[] = {24, 60, 12};
mbedtls_mpi p, q, g;
mbedtls_mpi_init(&p);
mbedtls_mpi_init(&q);
mbedtls_mpi_init(&g);
mbedtls_mpi_lset(&g, 2);
for (size_t i = 0; i < sizeof adds / sizeof adds[0]; i++) {
for (int trial = 0; trial < 2; trial++) {
bool ok = sd_generate_safe_prime(&p, 512, adds[i], adds[i] - 1);
mbedtls_mpi_uint r = 0;
ok = ok && mbedtls_mpi_bitlen(&p) == 512 && mbedtls_mpi_mod_int(&r, &p, adds[i]) == 0 && r == adds[i] - 1;
mbedtls_mpi_copy(&q, &p);
mbedtls_mpi_shift_r(&q, 1);
ok = ok && mbedtls_mpi_is_prime_ext(&p, 40, sd_random, NULL) == 0 &&
mbedtls_mpi_is_prime_ext(&q, 40, sd_random, NULL) == 0;
char what[64];
snprintf(what, sizeof what, "a 512-bit safe prime ≡ %u (mod %u)", adds[i] - 1, adds[i]);
check(ok, what);
check(sd_check_params(&p, &g) == 0, "a generated prime has no DH_check findings");
}
}
mbedtls_mpi_free(&p);
mbedtls_mpi_free(&q);
mbedtls_mpi_free(&g);
}
int main(void) {
test_mont_pow();
test_is_prime();
test_check_params();
test_long_exponent();
test_generate();
fprintf(stderr, "%ld/%ld cases passed\n", total - failed, total);
return failed ? 1 : 0;
}
+52
View File
@@ -0,0 +1,52 @@
// crypto.getDiffieHellman and createDiffieHellmanGroup on every modp
// group: the RFC primes and generator, verifyError, case-insensitive names,
// private keys of the group's width, and key pairs that agree on one
// secret of the prime's length.
import { createDiffieHellmanGroup, getDiffieHellman, type DiffieHellmanGroup } from "node:crypto";
const groups = ["modp1", "modp2", "modp5", "modp14", "modp15", "modp16", "modp17", "modp18"];
function bitLength(bytes: Buffer): number {
if (bytes.length === 0) return 0;
return (bytes.length - 1) * 8 + bytes[0]!.toString(2).length;
}
for (const name of groups) {
const group: DiffieHellmanGroup = getDiffieHellman(name);
const prime: Buffer = group.getPrime();
console.log(
name,
group.verifyError,
bitLength(prime),
prime.toString("hex").slice(0, 24),
prime.toString("hex").slice(-16),
group.getGenerator("hex"),
);
}
// Key exchange on the groups whose exponentiations stay quick.
for (const name of ["modp1", "modp2", "modp5", "modp14"]) {
const alice = getDiffieHellman(name);
const bob = createDiffieHellmanGroup(name.toUpperCase());
const alicePublic: Buffer = alice.generateKeys();
const bobPublic: string = bob.generateKeys("base64");
const fromAlice: Buffer = alice.computeSecret(bobPublic, "base64");
const fromBob: string = bob.computeSecret(alicePublic, null, "hex");
const width = bitLength(alice.getPrivateKey());
console.log(
name,
fromAlice.length,
fromAlice.toString("hex") === fromBob,
alicePublic.length <= fromAlice.length,
name === "modp1" || name === "modp2" ? width <= bitLength(alice.getPrime()) : width,
);
// generateKeys keeps the key pair it has.
console.log(alice.generateKeys("hex") === alicePublic.toString("hex"), alice.getPublicKey().equals(alicePublic));
}
// The prime and generator in every encoding.
const modp5 = getDiffieHellman("Modp5");
for (const encoding of ["hex", "base64", "base64url", "latin1", "binary"] as const) {
const prime: string = modp5.getPrime(encoding as "hex");
console.log(encoding, prime.length, JSON.stringify(modp5.getGenerator(encoding as "hex")));
}
+169
View File
@@ -0,0 +1,169 @@
// crypto.createDiffieHellman over explicit parameters: fixed private keys
// give Node's public keys and secrets, verifyError reports DH_check's
// findings, and parameters that equal an OpenSSL named group draw private
// keys of the group's length.
import { createDiffieHellman, getDiffieHellman, type DiffieHellman } from "node:crypto";
// A 512-bit safe prime with p ≡ 23 (mod 24).
const P512 =
"f29864297728009aab9d4220c05ca2d80a5e4ac2f016cd098543a2486bde8bcb" +
"deed9eab7029c8d2b7a681f9495bfc7b1c39c6db64457bb79beeb74a4b78f5ff";
function bitLength(bytes: Buffer): number {
if (bytes.length === 0) return 0;
return (bytes.length - 1) * 8 + bytes[0]!.toString(2).length;
}
function fixed(prime: Buffer, generator: number | Buffer, key: string): DiffieHellman {
const dh = createDiffieHellman(prime, generator);
dh.setPrivateKey(key, "hex");
return dh;
}
const prime512 = Buffer.from(P512, "hex");
for (const generator of [2, 3, 5, Buffer.from([0x0b])]) {
const alice = fixed(prime512, generator, "0123456789abcdef0123456789abcdef");
const bob = fixed(prime512, generator, "fedcba9876543210fedcba9876543210ff");
const alicePublic: string = alice.generateKeys("hex");
const bobPublic: Buffer = bob.generateKeys();
const secret: string = alice.computeSecret(bobPublic, null, "hex");
console.log(alice.getGenerator("hex"), alice.verifyError, alicePublic.slice(0, 32), bobPublic.length);
console.log(secret, secret === bob.computeSecret(alicePublic, "hex", "hex"));
}
// Secrets pad to the prime's length; public keys are minimal.
const modp1 = getDiffieHellman("modp1").getPrime();
const small = fixed(modp1, 2, "01");
console.log(small.generateKeys("hex"), small.getPrivateKey("hex"));
const big = fixed(modp1, 2, "ff".repeat(100));
console.log(big.generateKeys().length, big.getPrivateKey().length);
const padded: Buffer = small.computeSecret(Buffer.from([4]));
console.log(padded.length, padded.subarray(0, 4).toString("hex"), padded.subarray(-2).toString("hex"));
console.log(big.computeSecret(Buffer.from([2]), null, "base64url"));
// A private key of 0 still yields a public key; reading it back and
// deriving a secret from it fail. A private key of 1 answers the peer's
// key.
function report(run: () => unknown): void {
try {
const result = run();
console.log(Buffer.isBuffer(result) ? result.toString("hex") : result);
} catch (error) {
const e = error as Error & { code?: string };
console.log(e.name, e.code, e.message);
}
}
const zero = fixed(prime512, 2, "00");
console.log(zero.generateKeys("hex"));
report(() => zero.getPrivateKey());
report(() => zero.computeSecret(Buffer.from([5])));
report(() => fixed(prime512, 2, "01").computeSecret(Buffer.from([5])));
// A private key longer than the prime: 8800 bits.
const long = fixed(modp1, 2, "ff".repeat(1100));
console.log(long.generateKeys("hex").slice(0, 32), long.computeSecret(Buffer.from([7]), null, "hex").slice(-32));
// setPublicKey and setPrivateKey answer the object and replace the keys.
const keys = createDiffieHellman(prime512);
keys.setPublicKey(Buffer.from([0, 0, 7]));
keys.setPrivateKey("0005", "hex");
console.log(keys.getPublicKey("hex"), keys.getPrivateKey("hex"));
console.log(keys.generateKeys("hex").length, keys.getPublicKey("hex") !== "07");
// verifyError for small, even, composite and non-safe primes and for
// unsuitable generators.
const cases: [string, number | string][] = [
["01", 2],
["02", 2],
["03", 2],
["0d", 2],
["15", 2],
["17", 2],
["17", 5],
["17", "16"],
["17", "1e"],
["18", 2],
["000017", 2],
["05", 2],
["05", 5],
["07", 2],
["09", 2],
["0b", 5],
["0f", 2],
["11", 2],
["2f", 2],
["3b", 5],
["0231", 2],
["0451", 2],
["07ff", 2],
];
for (const [prime, generator] of cases) {
const g = typeof generator === "number" ? generator : Buffer.from(generator, "hex");
console.log(prime, generator, createDiffieHellman(Buffer.from(prime, "hex"), g).verifyError);
}
const almost = Buffer.from(P512, "hex");
almost[almost.length - 1] = 0xfe;
console.log(createDiffieHellman(almost).verifyError);
const composite = Buffer.from(P512, "hex");
composite[composite.length - 1] = 0xfd;
console.log(createDiffieHellman(composite).verifyError);
const generatorPMinus1 = Buffer.from(P512, "hex");
generatorPMinus1[generatorPMinus1.length - 1] = 0xfe;
console.log(createDiffieHellman(prime512, generatorPMinus1).verifyError);
// Generated keys: bits(p) - 2 bits for other primes, at most the named
// group's key length for RFC 3526 and RFC 5114 parameters.
const generated = createDiffieHellman(prime512);
generated.generateKeys();
console.log(bitLength(generated.getPrivateKey()));
const modp14 = getDiffieHellman("modp14").getPrime();
const named = createDiffieHellman(modp14, Buffer.from([0, 2]));
named.generateKeys();
console.log(named.verifyError, bitLength(named.getPrivateKey()) <= 225);
const notNamed = createDiffieHellman(modp1);
notNamed.generateKeys();
console.log(bitLength(notNamed.getPrivateKey()));
const rfc5114 = createDiffieHellman(
Buffer.from(
"b10b8f96a080e01dde92de5eae5d54ec52c99fbcfb06a3c69a6a9dca52d23b616073e28675a23d189838ef1e2ee652c0" +
"13ecb4aea906112324975c3cd49b83bfaccbdd7d90c4bd7098488e9c219a73724effd6fae5644738faa31a4ff55bccc0" +
"a151af5f0dc8b4bd45bf37df365c1a65e68cfda76d4da708df1fb2bc2e4a4371",
"hex",
),
Buffer.from(
"a4d1cbd5c3fd34126765a442efb99905f8104dd258ac507fd6406cff14266d31266fea1e5c41564b777e690f5504f213" +
"160217b4b01b886a5e91547f9e2749f4d7fbd7d3b9a92ee1909d0d2263f80a76a6a24c087a091f531dbf0a0169b6a28a" +
"d662a4d18e73afa32d779d5918d08bc8858f4dcef97c2a24855e6eeb22b3b2e5",
"hex",
),
);
rfc5114.generateKeys();
console.log(rfc5114.verifyError, bitLength(rfc5114.getPrivateKey()) <= 160);
// RFC 5114's 2048-bit group with a 256-bit subgroup draws 224-bit keys.
const rfc5114q256 = createDiffieHellman(
Buffer.from(
"87a8e61db4b6663cffbbd19c651959998ceef608660dd0f25d2ceed4435e3b00e00df8f1d61957d4faf7df4561b2aa30" +
"16c3d91134096faa3bf4296d830e9a7c209e0c6497517abd5a8a9d306bcf67ed91f9e6725b4758c022e0b1ef4275bf7b" +
"6c5bfc11d45f9088b941f54eb1e59bb8bc39a0bf12307f5c4fdb70c581b23f76b63acae1caa6b7902d52526735488a0e" +
"f13c6d9a51bfa4ab3ad8347796524d8ef6a167b5a41825d967e144e5140564251ccacb83e6b486f6b3ca3f7971506026" +
"c0b857f689962856ded4010abd0be621c3a3960a54e710c375f26375d7014103a4b54330c198af126116d2276e11715f" +
"693877fad7ef09cadb094ae91e1a1597",
"hex",
),
Buffer.from(
"3fb32c9b73134d0b2e77506660edbd484ca7b18f21ef205407f4793a1a0ba12510dbc15077be463fff4fed4aac0bb555" +
"be3a6c1b0c6b47b1bc3773bf7e8c6f62901228f8c28cbb18a55ae31341000a650196f931c77a57f2ddf463e5e9ec144b" +
"777de62aaab8a8628ac376d282d6ed3864e67982428ebc831d14348f6f2f9193b5045af2767164e1dfc967c1fb3f2e55" +
"a4bd1bffe83b9c80d052b985d182ea0adb2a3b7313d3fe14c8484b1e052588b9b7d2bbd2df016199ecd06e1557cd0915" +
"b3353bbb64e0ec377fd028370df92b52c7891428cdc67eb6184b523d1db246c32f63078490f00ef8d647d148d4795451" +
"5e2327cfef98c582664b4c0f6cc41659",
"hex",
),
);
let widest = 0;
for (let i = 0; i < 8; i++) {
const keys = createDiffieHellman(rfc5114q256.getPrime(), rfc5114q256.getGenerator());
keys.generateKeys();
widest = Math.max(widest, bitLength(keys.getPrivateKey()));
}
console.log(rfc5114q256.verifyError, widest <= 224, widest > 200);
+147
View File
@@ -0,0 +1,147 @@
// createDiffieHellman, getDiffieHellman and DiffieHellman errors from
// JavaScript: argument types and ranges, the keyEncoding and generator
// forms, OpenSSL's generator and modulus errors with their library and
// reason properties, parameter sizes, group names, encodings, keys read
// before they exist, public keys outside (1, p - 1), key generation and
// secrets on primes outside 512 to 10000 bits, and members a
// DiffieHellmanGroup does not have.
import crypto from "node:crypto";
// Values the declared overloads reject reach the calls through an
// untyped function, as they would from other untyped code.
const loose = (value) => value;
function attempt(label, run) {
try {
const result = run();
if (Buffer.isBuffer(result)) console.log(label, "ok", result.toString("hex"));
else if (typeof result === "object" && result !== null)
console.log(label, "ok", result.getGenerator("hex"), result.getPrime().length);
else console.log(label, "ok", JSON.stringify(result));
} catch (e) {
const extra = e.library === undefined ? "" : ` [${Object.keys(e).join(",")}] ${e.library} / ${e.reason}`;
console.log(label, e.name, e.code, e.message + extra);
}
}
const prime = crypto.getDiffieHellman("modp1").getPrime();
attempt("size missing", () => crypto.createDiffieHellman(loose(undefined)));
attempt("size null", () => crypto.createDiffieHellman(loose(null)));
attempt("size boolean", () => crypto.createDiffieHellman(loose(true)));
attempt("size object", () => crypto.createDiffieHellman(loose({})));
attempt("size bigint", () => crypto.createDiffieHellman(loose(5n)));
attempt("size fraction", () => crypto.createDiffieHellman(1.5));
attempt("size NaN", () => crypto.createDiffieHellman(NaN));
attempt("size 2^31", () => crypto.createDiffieHellman(2 ** 31));
attempt("size 2^40", () => crypto.createDiffieHellman(2 ** 40));
attempt("size -1", () => crypto.createDiffieHellman(-1));
attempt("size -0", () => crypto.createDiffieHellman(-0));
attempt("size 1", () => crypto.createDiffieHellman(1));
attempt("size 1 bad generator", () => crypto.createDiffieHellman(1, 1));
attempt("size 2 generator 1", () => crypto.createDiffieHellman(2, 1));
attempt("size 2", () => crypto.createDiffieHellman(2));
attempt("size 511", () => crypto.createDiffieHellman(511));
attempt("size 10001", () => crypto.createDiffieHellman(10001));
attempt("size generator string", () => crypto.createDiffieHellman(64, loose("02")));
attempt("size generator view", () => crypto.createDiffieHellman(64, loose(Buffer.from([2]))));
attempt("generator 0", () => crypto.createDiffieHellman(prime, 0));
attempt("generator 1", () => crypto.createDiffieHellman(prime, 1));
attempt("generator -1", () => crypto.createDiffieHellman(prime, -1));
attempt("generator fraction", () => crypto.createDiffieHellman(prime, 2.5));
attempt("generator 2^31", () => crypto.createDiffieHellman(prime, 2 ** 31));
attempt("generator NaN", () => crypto.createDiffieHellman(prime, NaN));
attempt("generator null", () => crypto.createDiffieHellman(prime, loose(null)));
attempt("generator empty string", () => crypto.createDiffieHellman(prime, loose("")));
attempt("generator true", () => crypto.createDiffieHellman(prime, loose(true)));
attempt("generator object", () => crypto.createDiffieHellman(prime, loose({})));
attempt("generator view 1", () => crypto.createDiffieHellman(prime, Buffer.from([1])));
attempt("generator view 0", () => crypto.createDiffieHellman(prime, Buffer.from([0])));
attempt("generator view empty", () => crypto.createDiffieHellman(prime, Buffer.alloc(0)));
attempt("generator view 0002", () => crypto.createDiffieHellman(prime, Buffer.from([0, 2])));
attempt("generator = p", () => crypto.createDiffieHellman(prime, prime));
attempt("generator > p", () => crypto.createDiffieHellman(prime, Buffer.concat([Buffer.from([1]), prime])));
attempt("generator string", () => crypto.createDiffieHellman(prime, loose("abc")));
attempt("generator string hex", () => crypto.createDiffieHellman(prime, loose("05"), loose("hex")));
attempt("generator bad encoding", () => crypto.createDiffieHellman(prime, loose("05"), loose("nope")));
attempt("generator uint16", () => crypto.createDiffieHellman(prime, new Uint16Array([0x0300])));
attempt("prime hex", () => crypto.createDiffieHellman(prime.toString("hex"), "hex"));
attempt("prime base64 generator", () => crypto.createDiffieHellman(prime.toString("base64"), "base64", 5));
attempt("prime utf8", () => crypto.createDiffieHellman("abc").verifyError);
attempt("prime buffer encoding", () => crypto.createDiffieHellman("abc", "buffer"));
attempt("keyEncoding as generator", () => crypto.createDiffieHellman("abc", loose("nope")).verifyError);
attempt("keyEncoding as generator with encoding", () => crypto.createDiffieHellman("abc", loose("nope"), loose("hex")));
attempt("keyEncoding number", () => crypto.createDiffieHellman(prime, loose(5)));
attempt("keyEncoding on a view", () => crypto.createDiffieHellman(prime, loose("hex"), 5));
attempt("prime ArrayBuffer", () => crypto.createDiffieHellman(new Uint8Array(prime).buffer));
attempt("prime DataView", () => crypto.createDiffieHellman(new DataView(new ArrayBuffer(3))).verifyError);
attempt("prime zero", () => crypto.createDiffieHellman(Buffer.alloc(4)).getPrime());
attempt("group unknown", () => crypto.getDiffieHellman("modp3"));
attempt("group empty", () => crypto.getDiffieHellman(""));
attempt("group ffdhe", () => crypto.createDiffieHellmanGroup("ffdhe2048"));
attempt("group case", () => crypto.getDiffieHellman("MoDp2"));
attempt("group missing", () => crypto.getDiffieHellman(loose(undefined)));
attempt("group number", () => crypto.getDiffieHellman(loose(14)));
const group = crypto.getDiffieHellman("modp2");
attempt("group public before keys", () => group.getPublicKey());
attempt("group private before keys", () => group.getPrivateKey());
attempt("group secret before keys", () => group.computeSecret(Buffer.from([5])));
const untypedGroup = loose(group);
attempt("group setPublicKey", () => untypedGroup.setPublicKey(Buffer.from([5])));
attempt("group setPrivateKey", () => untypedGroup.setPrivateKey(Buffer.from([5])));
group.generateKeys();
attempt("secret 0", () => group.computeSecret(Buffer.from([0])));
attempt("secret empty", () => group.computeSecret(Buffer.alloc(0)));
attempt("secret 1", () => group.computeSecret(Buffer.from([0, 1])));
attempt("secret p - 1", () => {
const key = Buffer.from(group.getPrime());
key[key.length - 1]--;
return group.computeSecret(key);
});
attempt("secret p", () => group.computeSecret(group.getPrime()));
attempt("secret 2", () => group.computeSecret(Buffer.from([2])).length);
attempt("secret number", () => group.computeSecret(loose(5)));
attempt("secret bad input encoding", () => group.computeSecret("ab", loose("nope")));
attempt("secret bad output encoding", () => untypedGroup.computeSecret(Buffer.from([2]), null, "nope"));
attempt("getPrime bad encoding", () => untypedGroup.getPrime("nope"));
attempt("getPrime HEX", () => untypedGroup.getPrime("HEX").slice(0, 8));
attempt("getGenerator utf16le", () => untypedGroup.getGenerator("utf16le"));
attempt("verifyError call", () => untypedGroup.verifyError());
attempt("unknown member", () => untypedGroup.bogus());
const fresh = crypto.createDiffieHellman(prime);
attempt("public before keys", () => fresh.getPublicKey());
attempt("private before keys", () => fresh.getPrivateKey());
attempt("secret before keys", () => fresh.computeSecret(Buffer.from([5])));
attempt("setPublicKey number", () => fresh.setPublicKey(loose(5)));
attempt("setPrivateKey bad encoding", () => fresh.setPrivateKey("ab", loose("nope")));
attempt("setPublicKey 0", () => loose(fresh.setPublicKey(Buffer.from([0]))).getPublicKey());
attempt("setPrivateKey utf8", () => loose(fresh.setPrivateKey("ab")).getPrivateKey("hex"));
// Primes outside 512 to 10000 bits: key generation and secrets fail, but a
// private key the program sets still yields a public key.
for (const value of [23, 1, 0, 24]) {
const label = `p ${value}`;
const dh = crypto.createDiffieHellman(Buffer.from([value]));
attempt(`${label} generateKeys`, () => dh.generateKeys());
attempt(`${label} secret 2`, () => dh.computeSecret(Buffer.from([2])));
attempt(`${label} secret 5`, () => dh.computeSecret(Buffer.from([5])));
dh.setPrivateKey(Buffer.from([3]));
attempt(`${label} generateKeys with key`, () => dh.generateKeys());
attempt(`${label} public with key`, () => dh.getPublicKey());
attempt(`${label} secret with key`, () => dh.computeSecret(Buffer.from([5])));
}
const even = Buffer.from(prime);
even[even.length - 1] = 0xfe;
const evenDh = crypto.createDiffieHellman(even);
attempt("even generateKeys", () => evenDh.generateKeys());
evenDh.setPrivateKey(Buffer.from([3]));
attempt("even generateKeys with key", () => evenDh.generateKeys());
attempt("p 23 generator 30", () =>
loose(crypto.createDiffieHellman(Buffer.from([23]), 30).setPrivateKey(Buffer.from([2]))).generateKeys(),
);
attempt("p 9", () => loose(crypto.createDiffieHellman(Buffer.from([9])).setPrivateKey(Buffer.from([3]))).generateKeys());
+47
View File
@@ -0,0 +1,47 @@
// crypto.createDiffieHellman(primeLength, generator) generates a safe
// prime of the requested length: p ≡ 23 (mod 24) for the generator 2,
// p ≡ 59 (mod 60) for 5 and p ≡ 11 (mod 12) otherwise. A second party built
// from the first one's prime and generator agrees on the secret.
import { createDiffieHellman } from "node:crypto";
function bitLength(bytes: Buffer): number {
if (bytes.length === 0) return 0;
return (bytes.length - 1) * 8 + bytes[0]!.toString(2).length;
}
function mod(bytes: Buffer, m: number): number {
let r = 0;
for (const byte of bytes) r = (r * 256 + byte) % m;
return r;
}
for (const generator of [undefined, 2, 5, 3, 7]) {
const alice = generator === undefined ? createDiffieHellman(512) : createDiffieHellman(512, generator);
const prime = alice.getPrime();
console.log(
generator,
bitLength(prime),
alice.getGenerator("hex"),
alice.verifyError,
generator === undefined || generator === 2
? mod(prime, 24)
: generator === 5
? mod(prime, 60)
: mod(prime, 12),
);
const bob = createDiffieHellman(alice.getPrime(), alice.getGenerator());
const alicePublic = alice.generateKeys();
const bobPublic = bob.generateKeys("hex");
const secret = alice.computeSecret(bobPublic, "hex");
console.log(
bob.verifyError,
bitLength(alice.getPrivateKey()),
secret.length,
secret.equals(bob.computeSecret(alicePublic)),
);
}
// A string prime with its encoding, and the generator as a string.
const shared = createDiffieHellman(512);
const copy = createDiffieHellman(shared.getPrime("base64"), "base64", shared.getGenerator("hex"), "hex");
console.log(copy.getPrime().equals(shared.getPrime()), copy.getGenerator("hex"), copy.verifyError);
+73
View File
@@ -0,0 +1,73 @@
// DiffieHellman string inputs and outputs from CommonJS: primes and
// generators as strings in every binary encoding, the keyEncoding slot
// read as the generator, keys set in every Buffer encoding and read in the
// declared ones, and computeSecret's input and output encodings.
const crypto = require("node:crypto");
// Values the declared overloads do not cover reach the calls through an
// untyped function, as they would from other untyped code.
const loose = (value) => value;
const prime = crypto.getDiffieHellman("modp2").getPrime();
const encodings = ["hex", "base64", "base64url", "latin1", "binary", "HEX", "Base64"];
for (const encoding of encodings) {
const text = prime.toString(encoding.toLowerCase());
const dh = crypto.createDiffieHellman(text, encoding, "05", "hex");
console.log(encoding, dh.getPrime().equals(prime), dh.getGenerator("hex"));
}
console.log(crypto.createDiffieHellman(prime.toString("hex"), "hex", "05", "hex").verifyError);
// A truthy keyEncoding that names no encoding is the generator, and the
// generator slot its encoding.
console.log(crypto.createDiffieHellman(prime, 7).getGenerator("hex"));
console.log(crypto.createDiffieHellman(prime, "\x05").getGenerator("hex"));
console.log(crypto.createDiffieHellman(prime, Buffer.from([3])).getGenerator("hex"));
console.log(crypto.createDiffieHellman(prime, "buffer", 11).getGenerator("hex"));
console.log(crypto.createDiffieHellman(prime, "0d", "hex").getGenerator("hex"));
console.log(crypto.createDiffieHellman(prime, "base64", "Ew==", "base64").getGenerator("hex"));
console.log(crypto.createDiffieHellman(prime, "", 0, "").getGenerator("hex"));
// Keys in and out of every encoding.
const alice = crypto.createDiffieHellman(prime);
const bob = crypto.createDiffieHellman(prime);
alice.setPrivateKey("q83vEjRWeJA=", "base64");
bob.setPrivateKey(Buffer.from("10325476", "hex"));
alice.generateKeys();
bob.generateKeys();
function report(encoding, key, secret) {
const bytes = Buffer.isBuffer(secret) ? secret : Buffer.from(secret, encoding);
console.log(encoding, typeof key, key.length, bytes.toString("hex").slice(0, 24));
}
const hex = alice.getPublicKey("hex");
report("hex", hex, bob.computeSecret(hex, "hex", "hex"));
const base64 = alice.getPublicKey("base64");
report("base64", base64, bob.computeSecret(base64, "base64", "base64"));
const base64url = alice.getPublicKey("base64url");
report("base64url", base64url, bob.computeSecret(base64url, "base64url", "base64url"));
const binary = alice.getPublicKey("binary");
report("binary", binary, bob.computeSecret(binary, "binary", "binary"));
const view = alice.getPublicKey();
report("undefined", view, bob.computeSecret(view, undefined, undefined));
report("null", view, bob.computeSecret(view, null, null));
// Encodings @types/node does not declare for these methods reach them
// through an untyped receiver.
const untypedBob = loose(bob);
console.log(alice.getPrivateKey("hex"), alice.getPrivateKey("base64url"), untypedBob.getPrivateKey("latin1").length);
console.log(untypedBob.getPublicKey("utf16le").length, untypedBob.getPrime("ucs2").length, untypedBob.getGenerator("buffer"));
console.log(untypedBob.computeSecret(loose(alice).getPublicKey("latin1"), "latin1", "base64").slice(0, 16));
// setPublicKey and setPrivateKey read strings through their encoding;
// 'buffer' and a missing encoding read utf8.
const keys = crypto.createDiffieHellman(prime);
keys.setPublicKey("ffee", "hex");
loose(keys).setPrivateKey("zz", "buffer");
console.log(keys.getPublicKey("hex"), keys.getPrivateKey("hex"));
keys.setPublicKey("é");
console.log(keys.getPublicKey("hex"));
keys.setPublicKey("é", "latin1");
console.log(keys.getPublicKey("hex"));
keys.setPrivateKey(new Uint16Array([0x0102, 0x0304]));
console.log(keys.getPrivateKey("hex"));
keys.setPrivateKey(new DataView(new Uint8Array([9, 8, 7]).buffer));
console.log(keys.getPrivateKey("hex"));
+56
View File
@@ -0,0 +1,56 @@
// DiffieHellman and DiffieHellmanGroup values as ordinary values: class
// fields, optional fields, arrays, Map values, parameters and return
// values, with verifyError read through each.
import * as crypto from "node:crypto";
import { type DiffieHellman, type DiffieHellmanGroup } from "node:crypto";
const prime = crypto.getDiffieHellman("modp1").getPrime();
class Party {
readonly dh: DiffieHellman;
peer: DiffieHellman | null = null;
group?: DiffieHellmanGroup;
constructor(seed: number) {
this.dh = crypto.createDiffieHellman(prime, 2);
this.dh.setPrivateKey(Buffer.from([seed, seed + 1, seed + 2]));
this.dh.generateKeys();
}
secretWith(other: Party): string {
return this.dh.computeSecret(other.dh.getPublicKey(), null, "hex");
}
}
const alice = new Party(1);
const bob = new Party(7);
alice.peer = bob.dh;
console.log(alice.secretWith(bob) === bob.secretWith(alice), alice.secretWith(bob).slice(0, 32));
console.log(alice.peer !== null && alice.peer.getPublicKey().equals(bob.dh.getPublicKey()));
console.log(alice.group === undefined);
alice.group = crypto.getDiffieHellman("modp2");
console.log(alice.group.verifyError, alice.group.getPrime().length);
function verify(dh: DiffieHellman | DiffieHellmanGroup): number {
return dh.verifyError;
}
function make(bytes: number[]): DiffieHellman {
return crypto.createDiffieHellman(Buffer.from(bytes));
}
const all: (DiffieHellman | DiffieHellmanGroup)[] = [alice.dh, make([23]), make([24]), crypto.getDiffieHellman("modp5")];
console.log(all.map(verify).join(","));
for (const dh of all) console.log(dh.getGenerator("hex"), dh.getPrime().length);
const byName = new Map<string, DiffieHellmanGroup>();
for (const name of ["modp1", "modp2"]) byName.set(name, crypto.createDiffieHellmanGroup(name));
for (const [name, group] of byName) {
group.generateKeys();
console.log(name, group.getGenerator("hex"), group.computeSecret(alice.dh.getPublicKey()).length);
}
let maybe: DiffieHellman | undefined;
console.log(maybe?.verifyError);
maybe = make([0x0d]);
console.log(maybe?.verifyError, maybe.getPrime("hex"));
+22
View File
@@ -0,0 +1,22 @@
import {
type DiffieHellman,
type DiffieHellmanGroup,
createDiffieHellman,
createDiffieHellmanGroup,
getDiffieHellman,
} from "node:crypto";
const group: DiffieHellmanGroup = getDiffieHellman("modp2");
const alice: DiffieHellman = createDiffieHellman(group.getPrime(), group.getGenerator());
const bob: DiffieHellman = createDiffieHellman(group.getPrime("hex"), "hex", 2);
alice.setPrivateKey(Buffer.from("0a0b0c", "hex"));
bob.setPrivateKey("0d0e0f", "hex");
const alicePublic: Buffer = alice.generateKeys();
const bobPublic: string = bob.generateKeys("base64");
const fromAlice: string = alice.computeSecret(bobPublic, "base64", "hex");
const fromBob: Buffer = bob.computeSecret(alicePublic);
console.log(fromAlice === fromBob.toString("hex"), fromAlice.slice(0, 16), alice.verifyError);
const named: DiffieHellmanGroup = createDiffieHellmanGroup("modp5");
console.log(named.getPrime().length, named.getGenerator("hex"), bob.getPrivateKey("hex"));
const generated: string = named.generateKeys("hex");
console.log(generated.length <= 384, named.getPublicKey("hex") === generated);
+6
View File
@@ -103,6 +103,12 @@ cipherStream.on("data", () => {});
import { createECDH } from "node:crypto";
createECDH("sect163k1");
createECDH("prime256v1").computeSecret(Buffer.alloc(65), "hex");
/* DiffieHellman's Object.prototype members, and crypto.diffieHellman over
* asymmetric KeyObjects. */
import { createDiffieHellman, diffieHellman, type KeyObject } from "node:crypto";
createDiffieHellman(Buffer.from([23])).toString();
declare const dhKey: KeyObject;
diffieHellman({ privateKey: dhKey, publicKey: dhKey });
/* WebCrypto beyond the HMAC slice: @types/node declares the whole
* SubtleCrypto surface, and the methods outside importKey, sign, verify
* and digest fence by name. */
@@ -228,24 +228,42 @@ fenced.ts:105:1 - error SC2020: 'ECDH.computeSecret(key, encoding) with a Buffer
104 | createECDH("sect163k1");
105 | createECDH("prime256v1").computeSecret(Buffer.alloc(65), "hex");
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
106 | /* WebCrypto beyond the HMAC slice: @types/node declares the whole
106 | /* DiffieHellman's Object.prototype members, and crypto.diffieHellman over
hint: Node reads the second argument as the key's input encoding and answers a Buffer; pass the output encoding third: computeSecret(key, undefined, encoding)
fenced.ts:110:9 - error SC2020: 'crypto.subtle.encrypt' is part of the standard library types but has no scriptc lowering yet
fenced.ts:109:1 - error SC2020: 'DiffieHellman.toString' is part of the standard library types but has no scriptc lowering yet
109 | async function encryptWithWebCrypto(key: import("node:crypto").webcrypto.CryptoKey): Promise<void> {
110 | await crypto.subtle.encrypt({ name: "AES-GCM", iv: new Uint8Array(12) }, key, new Uint8Array(1));
108 | import { createDiffieHellman, diffieHellman, type KeyObject } from "node:crypto";
109 | createDiffieHellman(Buffer.from([23])).toString();
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
110 | declare const dhKey: KeyObject;
hint: generateKeys(), computeSecret(), getPrime(), getGenerator(), getPublicKey(), getPrivateKey(), setPublicKey(), setPrivateKey() and verifyError are supported
fenced.ts:111:1 - error SC2020: 'crypto.diffieHellman' is typed by @types/node but has no scriptc lowering yet
110 | declare const dhKey: KeyObject;
111 | diffieHellman({ privateKey: dhKey, publicKey: dhKey });
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
112 | /* WebCrypto beyond the HMAC slice: @types/node declares the whole
hint: crypto.diffieHellman takes asymmetric KeyObjects, which the static runtime does not have; the objects of createDiffieHellman, getDiffieHellman and createECDH compute shared secrets
fenced.ts:116:9 - error SC2020: 'crypto.subtle.encrypt' is part of the standard library types but has no scriptc lowering yet
115 | async function encryptWithWebCrypto(key: import("node:crypto").webcrypto.CryptoKey): Promise<void> {
116 | await crypto.subtle.encrypt({ name: "AES-GCM", iv: new Uint8Array(12) }, key, new Uint8Array(1));
| ^~~~~~~~~~~~~~~~~~~~~
111 | }
117 | }
hint: the native WebCrypto surface is crypto.subtle.importKey('raw', ...) for HMAC keys, sign and verify with HMAC, and digest with SHA-1, SHA-256, SHA-384 or SHA-512, each called directly on crypto.subtle
fenced.ts:115:15 - error SC2020: 'navigator.hardwareConcurrency' is typed by @types/node but has no scriptc lowering yet
fenced.ts:121:15 - error SC2020: 'navigator.hardwareConcurrency' is typed by @types/node but has no scriptc lowering yet
114 | * compile; the other members fence by name. */
115 | const cores = navigator.hardwareConcurrency;
120 | * compile; the other members fence by name. */
121 | const cores = navigator.hardwareConcurrency;
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
116 | void cores;
122 | void cores;
hint: of Node's navigator global only typeof navigator and navigator.userAgent compile
@@ -0,0 +1 @@
{ "plain": 4855, "san": 8228 }
@@ -0,0 +1 @@
{ "plain": 6328, "san": 10420 }
@@ -0,0 +1 @@
{ "plain": 8044, "san": 10499 }
@@ -0,0 +1 @@
{ "plain": 6999, "san": 9388 }
@@ -0,0 +1 @@
{ "plain": 6048, "san": 8117 }
@@ -0,0 +1 @@
{ "plain": 5664, "san": 7161 }
+47
View File
@@ -918,6 +918,53 @@ for (const run of [() => ecdh.getPublicKey.name, () => { ecdh.custom = 1; }]) {
});
});
// DiffieHellman primes past mbedTLS's 8192-bit limit throw a coded SC2020
// error, as do property reads other than verifyError, property writes, and
// Object.prototype method calls on an untyped DiffieHellman.
describe("DiffieHellman runtime refusals", () => {
test("primes longer than 8192 bits throw SC2020", async () => {
const r = await compileAndRun(
"dh-long-prime",
`import { createDiffieHellman } from "node:crypto";
const prime = Buffer.alloc(1025, 0xff);
for (const run of [() => createDiffieHellman(prime), () => createDiffieHellman(8193)]) {
try {
run();
} catch (error) {
const e = error as Error & { code?: string };
console.log(e.name, e.code, e.message);
}
}
console.log(createDiffieHellman(Buffer.alloc(1024, 0xff)).verifyError);
`,
);
expect(r.exitCode).toBe(0);
const message = "DiffieHellman primes longer than 8192 bits have no native implementation";
expect(r.stdout).toBe(`Error SC2020 ${message}\nError SC2020 ${message}\n1\n`);
expect(r.stderr).toBe("");
});
test("DiffieHellman property reads, writes and Object.prototype calls throw SC2020", async () => {
const r = await compileAndRun(
"dh-properties",
`const crypto = require("node:crypto");
const dh = crypto.getDiffieHellman("modp1");
console.log(dh.verifyError);
for (const run of [() => dh.getPrime.name, () => { dh.verifyError = 1; }, () => dh.hasOwnProperty("verifyError")]) {
try {
run();
} catch (e) {
console.log(e.name, e.code);
}
}
`,
"cjs",
);
expect(r.exitCode).toBe(0);
expect(r.stdout).toBe("0\nError SC2020\nError SC2020\nError SC2020\n");
});
});
// Node formats an unknown output encoding with %s, which prints a
// function's source text and calls a toString the encoding's class
// defines. The cipher runtime has neither, so both throw a coded SC2020
+14
View File
@@ -1114,6 +1114,20 @@ test("node-types: ECDH matches Node under @types/node", async () => {
expect(comparableStderr(native.stderr)).toBe(node.stderr);
});
test("node-types: DiffieHellman matches Node under @types/node", async () => {
const outDir = outDirFor("node-dh");
const entry = join(nodeTypesDir, "dh.ts");
const result = await compile(entry, { outPath: join(outDir, "dh"), outDir, sanitize });
expect(result.ok, !result.ok ? JSON.stringify(result.diagnostics, null, 2) : "").toBe(true);
if (!result.ok) return;
const [native, node] = await Promise.all([
execFileAsync(result.binaryPath),
execFileAsync(process.execPath, ["--disable-warning=MODULE_TYPELESS_PACKAGE_JSON", entry]),
]);
expect(native.stdout).toBe(node.stdout);
expect(comparableStderr(native.stderr)).toBe(node.stderr);
});
test("node-types: WebCrypto HMAC matches Node under @types/node", async () => {
const outDir = outDirFor("node-webcrypto-hmac");
const entry = join(nodeTypesDir, "webcrypto-hmac.ts");
@@ -48,6 +48,7 @@ const features: NativeLinkFeatures = {
tlsCa: false,
cipher: false,
ecdh: false,
dh: false,
webcrypto: false,
perfLoop: false,
};
@@ -49,6 +49,7 @@ const base: NativeLinkFeatures = {
tlsCa: false,
cipher: false,
ecdh: false,
dh: false,
webcrypto: false,
perfLoop: false,
};