1*9e94795aSAndroid Build Coastguard Worker /* 2*9e94795aSAndroid Build Coastguard Worker * Copyright 2014 The Android Open Source Project 3*9e94795aSAndroid Build Coastguard Worker * 4*9e94795aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*9e94795aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*9e94795aSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*9e94795aSAndroid Build Coastguard Worker * 8*9e94795aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*9e94795aSAndroid Build Coastguard Worker * 10*9e94795aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*9e94795aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*9e94795aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*9e94795aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*9e94795aSAndroid Build Coastguard Worker * limitations under the License. 15*9e94795aSAndroid Build Coastguard Worker */ 16*9e94795aSAndroid Build Coastguard Worker 17*9e94795aSAndroid Build Coastguard Worker package com.android.signtos; 18*9e94795aSAndroid Build Coastguard Worker 19*9e94795aSAndroid Build Coastguard Worker import org.bouncycastle.asn1.ASN1InputStream; 20*9e94795aSAndroid Build Coastguard Worker import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; 21*9e94795aSAndroid Build Coastguard Worker import org.bouncycastle.jce.provider.BouncyCastleProvider; 22*9e94795aSAndroid Build Coastguard Worker 23*9e94795aSAndroid Build Coastguard Worker import java.io.BufferedInputStream; 24*9e94795aSAndroid Build Coastguard Worker import java.io.BufferedOutputStream; 25*9e94795aSAndroid Build Coastguard Worker import java.io.BufferedReader; 26*9e94795aSAndroid Build Coastguard Worker import java.io.ByteArrayInputStream; 27*9e94795aSAndroid Build Coastguard Worker import java.io.DataInputStream; 28*9e94795aSAndroid Build Coastguard Worker import java.io.File; 29*9e94795aSAndroid Build Coastguard Worker import java.io.FileInputStream; 30*9e94795aSAndroid Build Coastguard Worker import java.io.FileOutputStream; 31*9e94795aSAndroid Build Coastguard Worker import java.io.IOException; 32*9e94795aSAndroid Build Coastguard Worker import java.io.InputStream; 33*9e94795aSAndroid Build Coastguard Worker import java.io.InputStreamReader; 34*9e94795aSAndroid Build Coastguard Worker import java.io.OutputStream; 35*9e94795aSAndroid Build Coastguard Worker import java.lang.reflect.Constructor; 36*9e94795aSAndroid Build Coastguard Worker import java.security.GeneralSecurityException; 37*9e94795aSAndroid Build Coastguard Worker import java.security.Key; 38*9e94795aSAndroid Build Coastguard Worker import java.security.KeyFactory; 39*9e94795aSAndroid Build Coastguard Worker import java.security.MessageDigest; 40*9e94795aSAndroid Build Coastguard Worker import java.security.PrivateKey; 41*9e94795aSAndroid Build Coastguard Worker import java.security.Provider; 42*9e94795aSAndroid Build Coastguard Worker import java.security.PublicKey; 43*9e94795aSAndroid Build Coastguard Worker import java.security.Security; 44*9e94795aSAndroid Build Coastguard Worker import java.security.Signature; 45*9e94795aSAndroid Build Coastguard Worker import java.security.interfaces.ECKey; 46*9e94795aSAndroid Build Coastguard Worker import java.security.interfaces.ECPublicKey; 47*9e94795aSAndroid Build Coastguard Worker import java.security.spec.InvalidKeySpecException; 48*9e94795aSAndroid Build Coastguard Worker import java.security.spec.PKCS8EncodedKeySpec; 49*9e94795aSAndroid Build Coastguard Worker import java.util.Arrays; 50*9e94795aSAndroid Build Coastguard Worker 51*9e94795aSAndroid Build Coastguard Worker import javax.crypto.Cipher; 52*9e94795aSAndroid Build Coastguard Worker import javax.crypto.EncryptedPrivateKeyInfo; 53*9e94795aSAndroid Build Coastguard Worker import javax.crypto.SecretKeyFactory; 54*9e94795aSAndroid Build Coastguard Worker import javax.crypto.spec.PBEKeySpec; 55*9e94795aSAndroid Build Coastguard Worker 56*9e94795aSAndroid Build Coastguard Worker /** 57*9e94795aSAndroid Build Coastguard Worker * Signs Trusty images for use with operating systems that support it. 58*9e94795aSAndroid Build Coastguard Worker */ 59*9e94795aSAndroid Build Coastguard Worker public class SignTos { 60*9e94795aSAndroid Build Coastguard Worker /** Size of the signature footer in bytes. */ 61*9e94795aSAndroid Build Coastguard Worker private static final int SIGNATURE_BLOCK_SIZE = 256; 62*9e94795aSAndroid Build Coastguard Worker 63*9e94795aSAndroid Build Coastguard Worker /** Current signature version code we use. */ 64*9e94795aSAndroid Build Coastguard Worker private static final int VERSION_CODE = 1; 65*9e94795aSAndroid Build Coastguard Worker 66*9e94795aSAndroid Build Coastguard Worker /** Size of the header on the file to skip. */ 67*9e94795aSAndroid Build Coastguard Worker private static final int HEADER_SIZE = 512; 68*9e94795aSAndroid Build Coastguard Worker 69*9e94795aSAndroid Build Coastguard Worker private static BouncyCastleProvider sBouncyCastleProvider; 70*9e94795aSAndroid Build Coastguard Worker 71*9e94795aSAndroid Build Coastguard Worker /** 72*9e94795aSAndroid Build Coastguard Worker * Reads the password from stdin and returns it as a string. 73*9e94795aSAndroid Build Coastguard Worker * 74*9e94795aSAndroid Build Coastguard Worker * @param keyFile The file containing the private key. Used to prompt the user. 75*9e94795aSAndroid Build Coastguard Worker */ readPassword(File keyFile)76*9e94795aSAndroid Build Coastguard Worker private static String readPassword(File keyFile) { 77*9e94795aSAndroid Build Coastguard Worker // TODO: use Console.readPassword() when it's available. 78*9e94795aSAndroid Build Coastguard Worker System.out.print("Enter password for " + keyFile + " (password will not be hidden): "); 79*9e94795aSAndroid Build Coastguard Worker System.out.flush(); 80*9e94795aSAndroid Build Coastguard Worker BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); 81*9e94795aSAndroid Build Coastguard Worker try { 82*9e94795aSAndroid Build Coastguard Worker return stdin.readLine(); 83*9e94795aSAndroid Build Coastguard Worker } catch (IOException ex) { 84*9e94795aSAndroid Build Coastguard Worker return null; 85*9e94795aSAndroid Build Coastguard Worker } 86*9e94795aSAndroid Build Coastguard Worker } 87*9e94795aSAndroid Build Coastguard Worker 88*9e94795aSAndroid Build Coastguard Worker /** 89*9e94795aSAndroid Build Coastguard Worker * Decrypt an encrypted PKCS#8 format private key. 90*9e94795aSAndroid Build Coastguard Worker * 91*9e94795aSAndroid Build Coastguard Worker * Based on ghstark's post on Aug 6, 2006 at 92*9e94795aSAndroid Build Coastguard Worker * http://forums.sun.com/thread.jspa?threadID=758133&messageID=4330949 93*9e94795aSAndroid Build Coastguard Worker * 94*9e94795aSAndroid Build Coastguard Worker * @param encryptedPrivateKey The raw data of the private key 95*9e94795aSAndroid Build Coastguard Worker * @param keyFile The file containing the private key 96*9e94795aSAndroid Build Coastguard Worker */ decryptPrivateKey(byte[] encryptedPrivateKey, File keyFile)97*9e94795aSAndroid Build Coastguard Worker private static PKCS8EncodedKeySpec decryptPrivateKey(byte[] encryptedPrivateKey, File keyFile) 98*9e94795aSAndroid Build Coastguard Worker throws GeneralSecurityException { 99*9e94795aSAndroid Build Coastguard Worker EncryptedPrivateKeyInfo epkInfo; 100*9e94795aSAndroid Build Coastguard Worker try { 101*9e94795aSAndroid Build Coastguard Worker epkInfo = new EncryptedPrivateKeyInfo(encryptedPrivateKey); 102*9e94795aSAndroid Build Coastguard Worker } catch (IOException ex) { 103*9e94795aSAndroid Build Coastguard Worker // Probably not an encrypted key. 104*9e94795aSAndroid Build Coastguard Worker return null; 105*9e94795aSAndroid Build Coastguard Worker } 106*9e94795aSAndroid Build Coastguard Worker 107*9e94795aSAndroid Build Coastguard Worker char[] password = readPassword(keyFile).toCharArray(); 108*9e94795aSAndroid Build Coastguard Worker 109*9e94795aSAndroid Build Coastguard Worker SecretKeyFactory skFactory = SecretKeyFactory.getInstance(epkInfo.getAlgName()); 110*9e94795aSAndroid Build Coastguard Worker Key key = skFactory.generateSecret(new PBEKeySpec(password)); 111*9e94795aSAndroid Build Coastguard Worker 112*9e94795aSAndroid Build Coastguard Worker Cipher cipher = Cipher.getInstance(epkInfo.getAlgName()); 113*9e94795aSAndroid Build Coastguard Worker cipher.init(Cipher.DECRYPT_MODE, key, epkInfo.getAlgParameters()); 114*9e94795aSAndroid Build Coastguard Worker 115*9e94795aSAndroid Build Coastguard Worker try { 116*9e94795aSAndroid Build Coastguard Worker return epkInfo.getKeySpec(cipher); 117*9e94795aSAndroid Build Coastguard Worker } catch (InvalidKeySpecException ex) { 118*9e94795aSAndroid Build Coastguard Worker System.err.println("signapk: Password for " + keyFile + " may be bad."); 119*9e94795aSAndroid Build Coastguard Worker throw ex; 120*9e94795aSAndroid Build Coastguard Worker } 121*9e94795aSAndroid Build Coastguard Worker } 122*9e94795aSAndroid Build Coastguard Worker 123*9e94795aSAndroid Build Coastguard Worker /** Read a PKCS#8 format private key. */ readPrivateKey(File file)124*9e94795aSAndroid Build Coastguard Worker private static PrivateKey readPrivateKey(File file) throws IOException, 125*9e94795aSAndroid Build Coastguard Worker GeneralSecurityException { 126*9e94795aSAndroid Build Coastguard Worker DataInputStream input = new DataInputStream(new FileInputStream(file)); 127*9e94795aSAndroid Build Coastguard Worker try { 128*9e94795aSAndroid Build Coastguard Worker byte[] bytes = new byte[(int) file.length()]; 129*9e94795aSAndroid Build Coastguard Worker input.read(bytes); 130*9e94795aSAndroid Build Coastguard Worker 131*9e94795aSAndroid Build Coastguard Worker /* Check to see if this is in an EncryptedPrivateKeyInfo structure. */ 132*9e94795aSAndroid Build Coastguard Worker PKCS8EncodedKeySpec spec = decryptPrivateKey(bytes, file); 133*9e94795aSAndroid Build Coastguard Worker if (spec == null) { 134*9e94795aSAndroid Build Coastguard Worker spec = new PKCS8EncodedKeySpec(bytes); 135*9e94795aSAndroid Build Coastguard Worker } 136*9e94795aSAndroid Build Coastguard Worker 137*9e94795aSAndroid Build Coastguard Worker /* 138*9e94795aSAndroid Build Coastguard Worker * Now it's in a PKCS#8 PrivateKeyInfo structure. Read its Algorithm 139*9e94795aSAndroid Build Coastguard Worker * OID and use that to construct a KeyFactory. 140*9e94795aSAndroid Build Coastguard Worker */ 141*9e94795aSAndroid Build Coastguard Worker ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(spec.getEncoded())); 142*9e94795aSAndroid Build Coastguard Worker PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject()); 143*9e94795aSAndroid Build Coastguard Worker String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId(); 144*9e94795aSAndroid Build Coastguard Worker 145*9e94795aSAndroid Build Coastguard Worker return KeyFactory.getInstance(algOid).generatePrivate(spec); 146*9e94795aSAndroid Build Coastguard Worker } finally { 147*9e94795aSAndroid Build Coastguard Worker input.close(); 148*9e94795aSAndroid Build Coastguard Worker } 149*9e94795aSAndroid Build Coastguard Worker } 150*9e94795aSAndroid Build Coastguard Worker 151*9e94795aSAndroid Build Coastguard Worker /** 152*9e94795aSAndroid Build Coastguard Worker * Tries to load a JSE Provider by class name. This is for custom PrivateKey 153*9e94795aSAndroid Build Coastguard Worker * types that might be stored in PKCS#11-like storage. 154*9e94795aSAndroid Build Coastguard Worker */ loadProviderIfNecessary(String providerClassName)155*9e94795aSAndroid Build Coastguard Worker private static void loadProviderIfNecessary(String providerClassName) { 156*9e94795aSAndroid Build Coastguard Worker if (providerClassName == null) { 157*9e94795aSAndroid Build Coastguard Worker return; 158*9e94795aSAndroid Build Coastguard Worker } 159*9e94795aSAndroid Build Coastguard Worker 160*9e94795aSAndroid Build Coastguard Worker final Class<?> klass; 161*9e94795aSAndroid Build Coastguard Worker try { 162*9e94795aSAndroid Build Coastguard Worker final ClassLoader sysLoader = ClassLoader.getSystemClassLoader(); 163*9e94795aSAndroid Build Coastguard Worker if (sysLoader != null) { 164*9e94795aSAndroid Build Coastguard Worker klass = sysLoader.loadClass(providerClassName); 165*9e94795aSAndroid Build Coastguard Worker } else { 166*9e94795aSAndroid Build Coastguard Worker klass = Class.forName(providerClassName); 167*9e94795aSAndroid Build Coastguard Worker } 168*9e94795aSAndroid Build Coastguard Worker } catch (ClassNotFoundException e) { 169*9e94795aSAndroid Build Coastguard Worker e.printStackTrace(); 170*9e94795aSAndroid Build Coastguard Worker System.exit(1); 171*9e94795aSAndroid Build Coastguard Worker return; 172*9e94795aSAndroid Build Coastguard Worker } 173*9e94795aSAndroid Build Coastguard Worker 174*9e94795aSAndroid Build Coastguard Worker Constructor<?> constructor = null; 175*9e94795aSAndroid Build Coastguard Worker for (Constructor<?> c : klass.getConstructors()) { 176*9e94795aSAndroid Build Coastguard Worker if (c.getParameterTypes().length == 0) { 177*9e94795aSAndroid Build Coastguard Worker constructor = c; 178*9e94795aSAndroid Build Coastguard Worker break; 179*9e94795aSAndroid Build Coastguard Worker } 180*9e94795aSAndroid Build Coastguard Worker } 181*9e94795aSAndroid Build Coastguard Worker if (constructor == null) { 182*9e94795aSAndroid Build Coastguard Worker System.err.println("No zero-arg constructor found for " + providerClassName); 183*9e94795aSAndroid Build Coastguard Worker System.exit(1); 184*9e94795aSAndroid Build Coastguard Worker return; 185*9e94795aSAndroid Build Coastguard Worker } 186*9e94795aSAndroid Build Coastguard Worker 187*9e94795aSAndroid Build Coastguard Worker final Object o; 188*9e94795aSAndroid Build Coastguard Worker try { 189*9e94795aSAndroid Build Coastguard Worker o = constructor.newInstance(); 190*9e94795aSAndroid Build Coastguard Worker } catch (Exception e) { 191*9e94795aSAndroid Build Coastguard Worker e.printStackTrace(); 192*9e94795aSAndroid Build Coastguard Worker System.exit(1); 193*9e94795aSAndroid Build Coastguard Worker return; 194*9e94795aSAndroid Build Coastguard Worker } 195*9e94795aSAndroid Build Coastguard Worker if (!(o instanceof Provider)) { 196*9e94795aSAndroid Build Coastguard Worker System.err.println("Not a Provider class: " + providerClassName); 197*9e94795aSAndroid Build Coastguard Worker System.exit(1); 198*9e94795aSAndroid Build Coastguard Worker } 199*9e94795aSAndroid Build Coastguard Worker 200*9e94795aSAndroid Build Coastguard Worker Security.insertProviderAt((Provider) o, 1); 201*9e94795aSAndroid Build Coastguard Worker } 202*9e94795aSAndroid Build Coastguard Worker getSignatureAlgorithm(Key key)203*9e94795aSAndroid Build Coastguard Worker private static String getSignatureAlgorithm(Key key) { 204*9e94795aSAndroid Build Coastguard Worker if ("EC".equals(key.getAlgorithm())) { 205*9e94795aSAndroid Build Coastguard Worker ECKey ecKey = (ECKey) key; 206*9e94795aSAndroid Build Coastguard Worker int curveSize = ecKey.getParams().getOrder().bitLength(); 207*9e94795aSAndroid Build Coastguard Worker if (curveSize <= 256) { 208*9e94795aSAndroid Build Coastguard Worker return "SHA256withECDSA"; 209*9e94795aSAndroid Build Coastguard Worker } else if (curveSize <= 384) { 210*9e94795aSAndroid Build Coastguard Worker return "SHA384withECDSA"; 211*9e94795aSAndroid Build Coastguard Worker } else { 212*9e94795aSAndroid Build Coastguard Worker return "SHA512withECDSA"; 213*9e94795aSAndroid Build Coastguard Worker } 214*9e94795aSAndroid Build Coastguard Worker } else { 215*9e94795aSAndroid Build Coastguard Worker throw new IllegalArgumentException("Unsupported key type " + key.getAlgorithm()); 216*9e94795aSAndroid Build Coastguard Worker } 217*9e94795aSAndroid Build Coastguard Worker } 218*9e94795aSAndroid Build Coastguard Worker 219*9e94795aSAndroid Build Coastguard Worker /** 220*9e94795aSAndroid Build Coastguard Worker * @param inputFilename 221*9e94795aSAndroid Build Coastguard Worker * @param outputFilename 222*9e94795aSAndroid Build Coastguard Worker */ signWholeFile(InputStream input, OutputStream output, PrivateKey signingKey)223*9e94795aSAndroid Build Coastguard Worker private static void signWholeFile(InputStream input, OutputStream output, PrivateKey signingKey) 224*9e94795aSAndroid Build Coastguard Worker throws Exception { 225*9e94795aSAndroid Build Coastguard Worker Signature sig = Signature.getInstance(getSignatureAlgorithm(signingKey)); 226*9e94795aSAndroid Build Coastguard Worker sig.initSign(signingKey); 227*9e94795aSAndroid Build Coastguard Worker 228*9e94795aSAndroid Build Coastguard Worker byte[] buffer = new byte[8192]; 229*9e94795aSAndroid Build Coastguard Worker 230*9e94795aSAndroid Build Coastguard Worker /* Skip the header. */ 231*9e94795aSAndroid Build Coastguard Worker int skippedBytes = 0; 232*9e94795aSAndroid Build Coastguard Worker while (skippedBytes != HEADER_SIZE) { 233*9e94795aSAndroid Build Coastguard Worker int bytesRead = input.read(buffer, 0, HEADER_SIZE - skippedBytes); 234*9e94795aSAndroid Build Coastguard Worker output.write(buffer, 0, bytesRead); 235*9e94795aSAndroid Build Coastguard Worker skippedBytes += bytesRead; 236*9e94795aSAndroid Build Coastguard Worker } 237*9e94795aSAndroid Build Coastguard Worker 238*9e94795aSAndroid Build Coastguard Worker int totalBytes = 0; 239*9e94795aSAndroid Build Coastguard Worker for (;;) { 240*9e94795aSAndroid Build Coastguard Worker int bytesRead = input.read(buffer); 241*9e94795aSAndroid Build Coastguard Worker if (bytesRead == -1) { 242*9e94795aSAndroid Build Coastguard Worker break; 243*9e94795aSAndroid Build Coastguard Worker } 244*9e94795aSAndroid Build Coastguard Worker totalBytes += bytesRead; 245*9e94795aSAndroid Build Coastguard Worker sig.update(buffer, 0, bytesRead); 246*9e94795aSAndroid Build Coastguard Worker output.write(buffer, 0, bytesRead); 247*9e94795aSAndroid Build Coastguard Worker } 248*9e94795aSAndroid Build Coastguard Worker 249*9e94795aSAndroid Build Coastguard Worker byte[] sigBlock = new byte[SIGNATURE_BLOCK_SIZE]; 250*9e94795aSAndroid Build Coastguard Worker sigBlock[0] = VERSION_CODE; 251*9e94795aSAndroid Build Coastguard Worker sig.sign(sigBlock, 1, sigBlock.length - 1); 252*9e94795aSAndroid Build Coastguard Worker 253*9e94795aSAndroid Build Coastguard Worker output.write(sigBlock); 254*9e94795aSAndroid Build Coastguard Worker } 255*9e94795aSAndroid Build Coastguard Worker usage()256*9e94795aSAndroid Build Coastguard Worker private static void usage() { 257*9e94795aSAndroid Build Coastguard Worker System.err.println("Usage: signtos " + 258*9e94795aSAndroid Build Coastguard Worker "[-providerClass <className>] " + 259*9e94795aSAndroid Build Coastguard Worker " privatekey.pk8 " + 260*9e94795aSAndroid Build Coastguard Worker "input.img output.img"); 261*9e94795aSAndroid Build Coastguard Worker System.exit(2); 262*9e94795aSAndroid Build Coastguard Worker } 263*9e94795aSAndroid Build Coastguard Worker main(String[] args)264*9e94795aSAndroid Build Coastguard Worker public static void main(String[] args) throws Exception { 265*9e94795aSAndroid Build Coastguard Worker if (args.length < 3) { 266*9e94795aSAndroid Build Coastguard Worker usage(); 267*9e94795aSAndroid Build Coastguard Worker } 268*9e94795aSAndroid Build Coastguard Worker 269*9e94795aSAndroid Build Coastguard Worker String providerClass = null; 270*9e94795aSAndroid Build Coastguard Worker String providerArg = null; 271*9e94795aSAndroid Build Coastguard Worker 272*9e94795aSAndroid Build Coastguard Worker int argstart = 0; 273*9e94795aSAndroid Build Coastguard Worker while (argstart < args.length && args[argstart].startsWith("-")) { 274*9e94795aSAndroid Build Coastguard Worker if ("-providerClass".equals(args[argstart])) { 275*9e94795aSAndroid Build Coastguard Worker if (argstart + 1 >= args.length) { 276*9e94795aSAndroid Build Coastguard Worker usage(); 277*9e94795aSAndroid Build Coastguard Worker } 278*9e94795aSAndroid Build Coastguard Worker providerClass = args[++argstart]; 279*9e94795aSAndroid Build Coastguard Worker ++argstart; 280*9e94795aSAndroid Build Coastguard Worker } else { 281*9e94795aSAndroid Build Coastguard Worker usage(); 282*9e94795aSAndroid Build Coastguard Worker } 283*9e94795aSAndroid Build Coastguard Worker } 284*9e94795aSAndroid Build Coastguard Worker 285*9e94795aSAndroid Build Coastguard Worker /* 286*9e94795aSAndroid Build Coastguard Worker * Should only be "<privatekey> <input> <output>" left. 287*9e94795aSAndroid Build Coastguard Worker */ 288*9e94795aSAndroid Build Coastguard Worker if (argstart != args.length - 3) { 289*9e94795aSAndroid Build Coastguard Worker usage(); 290*9e94795aSAndroid Build Coastguard Worker } 291*9e94795aSAndroid Build Coastguard Worker 292*9e94795aSAndroid Build Coastguard Worker sBouncyCastleProvider = new BouncyCastleProvider(); 293*9e94795aSAndroid Build Coastguard Worker Security.addProvider(sBouncyCastleProvider); 294*9e94795aSAndroid Build Coastguard Worker 295*9e94795aSAndroid Build Coastguard Worker loadProviderIfNecessary(providerClass); 296*9e94795aSAndroid Build Coastguard Worker 297*9e94795aSAndroid Build Coastguard Worker String keyFilename = args[args.length - 3]; 298*9e94795aSAndroid Build Coastguard Worker String inputFilename = args[args.length - 2]; 299*9e94795aSAndroid Build Coastguard Worker String outputFilename = args[args.length - 1]; 300*9e94795aSAndroid Build Coastguard Worker 301*9e94795aSAndroid Build Coastguard Worker PrivateKey privateKey = readPrivateKey(new File(keyFilename)); 302*9e94795aSAndroid Build Coastguard Worker 303*9e94795aSAndroid Build Coastguard Worker InputStream input = new BufferedInputStream(new FileInputStream(inputFilename)); 304*9e94795aSAndroid Build Coastguard Worker OutputStream output = new BufferedOutputStream(new FileOutputStream(outputFilename)); 305*9e94795aSAndroid Build Coastguard Worker try { 306*9e94795aSAndroid Build Coastguard Worker SignTos.signWholeFile(input, output, privateKey); 307*9e94795aSAndroid Build Coastguard Worker } finally { 308*9e94795aSAndroid Build Coastguard Worker input.close(); 309*9e94795aSAndroid Build Coastguard Worker output.close(); 310*9e94795aSAndroid Build Coastguard Worker } 311*9e94795aSAndroid Build Coastguard Worker 312*9e94795aSAndroid Build Coastguard Worker System.out.println("Successfully signed: " + outputFilename); 313*9e94795aSAndroid Build Coastguard Worker } 314*9e94795aSAndroid Build Coastguard Worker } 315