Skip to content

Commit

Permalink
refactor: update hash and remove circular imports
Browse files Browse the repository at this point in the history
  • Loading branch information
HamdaanAliQuatil committed Oct 25, 2024
1 parent b9ad66e commit 5ce6512
Show file tree
Hide file tree
Showing 40 changed files with 468 additions and 301 deletions.
12 changes: 12 additions & 0 deletions lib/src/impl_ffi/impl_ffi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,16 @@ final class _WebCryptoImpl implements WebCryptoImpl {

@override
final rsaPssPublicKey = const _StaticRsaPssPublicKeyImpl();

@override
final sha1 = const _Sha1();

@override
final sha256 = const _Sha256();

@override
final sha384 = const _Sha384();

@override
final sha512 = const _Sha512();
}
93 changes: 79 additions & 14 deletions lib/src/impl_ffi/impl_ffi.digest.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@

part of 'impl_ffi.dart';

abstract class _Hash implements Hash {
const _Hash();
abstract class _HashImpl implements HashImpl {
const _HashImpl();

factory _Hash.fromHash(Hash hash) {
if (hash is _Hash) {
factory _HashImpl.fromHash(HashImpl hash) {
if (hash is _HashImpl) {
return hash;
}
throw ArgumentError.value(
hash,
'hash',
'Custom implementations of Hash is not supported',
'Custom implementations of HashImpl is not supported',
);
}

Expand Down Expand Up @@ -62,39 +62,104 @@ abstract class _Hash implements Hash {
return out.copy(size);
});
}

@override
String hmacJwkAlg(HashImpl hash) {
if (hash == sha1) {
return 'HS1';
} else if (hash == sha256) {
return 'HS256';
} else if (hash == sha384) {
return 'HS384';
} else if (hash == sha512) {
return 'HS512';
} else {
throw UnsupportedError('hash is not supported');
}
}

@override
String rsaOaepJwkAlg(HashImpl hash){
if (hash == sha1) {
return 'RSA-OAEP-1';
} else if (hash == sha256) {
return 'RSA-OAEP-256';
} else if (hash == sha384) {
return 'RSA-OAEP-384';
} else if (hash == sha512) {
return 'RSA-OAEP-512';
} else {
throw UnsupportedError('hash is not supported');
}
}

@override
String rsaPssJwkAlg(HashImpl hash){
if (hash == sha1) {
return 'PS1';
} else if (hash == sha256) {
return 'PS256';
} else if (hash == sha384) {
return 'PS384';
} else if (hash == sha512) {
return 'PS512';
} else {
throw UnsupportedError('hash is not supported');
}
}

@override
String rsassaPkcs1V15JwkAlg(HashImpl hash){
if (hash == sha1) {
return 'RS1';
} else if (hash == sha256) {
return 'RS256';
} else if (hash == sha384) {
return 'RS384';
} else if (hash == sha512) {
return 'RS512';
} else {
throw UnsupportedError('hash is not supported');
}
}
}

class _Sha1 extends _Hash {
final class _Sha1 extends _HashImpl {
const _Sha1();

@override
ffi.Pointer<EVP_MD> Function() get _algorithm => ssl.EVP_sha1;
}

class _Sha256 extends _Hash {
final class _Sha256 extends _HashImpl {
const _Sha256();

@override
ffi.Pointer<EVP_MD> Function() get _algorithm => ssl.EVP_sha256;
}

class _Sha384 extends _Hash {
final class _Sha384 extends _HashImpl {
const _Sha384();

@override
ffi.Pointer<EVP_MD> Function() get _algorithm => ssl.EVP_sha384;
}

class _Sha512 extends _Hash {
final class _Sha512 extends _HashImpl {
const _Sha512();

@override
ffi.Pointer<EVP_MD> Function() get _algorithm => ssl.EVP_sha512;
}

const Hash sha1 = _Sha1();
const Hash sha256 = _Sha256();
const Hash sha384 = _Sha384();
const Hash sha512 = _Sha512();
// const HashImpl sha1 = _Sha1();
// const HashImpl sha256 = _Sha256();
// const HashImpl sha384 = _Sha384();
// const HashImpl sha512 = _Sha512();

HashImpl get sha1 => const _Sha1();
HashImpl get sha256 => const _Sha256();
HashImpl get sha384 => const _Sha384();
HashImpl get sha512 => const _Sha512();
// Note: Before adding new hash implementations, make sure to update all the
// places that does if (hash == Hash.shaXXX) ...
// places that does if (hash == HashImpl.shaXXX) ...
12 changes: 6 additions & 6 deletions lib/src/impl_ffi/impl_ffi.ecdsa.dart
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,12 @@ final class _EcdsaPrivateKeyImpl implements EcdsaPrivateKeyImpl {
}

@override
Future<Uint8List> signBytes(List<int> data, Hash hash) =>
Future<Uint8List> signBytes(List<int> data, HashImpl hash) =>
signStream(Stream.value(data), hash);

@override
Future<Uint8List> signStream(Stream<List<int>> data, Hash hash) async {
final md = _Hash.fromHash(hash)._md;
Future<Uint8List> signStream(Stream<List<int>> data, HashImpl hash) async {
final md = _HashImpl.fromHash(hash)._md;
final sig = await _signStream(_key, md, data);
return _convertEcdsaDerSignatureToWebCryptoSignature(_key, sig);
}
Expand Down Expand Up @@ -268,16 +268,16 @@ final class _EcdsaPublicKeyImpl implements EcdsaPublicKeyImpl {
}

@override
Future<bool> verifyBytes(List<int> signature, List<int> data, Hash hash) =>
Future<bool> verifyBytes(List<int> signature, List<int> data, HashImpl hash) =>
verifyStream(signature, Stream.value(data), hash);

@override
Future<bool> verifyStream(
List<int> signature,
Stream<List<int>> data,
Hash hash,
HashImpl hash,
) async {
final md = _Hash.fromHash(hash)._md;
final md = _HashImpl.fromHash(hash)._md;

// Convert to DER signature
final sig = _convertEcdsaWebCryptoSignatureToDerSignature(_key, signature);
Expand Down
4 changes: 2 additions & 2 deletions lib/src/impl_ffi/impl_ffi.hkdf.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ final class _HkdfSecretKeyImpl implements HkdfSecretKeyImpl {
@override
Future<Uint8List> deriveBits(
int length,
Hash hash,
HashImpl hash,
List<int> salt,
List<int> info,
) async {
if (length < 0) {
throw ArgumentError.value(length, 'length', 'must be positive integer');
}
final md = _Hash.fromHash(hash)._md;
final md = _HashImpl.fromHash(hash)._md;

// Mirroring limitations in chromium:
// https://chromium.googlesource.com/chromium/src/+/43d62c50b705f88c67b14539e91fd8fd017f70c4/components/webcrypto/algorithms/hkdf.cc#74
Expand Down
41 changes: 12 additions & 29 deletions lib/src/impl_ffi/impl_ffi.hmac.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,40 +32,23 @@ Uint8List _asUint8ListZeroedToBitLength(List<int> data, [int? lengthInBits]) {
return buf;
}

String _hmacJwkAlgFromHash(_Hash hash) {
if (hash == Hash.sha1) {
return 'HS1';
}
if (hash == Hash.sha256) {
return 'HS256';
}
if (hash == Hash.sha384) {
return 'HS384';
}
if (hash == Hash.sha512) {
return 'HS512';
}
assert(false); // This should never happen!
throw UnsupportedError('hash is not supported');
}

Future<HmacSecretKeyImpl> hmacSecretKey_importRawKey(
List<int> keyData,
Hash hash, {
HashImpl hash, {
int? length,
}) async {
return _HmacSecretKeyImpl(
_asUint8ListZeroedToBitLength(keyData, length),
_Hash.fromHash(hash),
_HashImpl.fromHash(hash),
);
}

Future<HmacSecretKeyImpl> hmacSecretKey_importJsonWebKey(
Map<String, dynamic> jwk,
Hash hash, {
HashImpl hash, {
int? length,
}) async {
final h = _Hash.fromHash(hash);
final h = _HashImpl.fromHash(hash);
final k = JsonWebKey.fromJson(jwk);

void checkJwk(bool condition, String prop, String message) =>
Expand All @@ -74,7 +57,7 @@ Future<HmacSecretKeyImpl> hmacSecretKey_importJsonWebKey(
checkJwk(k.kty == 'oct', 'kty', 'must be "oct"');
checkJwk(k.k != null, 'k', 'must be present');
checkJwk(k.use == null || k.use == 'sig', 'use', 'must be "sig", if present');
final expectedAlg = _hmacJwkAlgFromHash(h);
final expectedAlg = _HashImpl.fromHash(h).hmacJwkAlg(h);
checkJwk(
k.alg == null || k.alg == expectedAlg,
'alg',
Expand All @@ -87,10 +70,10 @@ Future<HmacSecretKeyImpl> hmacSecretKey_importJsonWebKey(
}

Future<HmacSecretKeyImpl> hmacSecretKey_generateKey(
Hash hash, {
HashImpl hash, {
int? length,
}) async {
final h = _Hash.fromHash(hash);
final h = _HashImpl.fromHash(hash);
length ??= ssl.EVP_MD_size(h._md) * 8;
final keyData = Uint8List((length / 8).ceil());
fillRandomBytes(keyData);
Expand All @@ -105,26 +88,26 @@ final class _StaticHmacSecretKeyImpl implements StaticHmacSecretKeyImpl {
const _StaticHmacSecretKeyImpl();

@override
Future<HmacSecretKeyImpl> importRawKey(List<int> keyData, Hash hash,
Future<HmacSecretKeyImpl> importRawKey(List<int> keyData, HashImpl hash,
{int? length}) {
return hmacSecretKey_importRawKey(keyData, hash, length: length);
}

@override
Future<HmacSecretKeyImpl> importJsonWebKey(
Map<String, dynamic> jwk, Hash hash,
Map<String, dynamic> jwk, HashImpl hash,
{int? length}) {
return hmacSecretKey_importJsonWebKey(jwk, hash, length: length);
}

@override
Future<HmacSecretKeyImpl> generateKey(Hash hash, {int? length = 32}) {
Future<HmacSecretKeyImpl> generateKey(HashImpl hash, {int? length = 32}) {
return hmacSecretKey_generateKey(hash, length: length);
}
}

final class _HmacSecretKeyImpl implements HmacSecretKeyImpl {
final _Hash _hash;
final _HashImpl _hash;
final Uint8List _keyData;

_HmacSecretKeyImpl(this._keyData, this._hash);
Expand Down Expand Up @@ -186,7 +169,7 @@ final class _HmacSecretKeyImpl implements HmacSecretKeyImpl {
return JsonWebKey(
kty: 'oct',
use: 'sig',
alg: _hmacJwkAlgFromHash(_hash),
alg: _HashImpl.fromHash(_hash).hmacJwkAlg(_hash),
k: _jwkEncodeBase64UrlNoPadding(_keyData),
).toJson();
}
Expand Down
4 changes: 2 additions & 2 deletions lib/src/impl_ffi/impl_ffi.pbkdf2.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ final class _Pbkdf2SecretKeyImpl implements Pbkdf2SecretKeyImpl {
@override
Future<Uint8List> deriveBits(
int length,
Hash hash,
HashImpl hash,
List<int> salt,
int iterations,
) async {
if (length < 0) {
throw ArgumentError.value(length, 'length', 'must be positive integer');
}
final md = _Hash.fromHash(hash)._md;
final md = _HashImpl.fromHash(hash)._md;

// Mirroring limitations in chromium:
// https://chromium.googlesource.com/chromium/src/+/43d62c50b705f88c67b14539e91fd8fd017f70c4/components/webcrypto/algorithms/pbkdf2.cc#75
Expand Down
Loading

0 comments on commit 5ce6512

Please sign in to comment.