Skip to content

Commit

Permalink
Refactor EcdhPublicKey and EcdhPrivateKey Class (#145)
Browse files Browse the repository at this point in the history
* refactor: update ecdh-private-key ecdh-public-key

* fix!: remove cyclic imports and migrate keypair class
  • Loading branch information
HamdaanAliQuatil authored Oct 18, 2024
1 parent cdf81ad commit 923ac08
Show file tree
Hide file tree
Showing 22 changed files with 339 additions and 187 deletions.
18 changes: 6 additions & 12 deletions lib/src/impl_ffi/impl_ffi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,6 @@ class _OperationError extends Error implements OperationError {
String toString() => _message;
}

/// Implementation of [KeyPair].
class _KeyPair<S, T> implements KeyPair<S, T> {
@override
final S privateKey;

@override
final T publicKey;

_KeyPair({required this.privateKey, required this.publicKey});
}


const WebCryptoImpl webCryptImpl = _WebCryptoImpl();

final class _WebCryptoImpl implements WebCryptoImpl {
Expand All @@ -89,4 +77,10 @@ final class _WebCryptoImpl implements WebCryptoImpl {

@override
final pbkdf2SecretKey = const _StaticPbkdf2SecretKeyImpl();

@override
final ecdhPrivateKey = const _StaticEcdhPrivateKeyImpl();

@override
final ecdhPublicKey = const _StaticEcdhPublicKeyImpl();
}
6 changes: 3 additions & 3 deletions lib/src/impl_ffi/impl_ffi.ec_common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,9 @@ KeyPair<_EvpPKey, _EvpPKey> _generateEcKeyPair(
final pubKey = _EvpPKey();
_checkOpIsOne(ssl.EVP_PKEY_set1_EC_KEY.invoke(pubKey, ecPub));

return _KeyPair(
privateKey: privKey,
publicKey: pubKey,
return createKeyPair(
privKey,
pubKey,
);
});
}
75 changes: 55 additions & 20 deletions lib/src/impl_ffi/impl_ffi.ecdh.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,71 +16,90 @@

part of 'impl_ffi.dart';

Future<EcdhPrivateKey> ecdhPrivateKey_importPkcs8Key(
Future<EcdhPrivateKeyImpl> ecdhPrivateKey_importPkcs8Key(
List<int> keyData,
EllipticCurve curve,
) async =>
_EcdhPrivateKey(_importPkcs8EcPrivateKey(keyData, curve));
_EcdhPrivateKeyImpl(_importPkcs8EcPrivateKey(keyData, curve));

Future<EcdhPrivateKey> ecdhPrivateKey_importJsonWebKey(
Future<EcdhPrivateKeyImpl> ecdhPrivateKey_importJsonWebKey(
Map<String, dynamic> jwk,
EllipticCurve curve,
) async =>
_EcdhPrivateKey(_importJwkEcPrivateOrPublicKey(
_EcdhPrivateKeyImpl(_importJwkEcPrivateOrPublicKey(
JsonWebKey.fromJson(jwk),
curve,
isPrivateKey: true,
expectedUse: 'enc',
expectedAlg: null, // ECDH has no validation of 'jwk.alg'
));

Future<KeyPair<EcdhPrivateKey, EcdhPublicKey>> ecdhPrivateKey_generateKey(
Future<KeyPair<EcdhPrivateKeyImpl, EcdhPublicKeyImpl>> ecdhPrivateKey_generateKey(
EllipticCurve curve,
) async {
final p = _generateEcKeyPair(curve);
return _KeyPair(
privateKey: _EcdhPrivateKey(p.privateKey),
publicKey: _EcdhPublicKey(p.publicKey),
return createKeyPair(
_EcdhPrivateKeyImpl(p.privateKey),
_EcdhPublicKeyImpl(p.publicKey),
);
}

Future<EcdhPublicKey> ecdhPublicKey_importRawKey(
Future<EcdhPublicKeyImpl> ecdhPublicKey_importRawKey(
List<int> keyData,
EllipticCurve curve,
) async =>
_EcdhPublicKey(_importRawEcPublicKey(keyData, curve));
_EcdhPublicKeyImpl(_importRawEcPublicKey(keyData, curve));

Future<EcdhPublicKey> ecdhPublicKey_importSpkiKey(
Future<EcdhPublicKeyImpl> ecdhPublicKey_importSpkiKey(
List<int> keyData,
EllipticCurve curve,
) async =>
_EcdhPublicKey(_importSpkiEcPublicKey(keyData, curve));
_EcdhPublicKeyImpl(_importSpkiEcPublicKey(keyData, curve));

Future<EcdhPublicKey> ecdhPublicKey_importJsonWebKey(
Future<EcdhPublicKeyImpl> ecdhPublicKey_importJsonWebKey(
Map<String, dynamic> jwk,
EllipticCurve curve,
) async =>
_EcdhPublicKey(_importJwkEcPrivateOrPublicKey(
_EcdhPublicKeyImpl(_importJwkEcPrivateOrPublicKey(
JsonWebKey.fromJson(jwk),
curve,
isPrivateKey: false,
expectedUse: 'enc',
expectedAlg: null, // ECDH has no validation of 'jwk.alg'
));

class _EcdhPrivateKey implements EcdhPrivateKey {
final class _StaticEcdhPrivateKeyImpl implements StaticEcdhPrivateKeyImpl {
const _StaticEcdhPrivateKeyImpl();

@override
Future<EcdhPrivateKeyImpl> importPkcs8Key(List<int> keyData, EllipticCurve curve) =>
ecdhPrivateKey_importPkcs8Key(keyData, curve);

@override
Future<EcdhPrivateKeyImpl> importJsonWebKey(Map<String, dynamic> jwk, EllipticCurve curve) =>
ecdhPrivateKey_importJsonWebKey(jwk, curve);

@override
Future<(EcdhPrivateKeyImpl, EcdhPublicKeyImpl)> generateKey(EllipticCurve curve) async {
final KeyPair<EcdhPrivateKeyImpl, EcdhPublicKeyImpl> keyPair = await ecdhPrivateKey_generateKey(curve);

return (keyPair.privateKey, keyPair.publicKey);
}
}

final class _EcdhPrivateKeyImpl implements EcdhPrivateKeyImpl {
final _EvpPKey _key;

_EcdhPrivateKey(this._key);
_EcdhPrivateKeyImpl(this._key);

@override
String toString() {
return 'Instance of \'EcdhPrivateKey\'';
}

@override
Future<Uint8List> deriveBits(int length, EcdhPublicKey publicKey) async {
if (publicKey is! _EcdhPublicKey) {
Future<Uint8List> deriveBits(int length, EcdhPublicKeyImpl publicKey) async {
if (publicKey is! _EcdhPublicKeyImpl) {
throw ArgumentError.value(
publicKey,
'publicKey',
Expand Down Expand Up @@ -167,10 +186,26 @@ class _EcdhPrivateKey implements EcdhPrivateKey {
Future<Uint8List> exportPkcs8Key() async => _exportPkcs8Key(_key);
}

class _EcdhPublicKey implements EcdhPublicKey {
final class _StaticEcdhPublicKeyImpl implements StaticEcdhPublicKeyImpl {
const _StaticEcdhPublicKeyImpl();

@override
Future<EcdhPublicKeyImpl> importRawKey(List<int> keyData, EllipticCurve curve) =>
ecdhPublicKey_importRawKey(keyData, curve);

@override
Future<EcdhPublicKeyImpl> importSpkiKey(List<int> keyData, EllipticCurve curve) =>
ecdhPublicKey_importSpkiKey(keyData, curve);

@override
Future<EcdhPublicKeyImpl> importJsonWebKey(Map<String, dynamic> jwk, EllipticCurve curve) =>
ecdhPublicKey_importJsonWebKey(jwk, curve);
}

final class _EcdhPublicKeyImpl implements EcdhPublicKeyImpl {
final _EvpPKey _key;

_EcdhPublicKey(this._key);
_EcdhPublicKeyImpl(this._key);

@override
String toString() {
Expand Down
6 changes: 3 additions & 3 deletions lib/src/impl_ffi/impl_ffi.ecdsa.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ Future<KeyPair<EcdsaPrivateKey, EcdsaPublicKey>> ecdsaPrivateKey_generateKey(
EllipticCurve curve,
) async {
final p = _generateEcKeyPair(curve);
return _KeyPair(
privateKey: _EcdsaPrivateKey(p.privateKey),
publicKey: _EcdsaPublicKey(p.publicKey),
return createKeyPair(
_EcdsaPrivateKey(p.privateKey),
_EcdsaPublicKey(p.publicKey),
);
}

Expand Down
8 changes: 4 additions & 4 deletions lib/src/impl_ffi/impl_ffi.rsa_common.dart
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ Map<String, dynamic> _exportJwkRsaPrivateOrPublicKey(
});
}

_KeyPair<_EvpPKey, _EvpPKey> _generateRsaKeyPair(
KeyPair<_EvpPKey, _EvpPKey> _generateRsaKeyPair(
int modulusLength,
BigInt publicExponent,
) {
Expand Down Expand Up @@ -278,9 +278,9 @@ _KeyPair<_EvpPKey, _EvpPKey> _generateRsaKeyPair(
final pubKey = _EvpPKey();
_checkOp(ssl.EVP_PKEY_set1_RSA.invoke(pubKey, pubRSA) == 1);

return _KeyPair(
privateKey: privKey,
publicKey: pubKey,
return createKeyPair(
privKey,
pubKey,
);
});
}
6 changes: 3 additions & 3 deletions lib/src/impl_ffi/impl_ffi.rsaoaep.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ Future<KeyPair<RsaOaepPrivateKey, RsaOaepPublicKey>>
// Get hash first, to avoid a leak of EVP_PKEY if _Hash.fromHash throws
final h = _Hash.fromHash(hash);
final keys = _generateRsaKeyPair(modulusLength, publicExponent);
return _KeyPair(
privateKey: _RsaOaepPrivateKey(keys.privateKey, h),
publicKey: _RsaOaepPublicKey(keys.publicKey, h),
return createKeyPair(
_RsaOaepPrivateKey(keys.privateKey, h),
_RsaOaepPublicKey(keys.publicKey, h),
);
}

Expand Down
6 changes: 3 additions & 3 deletions lib/src/impl_ffi/impl_ffi.rsapss.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ Future<KeyPair<RsaPssPrivateKey, RsaPssPublicKey>> rsaPssPrivateKey_generateKey(
// Validate and get hash function
final h = _Hash.fromHash(hash);
final keys = _generateRsaKeyPair(modulusLength, publicExponent);
return _KeyPair(
privateKey: _RsaPssPrivateKey(keys.privateKey, h),
publicKey: _RsaPssPublicKey(keys.publicKey, h),
return createKeyPair(
_RsaPssPrivateKey(keys.privateKey, h),
_RsaPssPublicKey(keys.publicKey, h),
);
}

Expand Down
6 changes: 3 additions & 3 deletions lib/src/impl_ffi/impl_ffi.rsassapkcs1v15.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ Future<KeyPair<RsassaPkcs1V15PrivateKey, RsassaPkcs1V15PublicKey>>
// Get hash first, to avoid a leak of EVP_PKEY if _Hash.fromHash throws
final h = _Hash.fromHash(hash);
final keys = _generateRsaKeyPair(modulusLength, publicExponent);
return _KeyPair(
privateKey: _RsassaPkcs1V15PrivateKey(keys.privateKey, h),
publicKey: _RsassaPkcs1V15PublicKey(keys.publicKey, h),
return createKeyPair(
_RsassaPkcs1V15PrivateKey(keys.privateKey, h),
_RsassaPkcs1V15PublicKey(keys.publicKey, h),
);
}

Expand Down
38 changes: 36 additions & 2 deletions lib/src/impl_interface/impl_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,46 @@ library impl_stub;
import 'dart:typed_data';
import 'dart:async';

import 'package:webcrypto/webcrypto.dart';

import 'package:webcrypto/webcrypto.dart' show Hash;

part 'impl_interface.aescbc.dart';
part 'impl_interface.aesctr.dart';
part 'impl_interface.hmac.dart';
part 'impl_interface.pbkdf2.dart';
part 'impl_interface.aesgcm.dart';
part 'impl_interface.ecdh.dart';

/// A key-pair as returned from key generation.
class KeyPair<S, T> {
KeyPair._(this.privateKey, this.publicKey); // keep the constructor private.

/// Private key for [publicKey].
final S privateKey;

/// Public key matching [privateKey].
final T publicKey;
}

/// Factory method to create KeyPair instance
KeyPair<S, T> createKeyPair<S, T>(S privateKey, T publicKey) {
return KeyPair._(privateKey, publicKey);
}

/// Elliptic curves supported by ECDSA and ECDH.
///
/// > [!NOTE]
/// > Additional values may be added to this enum in the future.
enum EllipticCurve {
p256,
p384,

///
///
/// P-521 is **not supported on Safari**, see [bug 216755 (bugs.webkit.org)][1].
///
/// [1]: https://bugs.webkit.org/show_bug.cgi?id=216755
p521,
}

/// Interface to be provided by platform implementations.
///
Expand All @@ -48,4 +80,6 @@ abstract interface class WebCryptoImpl {
StaticAesGcmSecretKeyImpl get aesGcmSecretKey;
StaticHmacSecretKeyImpl get hmacSecretKey;
StaticPbkdf2SecretKeyImpl get pbkdf2SecretKey;
StaticEcdhPrivateKeyImpl get ecdhPrivateKey;
StaticEcdhPublicKeyImpl get ecdhPublicKey;
}
39 changes: 39 additions & 0 deletions lib/src/impl_interface/impl_interface.ecdh.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

part of 'impl_interface.dart';

abstract interface class StaticEcdhPrivateKeyImpl {
Future<EcdhPrivateKeyImpl> importPkcs8Key(List<int> keyData, EllipticCurve curve);
Future<EcdhPrivateKeyImpl> importJsonWebKey(Map<String, dynamic> jwk, EllipticCurve curve);
Future<(EcdhPrivateKeyImpl, EcdhPublicKeyImpl)> generateKey(EllipticCurve curve);
}

abstract interface class EcdhPrivateKeyImpl {
Future<Uint8List> deriveBits(int length, EcdhPublicKeyImpl publicKey);
Future<Uint8List> exportPkcs8Key();
Future<Map<String, dynamic>> exportJsonWebKey();
}

abstract interface class StaticEcdhPublicKeyImpl {
Future<EcdhPublicKeyImpl> importRawKey(List<int> keyData, EllipticCurve curve);
Future<EcdhPublicKeyImpl> importSpkiKey(List<int> keyData, EllipticCurve curve);
Future<EcdhPublicKeyImpl> importJsonWebKey(Map<String, dynamic> jwk, EllipticCurve curve);
}

abstract interface class EcdhPublicKeyImpl {
Future<Uint8List> exportRawKey();
Future<Uint8List> exportSpkiKey();
Future<Map<String, dynamic>> exportJsonWebKey();
}
17 changes: 6 additions & 11 deletions lib/src/impl_js/impl_js.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,6 @@ class _OperationError extends Error implements OperationError {
String toString() => _message;
}

/// Implementation of [KeyPair].
class _KeyPair<S, T> implements KeyPair<S, T> {
@override
final S privateKey;

@override
final T publicKey;

_KeyPair({required this.privateKey, required this.publicKey});
}

const WebCryptoImpl webCryptImpl = _WebCryptoImpl();

final class _WebCryptoImpl implements WebCryptoImpl {
Expand All @@ -75,4 +64,10 @@ final class _WebCryptoImpl implements WebCryptoImpl {

@override
final pbkdf2SecretKey = const _StaticPbkdf2SecretKeyImpl();

@override
final ecdhPrivateKey = const _StaticEcdhPrivateKeyImpl();

@override
final ecdhPublicKey = const _StaticEcdhPublicKeyImpl();
}
Loading

0 comments on commit 923ac08

Please sign in to comment.