import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; import 'package:bignum/bignum.dart'; import 'package:flx/signing.dart'; import 'package:pointycastle/pointycastle.dart' hide CipherParameters; import 'package:test/test.dart'; Future main() async { // The following constant was generated via the openssl shell commands: // openssl ecparam -genkey -name prime256v1 -out privatekey.pem // openssl ec -in privatekey.pem -outform DER | base64 const String kPrivateKeyBase64 = 'MHcCAQEEIG4Xt+MgsdP/o89kAHz7EVVLKkN+DUfpaBtZfMyFGbUgoAoGCCqGSM49AwEHoUQDQgAElPtbBVPPqKHYXYAgHaxB2hL6sXeFc99YLijTAuAPe2Nbhywan+v4k+nFm0TJJW/mkV+nH+fyBZ98t4UcFCqkOg=='; final List kPrivateKeyDER = BASE64.decode(kPrivateKeyBase64); // Unpacked values of the above private key. const int kPrivateKeyD = 0x6e17b7e320b1d3ffa3cf64007cfb11554b2a437e0d47e9681b597ccc8519b520; const int kPublicKeyQx = 0x94fb5b0553cfa8a1d85d80201dac41da12fab1778573df582e28d302e00f7b63; const int kPublicKeyQy = 0x5b872c1a9febf893e9c59b44c9256fe6915fa71fe7f2059f7cb7851c142aa43a; // Test manifest. final Map kManifest = { 'name': 'test app', 'version': '1.0.0' }; // Simple test byte pattern (flat and in chunked form) and its SHA-256 hash. final Uint8List kTestBytes = new Uint8List.fromList([1, 2, 3]); final List kTestBytesList = [ new Uint8List.fromList([1, 2]), new Uint8List.fromList([3])]; final int kTestHash = 0x039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81; // Set up a key generator. CipherParameters cipher = CipherParameters.get(); cipher.seedRandom(); ECKeyGeneratorParameters ecParams = new ECKeyGeneratorParameters(cipher.domain); ParametersWithRandom keyGeneratorParams = new ParametersWithRandom(ecParams, cipher.random); KeyGenerator keyGenerator = new KeyGenerator('EC'); keyGenerator.init(keyGeneratorParams); test('can read openssl key pair', () { AsymmetricKeyPair keyPair = keyPairFromPrivateKeyBytes(kPrivateKeyDER); expect(keyPair != null, equals(true)); ECPrivateKey keyPairPrivateKey = keyPair.privateKey; ECPublicKey keyPairPublicKey = keyPair.publicKey; expect(keyPairPrivateKey.d.intValue(), equals(kPrivateKeyD)); expect(keyPairPublicKey.Q.x.toBigInteger().intValue(), equals(kPublicKeyQx)); expect(keyPairPublicKey.Q.y.toBigInteger().intValue(), equals(kPublicKeyQy)); }); test('serializeManifest adds key and content-hash', () { AsymmetricKeyPair keyPair = keyPairFromPrivateKeyBytes(kPrivateKeyDER); ECPublicKey keyPairPublicKey = keyPair.publicKey; Uint8List manifestBytes = serializeManifest(kManifest, keyPairPublicKey, kTestBytes); Map decodedManifest = JSON.decode(UTF8.decode(manifestBytes)); String expectedKey = BASE64.encode(keyPairPublicKey.Q.getEncoded()); expect(decodedManifest != null, equals(true)); expect(decodedManifest['name'], equals(kManifest['name'])); expect(decodedManifest['version'], equals(kManifest['version'])); expect(decodedManifest['key'], equals(expectedKey)); expect(decodedManifest['content-hash'], equals(kTestHash)); }); test('signManifest and verifyManifestSignature work', () { AsymmetricKeyPair keyPair = keyPairFromPrivateKeyBytes(kPrivateKeyDER); ECPrivateKey keyPairPrivateKey = keyPair.privateKey; ECPublicKey keyPairPublicKey = keyPair.publicKey; Map manifest = JSON.decode(UTF8.decode( serializeManifest(kManifest, keyPairPublicKey, kTestBytes)) ); Uint8List signatureBytes = signManifest(kTestBytes, keyPairPrivateKey); bool verifies = verifyManifestSignature(manifest, kTestBytes, signatureBytes); expect(verifies, equals(true)); // Ensure it fails with invalid signature or content. Uint8List badBytes = new Uint8List.fromList([42]); verifies = verifyManifestSignature(manifest, kTestBytes, badBytes); expect(verifies, equals(false)); verifies = verifyManifestSignature(manifest, badBytes, signatureBytes); expect(verifies, equals(false)); }); test('signing works with arbitrary key', () { AsymmetricKeyPair keyPair = keyGenerator.generateKeyPair(); ECPrivateKey keyPairPrivateKey = keyPair.privateKey; ECPublicKey keyPairPublicKey = keyPair.publicKey; String failReason = 'offending private key: ${keyPairPrivateKey.d}'; Map manifest = JSON.decode(UTF8.decode( serializeManifest(kManifest, keyPairPublicKey, kTestBytes)) ); Uint8List signatureBytes = signManifest(kTestBytes, keyPairPrivateKey); bool verifies = verifyManifestSignature(manifest, kTestBytes, signatureBytes); expect(verifies, equals(true), reason: failReason); // Ensure it fails with invalid signature or content. Uint8List badBytes = new Uint8List.fromList([42]); verifies = verifyManifestSignature(manifest, kTestBytes, badBytes); expect(verifies, equals(false), reason: failReason); verifies = verifyManifestSignature(manifest, badBytes, signatureBytes); expect(verifies, equals(false), reason: failReason); }); test('verifyContentHash works', () async { Stream contentStream = new Stream.fromIterable(kTestBytesList); bool verifies = await verifyContentHash(new BigInteger(kTestHash), contentStream); expect(verifies, equals(true)); // Ensure it fails with invalid hash or content. contentStream = new Stream.fromIterable(kTestBytesList); verifies = await verifyContentHash(new BigInteger(0xdeadbeef), contentStream); expect(verifies, equals(false)); Stream badContentStream = new Stream.fromIterable( [new Uint8List.fromList([42])] ); verifies = await verifyContentHash(new BigInteger(kTestHash), badContentStream); expect(verifies, equals(false)); }); }