diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index f8506818..686c3aec 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -61,6 +61,7 @@ jobs: matrix: package: - cryptography + - cryptography_test - jwk compiler: - vm diff --git a/cryptography/lib/src/browser/_javascript_bindings.dart b/cryptography/lib/src/browser/_javascript_bindings.dart index 985ffc52..9b8de93a 100644 --- a/cryptography/lib/src/browser/_javascript_bindings.dart +++ b/cryptography/lib/src/browser/_javascript_bindings.dart @@ -81,13 +81,13 @@ Future decrypt( } @internal -Future deriveBits( +Future deriveBits( JSAny algorithm, CryptoKey cryptoKey, JSNumber bits, ) async { final js = await _deriveBits(algorithm, cryptoKey, bits).toDart; - return js.toDart; + return js.toDart.asUint8List(); } @internal @@ -134,9 +134,9 @@ Future exportKeyWhenJwk(CryptoKey key) async { } @internal -Future exportKeyWhenRaw(CryptoKey key) async { +Future exportKeyWhenRaw(CryptoKey key) async { final js = await _exportKey('raw'.toJS, key).toDart; - return (js as JSArrayBuffer).toDart; + return (js as JSArrayBuffer).toDart.asUint8List(); } @internal @@ -202,13 +202,13 @@ JSUint8Array jsUint8ListFrom(List data) { } @internal -Future sign( +Future sign( JSAny algorithm, CryptoKey key, JSUint8Array data, ) async { final js = await _sign(algorithm, key, data).toDart; - return js.toDart; + return js.toDart.asUint8List(); } @internal @@ -330,6 +330,13 @@ extension type AesKeyGenParams._(JSObject jsObject) { }); } +@internal +extension type AlgorithmNameParams._(JSObject jsObject) { + external factory AlgorithmNameParams({ + required JSString name, + }); +} + @internal extension type CryptoKey._(JSObject _) implements JSObject { external JSObject get algorithm; @@ -346,8 +353,8 @@ extension type CryptoKeyPair._(JSObject jsObject) { } @internal -extension type EcdhKeyDeriveParams._(JSObject jsObject) { - external factory EcdhKeyDeriveParams({ +extension type DeriveParamsWhenPublicKey._(JSObject jsObject) { + external factory DeriveParamsWhenPublicKey({ required JSString name, required CryptoKey public, }); diff --git a/cryptography/lib/src/browser/browser_secret_key.dart b/cryptography/lib/src/browser/browser_secret_key.dart index caa80e99..a4b98645 100644 --- a/cryptography/lib/src/browser/browser_secret_key.dart +++ b/cryptography/lib/src/browser/browser_secret_key.dart @@ -95,8 +95,7 @@ class BrowserSecretKey extends SecretKey { return existing; } try { - final byteBuffer = await web_crypto.exportKeyWhenRaw(jsCryptoKey); - final bytes = Uint8List.view(byteBuffer); + final bytes = await web_crypto.exportKeyWhenRaw(jsCryptoKey); final secretKeyData = SecretKeyData( bytes, overwriteWhenDestroyed: true, diff --git a/cryptography/lib/src/browser/ecdh.dart b/cryptography/lib/src/browser/ecdh.dart index 1e20c7c0..848e7fba 100644 --- a/cryptography/lib/src/browser/ecdh.dart +++ b/cryptography/lib/src/browser/ecdh.dart @@ -14,7 +14,6 @@ import 'dart:js_interop'; import 'dart:math'; -import 'dart:typed_data'; import 'package:cryptography/cryptography.dart'; @@ -108,15 +107,15 @@ class BrowserEcdh extends Ecdh { final jsPrivateKey = await jsPrivateKeyFuture; final jsPublicKey = await jsPublicKeyFuture; try { - final byteBuffer = await web_crypto.deriveBits( - web_crypto.EcdhKeyDeriveParams( + final derivedBytes = await web_crypto.deriveBits( + web_crypto.DeriveParamsWhenPublicKey( name: 'ECDH'.toJS, public: jsPublicKey, ).jsObject, jsPrivateKey.jsPrivateKeyForEcdh!, (8 * length).toJS, ); - return SecretKey(Uint8List.view(byteBuffer)); + return SecretKey(derivedBytes); } catch (error, stackTrace) { throw StateError( 'Web Cryptography throw an error: $error\n$stackTrace', diff --git a/cryptography/lib/src/browser/ecdsa.dart b/cryptography/lib/src/browser/ecdsa.dart index 45e06544..739ba5c3 100644 --- a/cryptography/lib/src/browser/ecdsa.dart +++ b/cryptography/lib/src/browser/ecdsa.dart @@ -14,7 +14,6 @@ import 'dart:js_interop'; import 'dart:math'; -import 'dart:typed_data'; import 'package:cryptography/cryptography.dart'; @@ -94,7 +93,7 @@ class BrowserEcdsa extends Ecdsa { allowDeriveBits: true, ); final jsCryptoKey = browserEcKeyPair.jsPrivateKeyForEcdsa!; - final byteBuffer = await web_crypto.sign( + final signatureBytes = await web_crypto.sign( web_crypto.EcdsaParams( name: 'ECDSA'.toJS, hash: BrowserHashAlgorithmMixin.hashAlgorithmNameFor( @@ -106,7 +105,7 @@ class BrowserEcdsa extends Ecdsa { web_crypto.jsUint8ListFrom(message), ); return Signature( - Uint8List.view(byteBuffer), + signatureBytes, publicKey: await publicKeyFuture, ); } diff --git a/cryptography/lib/src/browser/hkdf.dart b/cryptography/lib/src/browser/hkdf.dart index 30834e37..7db5cd91 100644 --- a/cryptography/lib/src/browser/hkdf.dart +++ b/cryptography/lib/src/browser/hkdf.dart @@ -13,13 +13,12 @@ // limitations under the License. import 'dart:js_interop'; -import 'dart:typed_data'; import 'package:cryptography/cryptography.dart'; import 'package:cryptography/src/browser/hash.dart'; -import '_javascript_bindings.dart' show jsUint8ListFrom; import '_javascript_bindings.dart' as web_crypto; +import '_javascript_bindings.dart' show jsUint8ListFrom; /// HKDF implementation that uses _Web Cryptography API_ in browsers. /// @@ -49,7 +48,7 @@ class BrowserHkdf extends Hkdf { ); } final jsCryptoKey = await _jsCryptoKey(secretKey); - final byteBuffer = await web_crypto.deriveBits( + final bytes = await web_crypto.deriveBits( web_crypto.HkdfParams( name: 'HKDF'.toJS, hash: hashAlgorithmName.toJS, @@ -59,7 +58,7 @@ class BrowserHkdf extends Hkdf { jsCryptoKey, (8 * outputLength).toJS, ); - return SecretKeyData(Uint8List.view(byteBuffer)); + return SecretKeyData(bytes); } Future _jsCryptoKey(SecretKey secretKey) async { diff --git a/cryptography/lib/src/browser/hmac.dart b/cryptography/lib/src/browser/hmac.dart index ccc8278c..7a9dc313 100644 --- a/cryptography/lib/src/browser/hmac.dart +++ b/cryptography/lib/src/browser/hmac.dart @@ -13,7 +13,6 @@ // limitations under the License. import 'dart:js_interop'; -import 'dart:typed_data'; import 'package:cryptography/cryptography.dart'; @@ -56,12 +55,12 @@ class BrowserHmac extends Hmac { throw ArgumentError.value(aad, 'aad', 'AAD is unsupported by HMAC'); } final jsCryptoKey = await _jsCryptoKey(secretKey); - final byteBuffer = await web_crypto.sign( + final macBytes = await web_crypto.sign( 'HMAC'.toJS, jsCryptoKey, jsUint8ListFrom(bytes), ); - return Mac(Uint8List.view(byteBuffer)); + return Mac(macBytes); } Future _jsCryptoKey(SecretKey secretKey) async { diff --git a/cryptography/lib/src/browser/pbkdf2.dart b/cryptography/lib/src/browser/pbkdf2.dart index 7aa618cf..e8786e29 100644 --- a/cryptography/lib/src/browser/pbkdf2.dart +++ b/cryptography/lib/src/browser/pbkdf2.dart @@ -13,7 +13,6 @@ // limitations under the License. import 'dart:js_interop'; -import 'dart:typed_data'; import 'package:cryptography/cryptography.dart'; @@ -48,7 +47,7 @@ class BrowserPbkdf2 extends Pbkdf2 { final jsCryptoKey = await _jsCryptoKey(secretKey); // subtle.deriveBits(...) - final byteBuffer = await web_crypto.deriveBits( + final derivedBytes = await web_crypto.deriveBits( web_crypto.Pkdf2Params( name: 'PBKDF2'.toJS, hash: macAlgorithm.hashAlgorithmWebCryptoName.toJS, @@ -59,7 +58,7 @@ class BrowserPbkdf2 extends Pbkdf2 { bits.toJS, ); - return SecretKey(Uint8List.view(byteBuffer)); + return SecretKey(derivedBytes); } Future _jsCryptoKey(SecretKey secretKey) async { diff --git a/cryptography/lib/src/browser/rsa_pss.dart b/cryptography/lib/src/browser/rsa_pss.dart index ab9a3253..eb5c2e3e 100644 --- a/cryptography/lib/src/browser/rsa_pss.dart +++ b/cryptography/lib/src/browser/rsa_pss.dart @@ -107,7 +107,7 @@ class BrowserRsaPss extends RsaPss { webCryptoAlgorithm: _webCryptoAlgorithm, webCryptoHash: webCryptoHash, ); - final byteBuffer = await web_crypto.sign( + final signatureBytes = await web_crypto.sign( web_crypto.RsaPssParams( name: _webCryptoAlgorithm.toJS, saltLength: nonceLengthInBytes.toJS, @@ -116,7 +116,7 @@ class BrowserRsaPss extends RsaPss { Uint8List.fromList(message).toJS, ); return Signature( - Uint8List.view(byteBuffer), + signatureBytes, publicKey: await publicKeyFuture, ); } diff --git a/cryptography/lib/src/browser/rsa_ssa_pkcs1v15.dart b/cryptography/lib/src/browser/rsa_ssa_pkcs1v15.dart index 747338a2..b54e7b62 100644 --- a/cryptography/lib/src/browser/rsa_ssa_pkcs1v15.dart +++ b/cryptography/lib/src/browser/rsa_ssa_pkcs1v15.dart @@ -14,7 +14,6 @@ import 'dart:js_interop'; import 'dart:math'; -import 'dart:typed_data'; import 'package:cryptography/cryptography.dart'; @@ -95,13 +94,13 @@ class BrowserRsaSsaPkcs1v15 extends RsaSsaPkcs1v15 { webCryptoAlgorithm: _webCryptoAlgorithm, webCryptoHash: webCryptoHash, ); - final byteBuffer = await web_crypto.sign( + final signatureBytes = await web_crypto.sign( _webCryptoAlgorithm.toJS, jsCryptoKey, web_crypto.jsUint8ListFrom(message), ); return Signature( - Uint8List.view(byteBuffer), + signatureBytes, publicKey: await publicKeyFuture, ); } diff --git a/cryptography/lib/src/cryptography/algorithms.dart b/cryptography/lib/src/cryptography/algorithms.dart index cd8584bf..734b817e 100644 --- a/cryptography/lib/src/cryptography/algorithms.dart +++ b/cryptography/lib/src/cryptography/algorithms.dart @@ -622,6 +622,9 @@ abstract class Blake2b extends HashAlgorithm implements MacAlgorithm { /// Default value of [hashLengthInBytes] and [macLength]. static const int defaultHashLengthInBytes = 64; + @override + final int hashLengthInBytes; + factory Blake2b({ int hashLengthInBytes = defaultHashLengthInBytes, }) { @@ -639,27 +642,11 @@ abstract class Blake2b extends HashAlgorithm implements MacAlgorithm { }) : assert(hashLengthInBytes > 0), assert(hashLengthInBytes <= defaultHashLengthInBytes); - /// Enables you to replace [hashLengthInBytes]. - /// - /// Subclasses should replace this with their own implementation. - Blake2b replace({int? hashLength}) { - hashLength ??= hashLengthInBytes; - if (hashLength == hashLengthInBytes) { - return this; - } - return Blake2b( - hashLengthInBytes: hashLength, - ); - } + @override + int get blockLengthInBytes => 64; @override - void checkParameters({ - int? length, - required SecretKey secretKey, - required int nonceLength, - required int aadLength, - required int keyStreamIndex, - }) {} + int get hashCode => (Blake2b).hashCode; @override int get keyStreamUsed => 0; @@ -673,22 +660,30 @@ abstract class Blake2b extends HashAlgorithm implements MacAlgorithm { @override bool get supportsKeyStreamIndex => false; - @override - int get blockLengthInBytes => 64; - - @override - int get hashCode => (Blake2b).hashCode; - - @override - final int hashLengthInBytes; - @override bool operator ==(other) => other is Blake2b; @override - DartBlake2b toSync() => DartBlake2b( - hashLengthInBytes: hashLengthInBytes, - ); + void checkParameters({ + int? length, + required SecretKey secretKey, + required int nonceLength, + required int aadLength, + required int keyStreamIndex, + }) {} + + /// Enables you to replace [hashLengthInBytes]. + /// + /// Subclasses should replace this with their own implementation. + Blake2b replace({int? hashLength}) { + hashLength ??= hashLengthInBytes; + if (hashLength == hashLengthInBytes) { + return this; + } + return Blake2b( + hashLengthInBytes: hashLength, + ); + } @override String toString() { @@ -697,6 +692,11 @@ abstract class Blake2b extends HashAlgorithm implements MacAlgorithm { } return 'Blake2b(hashLengthInBytes: $hashLengthInBytes)'; } + + @override + DartBlake2b toSync() => DartBlake2b( + hashLengthInBytes: hashLengthInBytes, + ); } /// _BLAKE2S_ ([RFC 7693](https://tools.ietf.org/html/rfc7693)), which can be @@ -750,6 +750,9 @@ abstract class Blake2s extends HashAlgorithm implements MacAlgorithm { /// Default value of [hashLengthInBytes] and [macLength]. static const int defaultHashLengthInBytes = 32; + @override + final int hashLengthInBytes; + factory Blake2s({ int hashLengthInBytes = defaultHashLengthInBytes, }) { @@ -773,18 +776,6 @@ abstract class Blake2s extends HashAlgorithm implements MacAlgorithm { @override int get hashCode => (Blake2s).hashCode; - @override - final int hashLengthInBytes; - - @override - void checkParameters({ - int? length, - required SecretKey secretKey, - required int nonceLength, - required int aadLength, - required int keyStreamIndex, - }) {} - @override int get keyStreamUsed => 0; @@ -800,6 +791,15 @@ abstract class Blake2s extends HashAlgorithm implements MacAlgorithm { @override bool operator ==(other) => other is Blake2s; + @override + void checkParameters({ + int? length, + required SecretKey secretKey, + required int nonceLength, + required int aadLength, + required int keyStreamIndex, + }) {} + @override String toString() { if (hashLengthInBytes == defaultHashLengthInBytes) { @@ -1191,6 +1191,10 @@ abstract class Ed25519 extends SignatureAlgorithm { /// Constructor for classes that extend this class. const Ed25519.constructor({Random? random}) : _random = random; + @nonVirtual + @override + KeyPairType get keyPairType => KeyPairType.ed25519; + @override Future newKeyPair() { final seed = Uint8List(keyPairType.privateKeyLength); @@ -1203,6 +1207,30 @@ abstract class Ed25519 extends SignatureAlgorithm { @override String toString() => '$runtimeType()'; + + static void checkPrivateKeyLength(int length) { + if (length != 32) { + throw ArgumentError( + 'Private key must be 32 bytes (got $length bytes)', + ); + } + } + + static void checkPublicKeyLength(int length) { + if (length != 32) { + throw ArgumentError( + 'Public key must be 32 bytes (got $length bytes)', + ); + } + } + + static void checkSignatureLength(int length) { + if (length != 64) { + throw ArgumentError( + 'Signature must be 64 bytes (got $length bytes)', + ); + } + } } /// _Hchacha20_ ([draft-irtf-cfrg-xchacha](https://tools.ietf.org/html/draft-arciszewski-xchacha-03)) @@ -2193,6 +2221,10 @@ abstract class X25519 extends KeyExchangeAlgorithm { /// Constructor for classes that extend this class. const X25519.constructor({Random? random}) : _random = random; + @nonVirtual + @override + KeyPairType get keyPairType => KeyPairType.x25519; + @override Future newKeyPair() { final seed = Uint8List(keyPairType.privateKeyLength); diff --git a/cryptography/lib/src/cryptography/mac_algorithm.dart b/cryptography/lib/src/cryptography/mac_algorithm.dart index 1fdc1877..9db4bbd5 100644 --- a/cryptography/lib/src/cryptography/mac_algorithm.dart +++ b/cryptography/lib/src/cryptography/mac_algorithm.dart @@ -122,19 +122,11 @@ abstract class MacAlgorithm { List nonce = const [], List aad = const [], }) async { - final secretKeyBytes = await secretKey.extractBytes(); - if (secretKeyBytes.isEmpty) { - throw ArgumentError.value( - secretKey, - 'secretKey', - 'SecretKey bytes must be non-empty', - ); - } if (aad.isNotEmpty && !supportsAad) { throw ArgumentError.value( aad, 'aad', - 'AAD is not supported', + 'AAD is not supported by $runtimeType', ); } return _MacSink( diff --git a/cryptography/lib/src/dart/ed25519.dart b/cryptography/lib/src/dart/ed25519.dart index 23699661..5c89d709 100644 --- a/cryptography/lib/src/dart/ed25519.dart +++ b/cryptography/lib/src/dart/ed25519.dart @@ -32,9 +32,6 @@ class DartEd25519 extends Ed25519 { }) : _sha512 = sha512 ?? Sha512(), super.constructor(); - @override - KeyPairType get keyPairType => KeyPairType.ed25519; - @override Future newKeyPairFromSeed(List seed) async { if (seed.length != 32) { diff --git a/cryptography/lib/src/dart/x25519.dart b/cryptography/lib/src/dart/x25519.dart index 7b7175ea..6870e43f 100644 --- a/cryptography/lib/src/dart/x25519.dart +++ b/cryptography/lib/src/dart/x25519.dart @@ -42,9 +42,6 @@ class DartX25519 extends X25519 with DartKeyExchangeAlgorithmMixin { // Constant 121665 (0x1db41). const DartX25519({super.random}) : super.constructor(); - @override - KeyPairType get keyPairType => KeyPairType.x25519; - @override Future newKeyPairFromSeed(List seed) async { final modifiedBytes = DartX25519.modifiedPrivateKeyBytes(seed); diff --git a/cryptography_test/lib/algorithms/hmac.dart b/cryptography_test/lib/algorithms/hmac.dart index ff5ef23f..203214b7 100644 --- a/cryptography_test/lib/algorithms/hmac.dart +++ b/cryptography_test/lib/algorithms/hmac.dart @@ -28,11 +28,10 @@ void testHmac() { } void _testHmac(Hmac hmac) { - test('newSink(): empty key fails', () async { + test('newSink(): empty key is ok', () async { final secretKey = SecretKey([]); expect(await secretKey.extractBytes(), hasLength(0)); - final future = hmac.newMacSink(secretKey: secretKey); - await expectLater(future, throwsArgumentError); + await hmac.newMacSink(secretKey: secretKey); }); test('newSink(): closing twice is ok', () async { diff --git a/cryptography_test/lib/algorithms/x25519.dart b/cryptography_test/lib/algorithms/x25519.dart index 9eab1e43..3eb66fd1 100644 --- a/cryptography_test/lib/algorithms/x25519.dart +++ b/cryptography_test/lib/algorithms/x25519.dart @@ -24,176 +24,167 @@ import '../key_exchange.dart'; void testX25519() { testKeyExchangeAlgorithm( - builder: () { - return X25519(); - }, - otherTests: () { - _test(); - }, + builder: () => X25519(), + otherTests: _otherTests, ); } -void _test() { - group( - 'x25519:', - () { - test('information', () { - final algorithm = keyExchangeAlgorithm; - expect(algorithm.keyPairType, same(KeyPairType.x25519)); - expect(algorithm.keyPairType.name, 'x25519'); - expect(algorithm.keyPairType.publicKeyLength, 32); - }); - - test('1000 random key exchanges', () async { - final algorithm = X25519(); - for (var i = 0; i < 1000; i++) { - // Bob and Alice choose a random key pairs - final aliceKeyPair = await algorithm.newKeyPair(); - final alicePublicKey = await aliceKeyPair.extractPublicKey(); - - final bobKeyPair = await algorithm.newKeyPair(); - final bobPublicKey = await bobKeyPair.extractPublicKey(); - - // Alice calculates secret - final aliceShared = await algorithm.sharedSecretKey( +void _otherTests() { + test('information', () { + final algorithm = keyExchangeAlgorithm; + expect(algorithm.keyPairType, same(KeyPairType.x25519)); + expect(algorithm.keyPairType.name, 'x25519'); + expect(algorithm.keyPairType.publicKeyLength, 32); + }); + + test('1000 random key exchanges', () async { + final algorithm = X25519(); + for (var i = 0; i < 1000; i++) { + // Bob and Alice choose a random key pairs + final aliceKeyPair = await algorithm.newKeyPair(); + final alicePublicKey = await aliceKeyPair.extractPublicKey(); + + final bobKeyPair = await algorithm.newKeyPair(); + final bobPublicKey = await bobKeyPair.extractPublicKey(); + + // Alice calculates secret + final aliceShared = await algorithm.sharedSecretKey( + keyPair: aliceKeyPair, + remotePublicKey: bobPublicKey, + ); + final aliceSharedData = await aliceShared.extract(); + + // Bob calculates secret + final bobShared = await algorithm.sharedSecretKey( + keyPair: bobKeyPair, + remotePublicKey: alicePublicKey, + ); + final bobSharedData = await bobShared.extract(); + + // The secrets must be the same + expect( + hexFromBytes(aliceSharedData.bytes), + hexFromBytes(bobSharedData.bytes), + ); + } + + // This takes long time so skip the test in browsers. + }, testOn: 'vm', timeout: Timeout(const Duration(seconds: 120))); + + test('Test vectors from RFC 7748', () async { + final algorithm = X25519(); + + // The following constants are from RFC 7748: + // https://tools.ietf.org/html/rfc7748 + + final alicePrivateKeyBytes = hexToBytes( + '77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a', + ); + + final alicePublicKeyBytes = hexToBytes( + '8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a', + ); + + final bobPrivateKeyBytes = hexToBytes( + '5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb', + ); + + final bobPublicKeyBytes = hexToBytes( + 'de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f', + ); + + final sharedSecretBytes = hexToBytes( + '4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742', + ); + + // Test generating a key pair from seed (for Alice) + final aliceKeyPair = await algorithm.newKeyPairFromSeed( + alicePrivateKeyBytes, + ); + final aliceKeyPairData = await aliceKeyPair.extract(); + expect(aliceKeyPairData.type, KeyPairType.x25519); + expect( + aliceKeyPairData.bytes, + isNot(alicePrivateKeyBytes), + ); + expect( + aliceKeyPairData.bytes, + DartX25519.modifiedPrivateKeyBytes(alicePrivateKeyBytes), + ); + final alicePublicKey = await aliceKeyPair.extractPublicKey(); + expect(alicePublicKey.type, KeyPairType.x25519); + expect( + alicePublicKey.bytes, + alicePublicKeyBytes, + ); + + // Test generating a key pair from seed (for Bob) + final bobKeyPair = await algorithm.newKeyPairFromSeed( + bobPrivateKeyBytes, + ); + expect( + await bobKeyPair.extractPrivateKeyBytes(), + DartX25519.modifiedPrivateKeyBytes(bobPrivateKeyBytes), + ); + final bobPublicKey = await bobKeyPair.extractPublicKey(); + expect( + bobPublicKey.bytes, + bobPublicKeyBytes, + ); + + // Test generating a shared secret (for Alice) + expect( + await algorithm + .sharedSecretKey( keyPair: aliceKeyPair, remotePublicKey: bobPublicKey, - ); - final aliceSharedData = await aliceShared.extract(); - - // Bob calculates secret - final bobShared = await algorithm.sharedSecretKey( + ) + .then((value) => value.extractBytes()), + sharedSecretBytes, + ); + + // Test generating a shared secret (for Bob) + expect( + await algorithm + .sharedSecretKey( keyPair: bobKeyPair, remotePublicKey: alicePublicKey, - ); - final bobSharedData = await bobShared.extract(); - - // The secrets must be the same - expect( - hexFromBytes(aliceSharedData.bytes), - hexFromBytes(bobSharedData.bytes), - ); - } - - // This takes long time so skip the test in browsers. - }, testOn: 'vm', timeout: Timeout(const Duration(seconds: 120))); - - test('Test vectors from RFC 7748', () async { - final algorithm = X25519(); - - // The following constants are from RFC 7748: - // https://tools.ietf.org/html/rfc7748 - - final alicePrivateKeyBytes = hexToBytes( - '77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a', - ); - - final alicePublicKeyBytes = hexToBytes( - '8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a', - ); - - final bobPrivateKeyBytes = hexToBytes( - '5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb', - ); - - final bobPublicKeyBytes = hexToBytes( - 'de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f', - ); - - final sharedSecretBytes = hexToBytes( - '4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742', - ); - - // Test generating a key pair from seed (for Alice) - final aliceKeyPair = await algorithm.newKeyPairFromSeed( - alicePrivateKeyBytes, - ); - final aliceKeyPairData = await aliceKeyPair.extract(); - expect(aliceKeyPairData.type, KeyPairType.x25519); - expect( - aliceKeyPairData.bytes, - isNot(alicePrivateKeyBytes), - ); - expect( - aliceKeyPairData.bytes, - DartX25519.modifiedPrivateKeyBytes(alicePrivateKeyBytes), - ); - final alicePublicKey = await aliceKeyPair.extractPublicKey(); - expect(alicePublicKey.type, KeyPairType.x25519); - expect( - alicePublicKey.bytes, - alicePublicKeyBytes, - ); - - // Test generating a key pair from seed (for Bob) - final bobKeyPair = await algorithm.newKeyPairFromSeed( - bobPrivateKeyBytes, - ); - expect( - await bobKeyPair.extractPrivateKeyBytes(), - DartX25519.modifiedPrivateKeyBytes(bobPrivateKeyBytes), - ); - final bobPublicKey = await bobKeyPair.extractPublicKey(); - expect( - bobPublicKey.bytes, - bobPublicKeyBytes, - ); - - // Test generating a shared secret (for Alice) - expect( - await algorithm - .sharedSecretKey( - keyPair: aliceKeyPair, - remotePublicKey: bobPublicKey, - ) - .then((value) => value.extractBytes()), - sharedSecretBytes, - ); - - // Test generating a shared secret (for Bob) - expect( - await algorithm - .sharedSecretKey( - keyPair: bobKeyPair, - remotePublicKey: alicePublicKey, - ) - .then((value) => value.extractBytes()), - sharedSecretBytes, - ); - }); - - test('public key generation from seed with 10 000 cycles', () async { - final algorithm = X25519(); - const n = 10000; - - // Initial secret key - List input = Uint8List(32); - input[0] = 1; - - // 10 000 times - for (var i = 0; i < n; i++) { - // Generate a public key - final keyPair = await algorithm.newKeyPairFromSeed( - input, - ); - final publicKey = await keyPair.extractPublicKey(); - - // Use the output as the next input - input = publicKey.bytes; - } - - final expected = Uint8List.fromList([ - // Calculated with another implementation. - 138, 8, 200, 47, 95, 126, 210, 241, - 240, 215, 22, 64, 139, 230, 175, 228, - 225, 187, 38, 220, 231, 7, 114, 132, - 215, 244, 136, 80, 47, 52, 92, 15, - ]); - - expect(input, equals(expected)); - - // This takes long time so skip the test in browsers. - }, testOn: 'vm', timeout: Timeout(const Duration(seconds: 120))); - }, - ); + ) + .then((value) => value.extractBytes()), + sharedSecretBytes, + ); + }); + + test('public key generation from seed with 10 000 cycles', () async { + final algorithm = X25519(); + const n = 10000; + + // Initial secret key + List input = Uint8List(32); + input[0] = 1; + + // 10 000 times + for (var i = 0; i < n; i++) { + // Generate a public key + final keyPair = await algorithm.newKeyPairFromSeed( + input, + ); + final publicKey = await keyPair.extractPublicKey(); + + // Use the output as the next input + input = publicKey.bytes; + } + + final expected = Uint8List.fromList([ + // Calculated with another implementation. + 138, 8, 200, 47, 95, 126, 210, 241, + 240, 215, 22, 64, 139, 230, 175, 228, + 225, 187, 38, 220, 231, 7, 114, 132, + 215, 244, 136, 80, 47, 52, 92, 15, + ]); + + expect(input, equals(expected)); + + // This takes long time so skip the test in browsers. + }, testOn: 'vm', timeout: Timeout(const Duration(seconds: 120))); } diff --git a/cryptography_test/lib/cryptography_test.dart b/cryptography_test/lib/cryptography_testing.dart similarity index 100% rename from cryptography_test/lib/cryptography_test.dart rename to cryptography_test/lib/cryptography_testing.dart diff --git a/cryptography_test/test/main_test.dart b/cryptography_test/test/main_test.dart index 17da7dc3..3149045d 100644 --- a/cryptography_test/test/main_test.dart +++ b/cryptography_test/test/main_test.dart @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import 'package:cryptography_test/cryptography_test.dart'; +import 'package:cryptography_test/cryptography_testing.dart'; void main() { testCryptography();