Skip to content

Commit

Permalink
Refactor AesGcmSecretKey Class (#143)
Browse files Browse the repository at this point in the history
* refactor: update aesgcm-secret-key
  • Loading branch information
HamdaanAliQuatil authored Sep 27, 2024
1 parent 43fcf0d commit d3af452
Show file tree
Hide file tree
Showing 15 changed files with 149 additions and 42 deletions.
2 changes: 1 addition & 1 deletion lib/src/impl_ffi/impl_ffi.aescbc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ final class _StaticAesCbcSecretKeyImpl implements StaticAesCbcSecretKeyImpl {
}
}

final class _AesCbcSecretKeyImpl extends AesCbcSecretKeyImpl {
final class _AesCbcSecretKeyImpl implements AesCbcSecretKeyImpl {
final Uint8List _key;
_AesCbcSecretKeyImpl(this._key);

Expand Down
2 changes: 1 addition & 1 deletion lib/src/impl_ffi/impl_ffi.aesctr.dart
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ final class _StaticAesCtrSecretKeyImpl implements StaticAesCtrSecretKeyImpl {
}
}

final class _AesCtrSecretKeyImpl extends AesCtrSecretKeyImpl {
final class _AesCtrSecretKeyImpl implements AesCtrSecretKeyImpl {
final Uint8List _key;
_AesCtrSecretKeyImpl(this._key);

Expand Down
35 changes: 27 additions & 8 deletions lib/src/impl_ffi/impl_ffi.aesgcm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@

part of 'impl_ffi.dart';

Future<AesGcmSecretKey> aesGcm_importRawKey(List<int> keyData) async =>
_AesGcmSecretKey(_aesImportRawKey(keyData));
Future<AesGcmSecretKeyImpl> aesGcm_importRawKey(List<int> keyData) async =>
_AesGcmSecretKeyImpl(_aesImportRawKey(keyData));

Future<AesGcmSecretKey> aesGcm_importJsonWebKey(
Future<AesGcmSecretKeyImpl> aesGcm_importJsonWebKey(
Map<String, dynamic> jwk,
) async =>
_AesGcmSecretKey(_aesImportJwkKey(
_AesGcmSecretKeyImpl(_aesImportJwkKey(
jwk,
expectedJwkAlgSuffix: 'GCM',
));

Future<AesGcmSecretKey> aesGcm_generateKey(int length) async =>
_AesGcmSecretKey(_aesGenerateKey(length));
Future<AesGcmSecretKeyImpl> aesGcm_generateKey(int length) async =>
_AesGcmSecretKeyImpl(_aesGenerateKey(length));

Future<Uint8List> _aesGcmEncryptDecrypt(
List<int> key,
Expand Down Expand Up @@ -111,9 +111,28 @@ Future<Uint8List> _aesGcmEncryptDecrypt(
});
}

class _AesGcmSecretKey implements AesGcmSecretKey {
final class _StaticAesGcmSecretKeyImpl implements StaticAesGcmSecretKeyImpl {
const _StaticAesGcmSecretKeyImpl();

@override
Future<AesGcmSecretKeyImpl> importRawKey(List<int> keyData) async {
return await aesGcm_importRawKey(keyData);
}

@override
Future<AesGcmSecretKeyImpl> importJsonWebKey(Map<String, dynamic> jwk) async {
return await aesGcm_importJsonWebKey(jwk);
}

@override
Future<AesGcmSecretKeyImpl> generateKey(int length) async {
return await aesGcm_generateKey(length);
}
}

final class _AesGcmSecretKeyImpl implements AesGcmSecretKeyImpl {
final Uint8List _key;
_AesGcmSecretKey(this._key);
_AesGcmSecretKeyImpl(this._key);

@override
String toString() {
Expand Down
3 changes: 3 additions & 0 deletions lib/src/impl_ffi/impl_ffi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ final class _WebCryptoImpl implements WebCryptoImpl {
@override
final aesCtrSecretKey = const _StaticAesCtrSecretKeyImpl();

@override
final aesGcmSecretKey = const _StaticAesGcmSecretKeyImpl();

@override
final hmacSecretKey = const _StaticHmacSecretKeyImpl();
}
2 changes: 1 addition & 1 deletion lib/src/impl_interface/impl_interface.aescbc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ abstract interface class StaticAesCbcSecretKeyImpl {
Future<AesCbcSecretKeyImpl> generateKey(int length);
}

abstract class AesCbcSecretKeyImpl {
abstract interface class AesCbcSecretKeyImpl {
Future<Uint8List> encryptBytes(List<int> data, List<int> iv);
Future<Uint8List> decryptBytes(List<int> data, List<int> iv);
Stream<Uint8List> encryptStream(Stream<List<int>> data, List<int> iv);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/impl_interface/impl_interface.aesctr.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ abstract interface class StaticAesCtrSecretKeyImpl {
Future<AesCtrSecretKeyImpl> generateKey(int length);
}

abstract class AesCtrSecretKeyImpl {
abstract interface class AesCtrSecretKeyImpl {
Future<Uint8List> encryptBytes(List<int> data, List<int> counter, int length);
Future<Uint8List> decryptBytes(List<int> data, List<int> counter, int length);
Stream<Uint8List> encryptStream(Stream<List<int>> data, List<int> counter, int length);
Expand Down
28 changes: 28 additions & 0 deletions lib/src/impl_interface/impl_interface.aesgcm.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 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 StaticAesGcmSecretKeyImpl {
Future<AesGcmSecretKeyImpl> importRawKey(List<int> keyData);
Future<AesGcmSecretKeyImpl> importJsonWebKey(Map<String, dynamic> jwk);
Future<AesGcmSecretKeyImpl> generateKey(int length);
}

abstract interface class AesGcmSecretKeyImpl {
Future<Uint8List> encryptBytes(List<int> data, List<int> iv, {List<int>? additionalData, int? tagLength});
Future<Uint8List> decryptBytes(List<int> data, List<int> iv, {List<int>? additionalData, int? tagLength});
Future<Uint8List> exportRawKey();
Future<Map<String, dynamic>> exportJsonWebKey();
}
2 changes: 2 additions & 0 deletions lib/src/impl_interface/impl_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import 'package:webcrypto/webcrypto.dart';
part 'impl_interface.aescbc.dart';
part 'impl_interface.aesctr.dart';
part 'impl_interface.hmac.dart';
part 'impl_interface.aesgcm.dart';

/// Interface to be provided by platform implementations.
///
Expand All @@ -43,5 +44,6 @@ part 'impl_interface.hmac.dart';
abstract interface class WebCryptoImpl {
StaticAesCbcSecretKeyImpl get aesCbcSecretKey;
StaticAesCtrSecretKeyImpl get aesCtrSecretKey;
StaticAesGcmSecretKeyImpl get aesGcmSecretKey;
StaticHmacSecretKeyImpl get hmacSecretKey;
}
2 changes: 1 addition & 1 deletion lib/src/impl_js/impl_js.aesctr.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ final class _StaticAesCtrSecretKeyImpl implements StaticAesCtrSecretKeyImpl {
}
}

final class _AesCtrSecretKeyImpl extends AesCtrSecretKeyImpl {
final class _AesCtrSecretKeyImpl implements AesCtrSecretKeyImpl {
final subtle.JSCryptoKey _key;
_AesCtrSecretKeyImpl(this._key);

Expand Down
35 changes: 27 additions & 8 deletions lib/src/impl_js/impl_js.aesgcm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ part of 'impl_js.dart';

const _aesGcmAlgorithm = subtle.Algorithm(name: 'AES-GCM');

Future<AesGcmSecretKey> aesGcm_importRawKey(List<int> keyData) async {
return _AesGcmSecretKey(await _importKey(
Future<AesGcmSecretKeyImpl> aesGcm_importRawKey(List<int> keyData) async {
return _AesGcmSecretKeyImpl(await _importKey(
'raw',
keyData,
_aesGcmAlgorithm,
Expand All @@ -28,28 +28,47 @@ Future<AesGcmSecretKey> aesGcm_importRawKey(List<int> keyData) async {
));
}

Future<AesGcmSecretKey> aesGcm_importJsonWebKey(
Future<AesGcmSecretKeyImpl> aesGcm_importJsonWebKey(
Map<String, dynamic> jwk,
) async {
return _AesGcmSecretKey(await _importJsonWebKey(
return _AesGcmSecretKeyImpl(await _importJsonWebKey(
jwk,
_aesGcmAlgorithm,
_usagesEncryptDecrypt,
'secret',
));
}

Future<AesGcmSecretKey> aesGcm_generateKey(int length) async {
return _AesGcmSecretKey(await _generateKey(
Future<AesGcmSecretKeyImpl> aesGcm_generateKey(int length) async {
return _AesGcmSecretKeyImpl(await _generateKey(
_aesGcmAlgorithm.update(length: length),
_usagesEncryptDecrypt,
'secret',
));
}

class _AesGcmSecretKey implements AesGcmSecretKey {
final class _StaticAesGcmSecretKeyImpl implements StaticAesGcmSecretKeyImpl {
const _StaticAesGcmSecretKeyImpl();

@override
Future<AesGcmSecretKeyImpl> importRawKey(List<int> keyData) async {
return await aesGcm_importRawKey(keyData);
}

@override
Future<AesGcmSecretKeyImpl> importJsonWebKey(Map<String, dynamic> jwk) async {
return await aesGcm_importJsonWebKey(jwk);
}

@override
Future<AesGcmSecretKeyImpl> generateKey(int length) async {
return await aesGcm_generateKey(length);
}
}

final class _AesGcmSecretKeyImpl implements AesGcmSecretKeyImpl {
final subtle.JSCryptoKey _key;
_AesGcmSecretKey(this._key);
_AesGcmSecretKeyImpl(this._key);

@override
String toString() {
Expand Down
3 changes: 3 additions & 0 deletions lib/src/impl_js/impl_js.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ final class _WebCryptoImpl implements WebCryptoImpl {
@override
final aesCtrSecretKey = const _StaticAesCtrSecretKeyImpl();

@override
final aesGcmSecretKey = const _StaticAesGcmSecretKeyImpl();

@override
final hmacSecretKey = const _StaticHmacSecretKeyImpl();
}
8 changes: 0 additions & 8 deletions lib/src/impl_stub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -190,14 +190,6 @@ Future<RsaOaepPublicKey> rsaOaepPublicKey_importJsonWebKey(

//---------------------- AES-GCM

Future<AesGcmSecretKey> aesGcm_importRawKey(List<int> keyData) =>
throw _notImplemented;

Future<AesGcmSecretKey> aesGcm_importJsonWebKey(Map<String, dynamic> jwk) =>
throw _notImplemented;

Future<AesGcmSecretKey> aesGcm_generateKey(int length) => throw _notImplemented;

//---------------------- ECDH

Future<EcdhPrivateKey> ecdhPrivateKey_importPkcs8Key(
Expand Down
31 changes: 31 additions & 0 deletions lib/src/impl_stub/impl_stub.aesgcm.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// 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_stub.dart';

final class _StaticAesGcmSecretKeyImpl implements StaticAesGcmSecretKeyImpl {
const _StaticAesGcmSecretKeyImpl();

@override
Future<AesGcmSecretKeyImpl> importRawKey(List<int> keyData) =>
throw UnimplementedError('Not implemented');

@override
Future<AesGcmSecretKeyImpl> importJsonWebKey(Map<String, dynamic> jwk) =>
throw UnimplementedError('Not implemented');

@override
Future<AesGcmSecretKeyImpl> generateKey(int length) =>
throw UnimplementedError('Not implemented');
}
4 changes: 4 additions & 0 deletions lib/src/impl_stub/impl_stub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import 'package:webcrypto/webcrypto.dart';

part 'impl_stub.aescbc.dart';
part 'impl_stub.aesctr.dart';
part 'impl_stub.aesgcm.dart';
part 'impl_stub.hmac.dart';

const WebCryptoImpl webCryptImpl = _WebCryptoImpl();
Expand All @@ -32,6 +33,9 @@ final class _WebCryptoImpl implements WebCryptoImpl {
@override
final aesCtrSecretKey = const _StaticAesCtrSecretKeyImpl();

@override
final aesGcmSecretKey = const _StaticAesGcmSecretKeyImpl();

@override
final hmacSecretKey = const _StaticHmacSecretKeyImpl();
}
32 changes: 19 additions & 13 deletions lib/src/webcrypto/webcrypto.aesgcm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ part of 'webcrypto.dart';
/// [1]: https://csrc.nist.gov/pubs/sp/800/38/d/final
/// [2]: https://tools.ietf.org/html/rfc7517
/// [3]: https://en.wikipedia.org/wiki/Authenticated_encryption
@sealed
abstract class AesGcmSecretKey {
AesGcmSecretKey._(); // keep the constructor private.
final class AesGcmSecretKey {
final AesGcmSecretKeyImpl _impl;

AesGcmSecretKey._(this._impl); // keep the constructor private.

/// Import an [AesGcmSecretKey] from raw [keyData].
///
Expand Down Expand Up @@ -66,8 +67,9 @@ abstract class AesGcmSecretKey {
/// // Decrypt message (requires the same iv)
/// print(utf8.decode(await k.decryptBytes(c, iv))); // hello world
/// ```
static Future<AesGcmSecretKey> importRawKey(List<int> keyData) {
return impl.aesGcm_importRawKey(keyData);
static Future<AesGcmSecretKey> importRawKey(List<int> keyData) async {
final impl = await webCryptImpl.aesGcmSecretKey.importRawKey(keyData);
return AesGcmSecretKey._(impl);
}

/// Import an [AesGcmSecretKey] from [JSON Web Key][1].
Expand Down Expand Up @@ -102,8 +104,9 @@ abstract class AesGcmSecretKey {
/// ```
///
/// [1]: https://tools.ietf.org/html/rfc7517
static Future<AesGcmSecretKey> importJsonWebKey(Map<String, dynamic> jwk) {
return impl.aesGcm_importJsonWebKey(jwk);
static Future<AesGcmSecretKey> importJsonWebKey(Map<String, dynamic> jwk) async {
final impl = await webCryptImpl.aesGcmSecretKey.importJsonWebKey(jwk);
return AesGcmSecretKey._(impl);
}

/// Generate a random [AesGcmSecretKey].
Expand All @@ -122,8 +125,9 @@ abstract class AesGcmSecretKey {
/// // Generate a new random AES-GCM secret key for AES-256.
/// final key = await AesGcmSecretKey.generate(256);
/// ```
static Future<AesGcmSecretKey> generateKey(int length) {
return impl.aesGcm_generateKey(length);
static Future<AesGcmSecretKey> generateKey(int length) async {
final impl = await webCryptImpl.aesGcmSecretKey.generateKey(length);
return AesGcmSecretKey._(impl);
}

/// Encrypt [data] with this [AesCbcSecretKey] using AES in
Expand Down Expand Up @@ -218,7 +222,8 @@ abstract class AesGcmSecretKey {
List<int> iv, {
List<int>? additionalData,
int? tagLength = 128,
});
}) =>
_impl.encryptBytes(data, iv, additionalData: additionalData, tagLength: tagLength);

// TODO: Document this method, notice that [data] must be concatenation of
// ciphertext and authentication tag.
Expand All @@ -228,7 +233,8 @@ abstract class AesGcmSecretKey {
List<int> iv, {
List<int>? additionalData,
int? tagLength = 128,
});
}) =>
_impl.decryptBytes(data, iv, additionalData: additionalData, tagLength: tagLength);

/// Export [AesGcmSecretKey] as raw bytes.
///
Expand All @@ -250,7 +256,7 @@ abstract class AesGcmSecretKey {
/// // If we wanted to we could import the key as follows:
/// // key = await AesGcmSecretKey.importRawKey(secretBytes);
/// ```
Future<Uint8List> exportRawKey();
Future<Uint8List> exportRawKey() => _impl.exportRawKey();

/// Export [AesGcmSecretKey] as [JSON Web Key][1].
///
Expand All @@ -274,5 +280,5 @@ abstract class AesGcmSecretKey {
/// ```
///
/// [1]: https://tools.ietf.org/html/rfc7517
Future<Map<String, dynamic>> exportJsonWebKey();
Future<Map<String, dynamic>> exportJsonWebKey() => _impl.exportJsonWebKey();
}

0 comments on commit d3af452

Please sign in to comment.