GeezerVison is showing github.com — crypto: make generatePrime/checkPrime interruptible · nodejs/node@1994eaa
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/crypto.md +14Lines changed: 14 additions & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -3934,6 +3934,13 @@ By default, the prime is encoded as a big-endian sequence of octets | 3934 | 3934 | in an {ArrayBuffer}. If the `bigint` option is `true`, then a {bigint} | 3935 | 3935 | is provided. | 3936 | 3936 |
| | 3937 | +The `size` of the prime will have a direct impact on how long it takes to | | 3938 | +generate the prime. The larger the size, the longer it will take. Because | | 3939 | +we use OpenSSL's `BN_generate_prime_ex` function, which provides only | | 3940 | +minimal control over our ability to interrupt the generation process, | | 3941 | +it is not recommended to generate overly large primes, as doing so may make | | 3942 | +the process unresponsive. | | 3943 | + | 3937 | 3944 | ### `crypto.generatePrimeSync(size[, options])` | 3938 | 3945 |
| 3939 | 3946 | <!-- YAML | @@ -3975,6 +3982,13 @@ By default, the prime is encoded as a big-endian sequence of octets | 3975 | 3982 | in an {ArrayBuffer}. If the `bigint` option is `true`, then a {bigint} | 3976 | 3983 | is provided. | 3977 | 3984 |
| | 3985 | +The `size` of the prime will have a direct impact on how long it takes to | | 3986 | +generate the prime. The larger the size, the longer it will take. Because | | 3987 | +we use OpenSSL's `BN_generate_prime_ex` function, which provides only | | 3988 | +minimal control over our ability to interrupt the generation process, | | 3989 | +it is not recommended to generate overly large primes, as doing so may make | | 3990 | +the process unresponsive. | | 3991 | + | 3978 | 3992 | ### `crypto.getCipherInfo(nameOrNid[, options])` | 3979 | 3993 |
| 3980 | 3994 | <!-- YAML | |
Collapse file Copy file name to clipboardExpand all lines: src/crypto/crypto_random.cc +29-11Lines changed: 29 additions & 11 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -28,6 +28,25 @@ using v8::Uint32; | 28 | 28 | using v8::Value; | 29 | 29 |
| 30 | 30 | namespace crypto { | | 31 | +namespace { | | 32 | +using BNGENCBPointer = DeleteFnPtr<BN_GENCB, BN_GENCB_free>; | | 33 | + | | 34 | +BNGENCBPointer getBN_GENCB(Environment* env) { | | 35 | + // The callback is used to check if the operation should be stopped. | | 36 | + // Currently, the only check we perform is if env->is_stopping() | | 37 | + // is true. | | 38 | + BNGENCBPointer cb(BN_GENCB_new()); | | 39 | + BN_GENCB_set( | | 40 | + cb.get(), | | 41 | + [](int a, int b, BN_GENCB* cb) -> int { | | 42 | + Environment* env = static_cast<Environment*>(BN_GENCB_get_arg(cb)); | | 43 | + return env->is_stopping() ? 0 : 1; | | 44 | + }, | | 45 | + env); | | 46 | + return cb; | | 47 | +} | | 48 | + | | 49 | +} // namespace | 31 | 50 | MaybeLocal<Value> RandomBytesTraits::EncodeOutput( | 32 | 51 | Environment* env, const RandomBytesConfig& params, ByteSource* unused) { | 33 | 52 | return v8::Undefined(env->isolate()); | @@ -150,13 +169,14 @@ bool RandomPrimeTraits::DeriveBits(Environment* env, | 150 | 169 | // Make sure the CSPRNG is properly seeded. | 151 | 170 | CHECK(ncrypto::CSPRNG(nullptr, 0)); | 152 | 171 |
| 153 | | - if (BN_generate_prime_ex( | 154 | | - params.prime.get(), | 155 | | - params.bits, | 156 | | - params.safe ? 1 : 0, | 157 | | - params.add.get(), | 158 | | - params.rem.get(), | 159 | | - nullptr) == 0) { | | 172 | + BNGENCBPointer cb = getBN_GENCB(env); | | 173 | + | | 174 | + if (BN_generate_prime_ex(params.prime.get(), | | 175 | + params.bits, | | 176 | + params.safe ? 1 : 0, | | 177 | + params.add.get(), | | 178 | + params.rem.get(), | | 179 | + cb.get()) == 0) { | 160 | 180 | return false; | 161 | 181 | } | 162 | 182 |
| @@ -189,12 +209,10 @@ bool CheckPrimeTraits::DeriveBits( | 189 | 209 | ByteSource* out) { | 190 | 210 |
| 191 | 211 | BignumCtxPointer ctx(BN_CTX_new()); | | 212 | + BNGENCBPointer cb = getBN_GENCB(env); | 192 | 213 |
| 193 | 214 | int ret = BN_is_prime_ex( | 194 | | - params.candidate.get(), | 195 | | - params.checks, | 196 | | - ctx.get(), | 197 | | - nullptr); | | 215 | + params.candidate.get(), params.checks, ctx.get(), cb.get()); | 198 | 216 | if (ret < 0) return false; | 199 | 217 | ByteSource::Builder buf(1); | 200 | 218 | buf.data<char>()[0] = ret; | |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-crypto-prime.js +16Lines changed: 16 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -14,6 +14,8 @@ const { | 14 | 14 | checkPrimeSync, | 15 | 15 | } = require('crypto'); | 16 | 16 |
| | 17 | +const { Worker } = require('worker_threads'); | | 18 | + | 17 | 19 | const { promisify } = require('util'); | 18 | 20 | const pgeneratePrime = promisify(generatePrime); | 19 | 21 | const pCheckPrime = promisify(checkPrime); | @@ -295,3 +297,17 @@ assert.throws(() => { | 295 | 297 | checkPrime(prime, common.mustSucceed(assert)); | 296 | 298 | })); | 297 | 299 | } | | 300 | + | | 301 | +{ | | 302 | + // Verify that generatePrime can be reasonably interrupted. | | 303 | + const worker = new Worker(` | | 304 | + const { generatePrime } = require('crypto'); | | 305 | + generatePrime(2048, () => { | | 306 | + throw new Error('should not be called'); | | 307 | + }); | | 308 | + process.exit(42); | | 309 | + `, { eval: true }); | | 310 | + | | 311 | + worker.on('error', common.mustNotCall()); | | 312 | + worker.on('exit', common.mustCall((exitCode) => assert.strictEqual(exitCode, 42))); | | 313 | +} |
|