Commit d74a7517 authored by Matt Perry's avatar Matt Perry

flx: Support for seeding the RNG for package signing.

Add a test for signing/verifying with a random generated key pair.
parent f962c0fc
...@@ -20,25 +20,38 @@ class CipherParameters { ...@@ -20,25 +20,38 @@ class CipherParameters {
final String signerAlgorithm = 'SHA-256/ECDSA'; final String signerAlgorithm = 'SHA-256/ECDSA';
final String hashAlgorithm = 'SHA-256'; final String hashAlgorithm = 'SHA-256';
final ECDomainParameters domain = new ECDomainParameters('prime256v1'); final ECDomainParameters domain = new ECDomainParameters('prime256v1');
final SecureRandom random = _initRandom(); SecureRandom get random {
} if (_random == null)
_initRandom(new Uint8List(16), new Uint8List(16));
return _random;
}
SecureRandom _initRandom() { // Seeds our secure random number generator using data from /dev/urandom.
// TODO(mpcomplete): Provide a better seed here. External entropy source? // Disclaimer: I don't really understand why we need 2 parameters for
final Uint8List key = new Uint8List(16); // cipher's API.
final KeyParameter keyParam = new KeyParameter(key); Future seedRandom() async {
final ParametersWithIV params = new ParametersWithIV(keyParam, new Uint8List(16)); RandomAccessFile file = await new File("/dev/urandom").open();
SecureRandom random = new SecureRandom('AES/CTR/AUTO-SEED-PRNG') Uint8List key = new Uint8List.fromList(await file.read(16));
..seed(params); Uint8List iv = new Uint8List.fromList(await file.read(16));
return random; _initRandom(key, iv);
} }
CipherParameters _initParams() { SecureRandom _random;
initCipher(); void _initRandom(Uint8List key, Uint8List iv) {
return new CipherParameters(); KeyParameter keyParam = new KeyParameter(key);
ParametersWithIV params = new ParametersWithIV(keyParam, iv);
_random = new SecureRandom('AES/CTR/AUTO-SEED-PRNG')
..seed(params);
}
static CipherParameters get() => _params;
static CipherParameters _init() {
initCipher();
return new CipherParameters();
}
} }
final CipherParameters _params = _initParams(); final CipherParameters _params = CipherParameters._init();
// Returns a serialized manifest, with the public key and hash of the content // Returns a serialized manifest, with the public key and hash of the content
// included. // included.
......
name: flx name: flx
version: 0.0.6 version: 0.0.7
author: Flutter Authors <flutter-dev@googlegroups.com> author: Flutter Authors <flutter-dev@googlegroups.com>
description: Library for dealing with Flutter bundle (.flx) files description: Library for dealing with Flutter bundle (.flx) files
homepage: http://flutter.io homepage: http://flutter.io
......
...@@ -6,8 +6,9 @@ import 'package:bignum/bignum.dart'; ...@@ -6,8 +6,9 @@ import 'package:bignum/bignum.dart';
import 'package:flx/signing.dart'; import 'package:flx/signing.dart';
import 'package:quiver/testing/async.dart'; import 'package:quiver/testing/async.dart';
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:cipher/cipher.dart' hide CipherParameters;
void main() { main() async {
// The following constant was generated via the openssl shell commands: // The following constant was generated via the openssl shell commands:
// openssl ecparam -genkey -name prime256v1 -out privatekey.pem // openssl ecparam -genkey -name prime256v1 -out privatekey.pem
// openssl ec -in privatekey.pem -outform DER | base64 // openssl ec -in privatekey.pem -outform DER | base64
...@@ -31,6 +32,15 @@ void main() { ...@@ -31,6 +32,15 @@ void main() {
new Uint8List.fromList(<int>[1, 2]), new Uint8List.fromList(<int>[3])]; new Uint8List.fromList(<int>[1, 2]), new Uint8List.fromList(<int>[3])];
final int kTestHash = 0x039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81; final int kTestHash = 0x039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81;
// Set up a key generator.
CipherParameters cipher = CipherParameters.get();
await cipher.seedRandom();
ECKeyGeneratorParameters ecParams = new ECKeyGeneratorParameters(cipher.domain);
ParametersWithRandom<ECKeyGeneratorParameters> keyGeneratorParams =
new ParametersWithRandom<ECKeyGeneratorParameters>(ecParams, cipher.random);
KeyGenerator keyGenerator = new KeyGenerator('EC');
keyGenerator.init(keyGeneratorParams);
test('can read openssl key pair', () { test('can read openssl key pair', () {
AsymmetricKeyPair keyPair = keyPairFromPrivateKeyBytes(kPrivateKeyDER); AsymmetricKeyPair keyPair = keyPairFromPrivateKeyBytes(kPrivateKeyDER);
expect(keyPair != null, equals(true)); expect(keyPair != null, equals(true));
...@@ -68,6 +78,24 @@ void main() { ...@@ -68,6 +78,24 @@ void main() {
expect(verifies, equals(false)); expect(verifies, equals(false));
}); });
test('signing works with arbitrary key', () {
AsymmetricKeyPair keyPair = keyGenerator.generateKeyPair();
String failReason = 'offending private key: ${keyPair.privateKey.d}';
Map<String, dynamic> manifest = JSON.decode(UTF8.decode(
serializeManifest(kManifest, keyPair.publicKey, kTestBytes)));
Uint8List signatureBytes = signManifest(kTestBytes, keyPair.privateKey);
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(<int>[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', () { test('verifyContentHash works', () {
new FakeAsync().run((FakeAsync async) { new FakeAsync().run((FakeAsync async) {
bool verifies; bool verifies;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment