xref: /aosp_15_r20/build/make/tools/signtos/SignTos.java (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
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