Skip to content

Commit a33ce6e

Browse files
Move RSA Key Generation off the main-thread with Isolates (#199)
* perf: optimize rsa key generation with isolates * fix: resolve linter issues
1 parent 7801d4f commit a33ce6e

File tree

5 files changed

+26
-7
lines changed

5 files changed

+26
-7
lines changed

lib/src/impl_ffi/impl_ffi.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import 'dart:async';
2020
import 'dart:ffi' show Allocator;
2121
import 'dart:typed_data';
2222
import 'dart:convert' show utf8, base64Url;
23+
import 'dart:isolate';
2324
import 'dart:ffi' as ffi;
2425
import 'dart:math' as math;
2526
import 'package:meta/meta.dart';

lib/src/impl_ffi/impl_ffi.rsa_common.dart

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,10 +229,10 @@ Map<String, dynamic> _exportJwkRsaPrivateOrPublicKey(
229229
});
230230
}
231231

232-
KeyPair<_EvpPKey, _EvpPKey> _generateRsaKeyPair(
232+
Future<KeyPair<_EvpPKey, _EvpPKey>> _generateRsaKeyPair(
233233
int modulusLength,
234234
BigInt publicExponent,
235-
) {
235+
) async {
236236
// Sanity check for the modulusLength
237237
if (modulusLength < 256 || modulusLength > 16384) {
238238
throw UnsupportedError(
@@ -251,13 +251,14 @@ KeyPair<_EvpPKey, _EvpPKey> _generateRsaKeyPair(
251251
throw UnsupportedError('publicExponent is not supported, try 3 or 65537');
252252
}
253253

254-
return _Scope.sync((scope) {
254+
return _Scope.async((scope) async {
255255
// Generate private RSA key
256256
final privRSA = scope.createRSA();
257257

258258
final e = scope.createBN();
259259
_checkOpIsOne(ssl.BN_set_word(e, publicExponent.toInt()));
260-
_checkOpIsOne(ssl.RSA_generate_key_ex(
260+
261+
_checkOpIsOne(await _RSA_generate_key_ex(
261262
privRSA,
262263
modulusLength,
263264
e,
@@ -284,3 +285,20 @@ KeyPair<_EvpPKey, _EvpPKey> _generateRsaKeyPair(
284285
);
285286
});
286287
}
288+
289+
/// Helper function to run `ssl.RSA_generate_key_ex` in an [Isolate]
290+
/// using [Isolate.run].
291+
///
292+
/// Using this auxiliary function to wrap the call should reduce the risk that
293+
/// unnecessary variables are copied into the closure passed to [Isolate.run].
294+
// ignore: non_constant_identifier_names
295+
Future<int> _RSA_generate_key_ex(
296+
ffi.Pointer<RSA> rsa,
297+
int bits,
298+
ffi.Pointer<BIGNUM> e,
299+
ffi.Pointer<BN_GENCB> cb,
300+
) async =>
301+
await Isolate.run(
302+
() => ssl.RSA_generate_key_ex(rsa, bits, e, cb),
303+
debugName: 'RSA_generate_key_ex',
304+
);

lib/src/impl_ffi/impl_ffi.rsaoaep.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Future<KeyPair<RsaOaepPrivateKeyImpl, RsaOaepPublicKeyImpl>>
5050
) async {
5151
// Get hash first, to avoid a leak of EVP_PKEY if _HashImpl.fromHash throws
5252
final h = _HashImpl.fromHash(hash);
53-
final keys = _generateRsaKeyPair(modulusLength, publicExponent);
53+
final keys = await _generateRsaKeyPair(modulusLength, publicExponent);
5454
return (
5555
privateKey: _RsaOaepPrivateKeyImpl(keys.privateKey, h),
5656
publicKey: _RsaOaepPublicKeyImpl(keys.publicKey, h),

lib/src/impl_ffi/impl_ffi.rsapss.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Future<KeyPair<RsaPssPrivateKeyImpl, RsaPssPublicKeyImpl>>
5050
) async {
5151
// Validate and get hash function
5252
final h = _HashImpl.fromHash(hash);
53-
final keys = _generateRsaKeyPair(modulusLength, publicExponent);
53+
final keys = await _generateRsaKeyPair(modulusLength, publicExponent);
5454
return (
5555
privateKey: _RsaPssPrivateKeyImpl(keys.privateKey, h),
5656
publicKey: _RsaPssPublicKeyImpl(keys.publicKey, h),

lib/src/impl_ffi/impl_ffi.rsassapkcs1v15.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Future<KeyPair<RsaSsaPkcs1V15PrivateKeyImpl, RsaSsaPkcs1V15PublicKeyImpl>>
5050
) async {
5151
// Get hash first, to avoid a leak of EVP_PKEY if _HashImpl.fromHash throws
5252
final h = _HashImpl.fromHash(hash);
53-
final keys = _generateRsaKeyPair(modulusLength, publicExponent);
53+
final keys = await _generateRsaKeyPair(modulusLength, publicExponent);
5454
return (
5555
privateKey: _RsaSsaPkcs1V15PrivateKeyImpl(keys.privateKey, h),
5656
publicKey: _RsaSsaPkcs1V15PublicKeyImpl(keys.publicKey, h),

0 commit comments

Comments
 (0)