mirror of
https://github.com/flutter/flutter
synced 2024-10-13 03:32:55 +00:00
Change signing code to use shared flx package.
This commit is contained in:
parent
b7f918c92b
commit
828b861fce
|
@ -7,11 +7,10 @@ import 'dart:io';
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:archive/archive.dart';
|
||||
import 'package:cipher/cipher.dart';
|
||||
import 'package:cipher/impl/client.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import '../signing.dart';
|
||||
import 'package:flx/bundle.dart';
|
||||
import 'package:flx/signing.dart';
|
||||
import '../toolchain.dart';
|
||||
import 'flutter_command.dart';
|
||||
|
||||
|
@ -100,16 +99,6 @@ ArchiveFile _createFile(String key, String assetBase) {
|
|||
return new ArchiveFile.noCompress(key, content.length, content);
|
||||
}
|
||||
|
||||
// Writes a 32-bit length followed by the content of [bytes].
|
||||
void _writeBytesWithLength(File outputFile, List<int> bytes) {
|
||||
if (bytes == null)
|
||||
bytes = new Uint8List(0);
|
||||
assert(bytes.length < 0xffffffff);
|
||||
ByteData length = new ByteData(4)..setUint32(0, bytes.length, Endianness.LITTLE_ENDIAN);
|
||||
outputFile.writeAsBytesSync(length.buffer.asUint8List(), mode: FileMode.APPEND);
|
||||
outputFile.writeAsBytesSync(bytes, mode: FileMode.APPEND);
|
||||
}
|
||||
|
||||
ArchiveFile _createSnapshotFile(String snapshotPath) {
|
||||
File file = new File(snapshotPath);
|
||||
List<int> content = file.readAsBytesSync();
|
||||
|
@ -139,7 +128,6 @@ class BuildCommand extends FlutterCommand {
|
|||
|
||||
@override
|
||||
Future<int> run() async {
|
||||
initCipher();
|
||||
String compilerPath = argResults['compiler'];
|
||||
|
||||
if (compilerPath == null)
|
||||
|
@ -193,16 +181,15 @@ class BuildCommand extends FlutterCommand {
|
|||
archive.addFile(file);
|
||||
}
|
||||
|
||||
ECPrivateKey privateKey = await loadPrivateKey(privateKeyPath);
|
||||
ECPublicKey publicKey = publicKeyFromPrivateKey(privateKey);
|
||||
|
||||
File outputFile = new File(outputPath);
|
||||
outputFile.writeAsStringSync('#!mojo mojo:sky_viewer\n');
|
||||
KeyPair keyPair = KeyPair.readFromPrivateKeySync(privateKeyPath);
|
||||
Uint8List zipBytes = new Uint8List.fromList(new ZipEncoder().encode(archive));
|
||||
Uint8List manifestBytes = serializeManifest(manifestDescriptor, publicKey, zipBytes);
|
||||
_writeBytesWithLength(outputFile, signManifest(manifestBytes, privateKey));
|
||||
_writeBytesWithLength(outputFile, manifestBytes);
|
||||
outputFile.writeAsBytesSync(zipBytes, mode: FileMode.APPEND, flush: true);
|
||||
Bundle bundle = new Bundle.fromContent(
|
||||
path: outputPath,
|
||||
manifest: manifestDescriptor,
|
||||
contentBytes: zipBytes,
|
||||
keyPair: keyPair
|
||||
);
|
||||
bundle.writeSync();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:asn1lib/asn1lib.dart';
|
||||
import 'package:bignum/bignum.dart';
|
||||
import 'package:cipher/cipher.dart';
|
||||
|
||||
// The ECDSA algorithm parameters we're using. These match the parameters used
|
||||
// by the Flutter updater package.
|
||||
final ECDomainParameters _ecDomain = new ECDomainParameters('prime256v1');
|
||||
final String kSignerAlgorithm = 'SHA-256/ECDSA';
|
||||
final String kHashAlgorithm = 'SHA-256';
|
||||
|
||||
final SecureRandom _random = _initRandom();
|
||||
|
||||
SecureRandom _initRandom() {
|
||||
// TODO(mpcomplete): Provide a better seed here. External entropy source?
|
||||
final Uint8List key = new Uint8List(16);
|
||||
final KeyParameter keyParam = new KeyParameter(key);
|
||||
final ParametersWithIV params = new ParametersWithIV(keyParam, new Uint8List(16));
|
||||
SecureRandom random = new SecureRandom('AES/CTR/AUTO-SEED-PRNG')
|
||||
..seed(params);
|
||||
return random;
|
||||
}
|
||||
|
||||
// Returns a serialized manifest, with the public key and hash of the content
|
||||
// included.
|
||||
Uint8List serializeManifest(Map manifestDescriptor, ECPublicKey publicKey, Uint8List zipBytes) {
|
||||
if (manifestDescriptor == null)
|
||||
return null;
|
||||
final List<String> kSavedKeys = [
|
||||
'name',
|
||||
'version',
|
||||
'update-url'
|
||||
];
|
||||
Map outputManifest = new Map();
|
||||
manifestDescriptor.forEach((key, value) {
|
||||
if (kSavedKeys.contains(key))
|
||||
outputManifest[key] = value;
|
||||
});
|
||||
|
||||
if (publicKey != null)
|
||||
outputManifest['key'] = BASE64.encode(publicKey.Q.getEncoded());
|
||||
|
||||
Uint8List zipHash = new Digest(kHashAlgorithm).process(zipBytes);
|
||||
BigInteger zipHashInt = new BigInteger.fromBytes(1, zipHash);
|
||||
outputManifest['content-hash'] = zipHashInt.intValue();
|
||||
|
||||
return new Uint8List.fromList(UTF8.encode(JSON.encode(outputManifest)));
|
||||
}
|
||||
|
||||
// Returns the ASN.1 encoded signature of the input manifestBytes.
|
||||
List<int> signManifest(Uint8List manifestBytes, ECPrivateKey privateKey) {
|
||||
if (manifestBytes == null || privateKey == null)
|
||||
return [];
|
||||
Signer signer = new Signer(kSignerAlgorithm);
|
||||
PrivateKeyParameter params = new PrivateKeyParameter(privateKey);
|
||||
signer.init(true, new ParametersWithRandom(params, _random));
|
||||
ECSignature signature = signer.generateSignature(manifestBytes);
|
||||
ASN1Sequence asn1 = new ASN1Sequence()
|
||||
..add(new ASN1Integer(signature.r))
|
||||
..add(new ASN1Integer(signature.s));
|
||||
return asn1.encodedBytes;
|
||||
}
|
||||
|
||||
ECPrivateKey _asn1ParsePrivateKey(ECDomainParameters ecDomain, Uint8List privateKey) {
|
||||
ASN1Parser parser = new ASN1Parser(privateKey);
|
||||
ASN1Sequence seq = parser.nextObject();
|
||||
assert(seq.elements.length >= 2);
|
||||
ASN1OctetString keyOct = seq.elements[1];
|
||||
BigInteger d = new BigInteger.fromBytes(1, keyOct.octets);
|
||||
return new ECPrivateKey(d, ecDomain);
|
||||
}
|
||||
|
||||
Future<ECPrivateKey> loadPrivateKey(String privateKeyPath) async {
|
||||
File file = new File(privateKeyPath);
|
||||
if (!file.existsSync())
|
||||
return null;
|
||||
List<int> bytes = file.readAsBytesSync();
|
||||
return _asn1ParsePrivateKey(_ecDomain, new Uint8List.fromList(bytes));
|
||||
}
|
||||
|
||||
ECPublicKey publicKeyFromPrivateKey(ECPrivateKey privateKey) {
|
||||
if (privateKey == null)
|
||||
return null;
|
||||
ECPoint Q = privateKey.parameters.G * privateKey.d;
|
||||
return new ECPublicKey(Q, privateKey.parameters);
|
||||
}
|
|
@ -12,6 +12,7 @@ dependencies:
|
|||
args: ^0.13.0
|
||||
asn1lib: ^0.4.1
|
||||
cipher: ^0.7.1
|
||||
flx: ^0.0.1
|
||||
crypto: ^0.9.1
|
||||
mustache4dart: ^1.0.0
|
||||
path: ^1.3.0
|
||||
|
|
Loading…
Reference in a new issue