diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 00000000..26d33521
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/dart-pg.iml b/.idea/dart-pg.iml
new file mode 100644
index 00000000..dff73777
--- /dev/null
+++ b/.idea/dart-pg.iml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000..639900d1
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 00000000..3059f289
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000..35eb1ddf
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/src/helpers.dart b/lib/src/helpers.dart
index e1fd1713..1017fb39 100644
--- a/lib/src/helpers.dart
+++ b/lib/src/helpers.dart
@@ -64,12 +64,38 @@ class Helper {
),
);
+ static pc.SecureRandom _secureWithSeed(final Uint8List seed) {
+ if (seed.isNotEmpty) {
+ return pc.SecureRandom('Fortuna')
+ ..seed(
+ pc.KeyParameter(
+ seed
+ ),
+ );
+ } else {
+ return pc.SecureRandom('Fortuna')
+ ..seed(
+ pc.KeyParameter(
+ Uint8List.fromList(
+ List.generate(
+ 32,
+ ((_) => _random.nextInt(0xffffffff)),
+ ),
+ ),
+ ),
+ );
+ }
+ }
+
static BigInt readMPI(Uint8List bytes) {
final bitLength = bytes.sublist(0, 2).toUint16();
return bytes.sublist(2, ((bitLength + 7) >> 3) + 2).toBigIntWithSign(1);
}
static pc.SecureRandom secureRandom() => _secureRandom;
+ static pc.SecureRandom secureWithSeed(final Uint8List seed) {
+ return _secureWithSeed(seed);
+ }
static Uint8List generatePrefix([
final SymmetricAlgorithm symmetric = SymmetricAlgorithm.aes256,
diff --git a/lib/src/openpgp.dart b/lib/src/openpgp.dart
index 2b4dddd1..a8d36deb 100644
--- a/lib/src/openpgp.dart
+++ b/lib/src/openpgp.dart
@@ -48,6 +48,7 @@ class OpenPGP {
final int keyExpirationTime = 0,
final String? subkeyPassphrase,
final DateTime? date,
+ required Uint8List seed
}) async =>
PrivateKey.generate(
userIDs,
@@ -59,6 +60,7 @@ class OpenPGP {
keyExpirationTime: keyExpirationTime,
subkeyPassphrase: subkeyPassphrase,
date: date,
+ seed: seed
);
/// Read an armored & unlock OpenPGP private key with the given passphrase.
diff --git a/lib/src/packet/key/key_pair_params.dart b/lib/src/packet/key/key_pair_params.dart
index 04e4ad49..b925da0b 100644
--- a/lib/src/packet/key/key_pair_params.dart
+++ b/lib/src/packet/key/key_pair_params.dart
@@ -36,6 +36,7 @@ class KeyPairParams {
final RSAKeySize rsaKeySize = RSAKeySize.s4096,
final DHKeySize dhKeySize = DHKeySize.l2048n224,
final CurveInfo curve = CurveInfo.secp521r1,
+ required Uint8List seed,
}) async {
switch (algorithm) {
case KeyAlgorithm.rsaEncryptSign:
@@ -43,7 +44,7 @@ class KeyPairParams {
case KeyAlgorithm.rsaSign:
return _generateRSAKeyPair(rsaKeySize);
case KeyAlgorithm.ecdsa:
- final keyPair = _generateECKeyPair(curve);
+ final keyPair = _generateECKeyPairWithSeed(seed, curve);
final q = keyPair.publicKey.Q!;
return KeyPairParams(
ECDSAPublicParams(
@@ -56,7 +57,7 @@ class KeyPairParams {
if (curve == CurveInfo.curve25519) {
return _generateCurve25519KeyPair();
} else {
- final keyPair = _generateECKeyPair(curve);
+ final keyPair = _generateECKeyPairWithSeed(seed, curve);
final q = keyPair.publicKey.Q!;
return KeyPairParams(
ECDHPublicParams(
@@ -69,7 +70,7 @@ class KeyPairParams {
);
}
case KeyAlgorithm.eddsa:
- return _generateEd25519KeyPair();
+ return _generateEd25519KeyPair(seed);
case KeyAlgorithm.dsa:
return _generateDSAKeyPair(dhKeySize);
case KeyAlgorithm.elgamal:
@@ -210,8 +211,36 @@ class KeyPairParams {
}
}
- static KeyPairParams _generateEd25519KeyPair() {
- final seed = Helper.secureRandom().nextBytes(TweetNaCl.seedSize);
+ static AsymmetricKeyPair _generateECKeyPairWithSeed(final Uint8List seed,
+ [
+ final CurveInfo curve = CurveInfo.secp521r1,
+ ]) {
+ switch (curve) {
+ case CurveInfo.curve25519:
+ case CurveInfo.ed25519:
+ throw UnsupportedError(
+ 'Curve ${curve.name} is unsupported for key generation.',
+ );
+ default:
+ final keyGen = KeyGenerator('EC')
+ ..init(
+ ParametersWithRandom(
+ ECKeyGeneratorParameters(
+ ECDomainParameters(curve.name.toLowerCase()),
+ ),
+ Helper.secureWithSeed(seed),
+ ),
+ );
+ final keyPair = keyGen.generateKeyPair();
+ return AsymmetricKeyPair(
+ keyPair.publicKey as ECPublicKey,
+ keyPair.privateKey as ECPrivateKey,
+ );
+ }
+ }
+
+ static KeyPairParams _generateEd25519KeyPair(final Uint8List feedSeed) {
+ final seed = Helper.secureWithSeed(feedSeed).nextBytes(TweetNaCl.seedSize);
return KeyPairParams(
EdDSAPublicParams(
CurveInfo.ed25519.asn1Oid,
diff --git a/lib/src/packet/secret_key.dart b/lib/src/packet/secret_key.dart
index f88a47ce..e12ad797 100644
--- a/lib/src/packet/secret_key.dart
+++ b/lib/src/packet/secret_key.dart
@@ -111,12 +111,14 @@ class SecretKeyPacket extends ContainedPacket implements KeyPacket {
final DHKeySize dhKeySize = DHKeySize.l2048n224,
final CurveInfo curve = CurveInfo.secp521r1,
final DateTime? date,
+ required Uint8List seed,
}) async {
final keyPair = await KeyPairParams.generate(
algorithm,
rsaKeySize: rsaKeySize,
dhKeySize: dhKeySize,
curve: curve,
+ seed: seed
);
return SecretKeyPacket(
diff --git a/lib/src/packet/secret_subkey.dart b/lib/src/packet/secret_subkey.dart
index 84e0a39d..7fbae954 100644
--- a/lib/src/packet/secret_subkey.dart
+++ b/lib/src/packet/secret_subkey.dart
@@ -43,12 +43,14 @@ class SecretSubkeyPacket extends SecretKeyPacket implements SubkeyPacket {
final DHKeySize dhKeySize = DHKeySize.l2048n224,
final CurveInfo curve = CurveInfo.secp521r1,
final DateTime? date,
+ required Uint8List seed
}) async {
final keyPair = await KeyPairParams.generate(
algorithm,
rsaKeySize: rsaKeySize,
dhKeySize: dhKeySize,
curve: curve,
+ seed: seed
);
return SecretSubkeyPacket(
diff --git a/lib/src/type/private_key.dart b/lib/src/type/private_key.dart
index b2b8261d..6a779c68 100644
--- a/lib/src/type/private_key.dart
+++ b/lib/src/type/private_key.dart
@@ -24,6 +24,7 @@ import '../packet/signature_packet.dart';
import '../packet/user_id.dart';
import 'key.dart';
import 'subkey.dart';
+import 'dart:typed_data';
/// Class that represents an OpenPGP Private Key
class PrivateKey extends Key {
@@ -72,6 +73,7 @@ class PrivateKey extends Key {
final int keyExpirationTime = 0,
final String? subkeyPassphrase,
final DateTime? date,
+ required Uint8List seed,
}) async {
if (userIDs.isEmpty || passphrase.isEmpty) {
throw ArgumentError(
@@ -106,6 +108,7 @@ class PrivateKey extends Key {
dhKeySize: dhKeySize,
curve: (type == KeyGenerationType.eddsa) ? CurveInfo.ed25519 : curve,
date: date,
+ seed: seed
).then((secretKey) => secretKey.encrypt(passphrase));
final secretSubkey = await SecretSubkeyPacket.generate(
subkeyAlgorithm,
@@ -113,6 +116,7 @@ class PrivateKey extends Key {
dhKeySize: dhKeySize,
curve: (type == KeyGenerationType.eddsa) ? CurveInfo.curve25519 : curve,
date: date,
+ seed: seed
).then(
(secretSubkey) => secretSubkey.encrypt(subkeyPassphrase ?? passphrase),
);
@@ -358,6 +362,7 @@ class PrivateKey extends Key {
final int keyExpirationTime = 0,
final bool subkeySign = false,
final DateTime? date,
+ required Uint8List seed,
}) async {
if (passphrase.isEmpty) {
throw ArgumentError('passphrase are required for key generation');
@@ -368,6 +373,7 @@ class PrivateKey extends Key {
dhKeySize: dhKeySize,
curve: curve,
date: date,
+ seed: seed
).then((secretSubkey) => secretSubkey.encrypt(passphrase));
return PrivateKey.fromPacketList(PacketList([