mincrypt: support SHA-256 hash algorithm

- adds a library to compute the SHA-256 hash

- updates the RSA verifier to take an argument specifying either SHA-1
  or SHA-256

- updates DumpPublicKey to with new "key" version numbers for
  specifying SHA-256

- adds new argument to adb auth code to maintain existing behavior

(cherry picked from commit 515e1639ef0ab5e3149fafeffce826cf654d616f)

Change-Id: Ib35643b3d864742e817ac6e725499b451e45afcf
diff --git a/libmincrypt/tools/DumpPublicKey.java b/libmincrypt/tools/DumpPublicKey.java
index 12b4f56..7189116 100644
--- a/libmincrypt/tools/DumpPublicKey.java
+++ b/libmincrypt/tools/DumpPublicKey.java
@@ -19,7 +19,7 @@
 import java.io.FileInputStream;
 import java.math.BigInteger;
 import java.security.cert.CertificateFactory;
-import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
 import java.security.KeyStore;
 import java.security.Key;
 import java.security.PublicKey;
@@ -34,20 +34,22 @@
     /**
      * @param key to perform sanity checks on
      * @return version number of key.  Supported versions are:
-     *     1: 2048-bit key with e=3
-     *     2: 2048-bit key with e=65537
+     *     1: 2048-bit RSA key with e=3 and SHA-1 hash
+     *     2: 2048-bit RSA key with e=65537 and SHA-1 hash
+     *     3: 2048-bit RSA key with e=3 and SHA-256 hash
+     *     4: 2048-bit RSA key with e=65537 and SHA-256 hash
      * @throws Exception if the key has the wrong size or public exponent
 
      */
-    static int check(RSAPublicKey key) throws Exception {
+    static int check(RSAPublicKey key, boolean useSHA256) throws Exception {
         BigInteger pubexp = key.getPublicExponent();
         BigInteger modulus = key.getModulus();
         int version;
 
         if (pubexp.equals(BigInteger.valueOf(3))) {
-            version = 1;
+            version = useSHA256 ? 3 : 1;
         } else if (pubexp.equals(BigInteger.valueOf(65537))) {
-            version = 2;
+            version = useSHA256 ? 4 : 2;
         } else {
             throw new Exception("Public exponent should be 3 or 65537 but is " +
                                 pubexp.toString(10) + ".");
@@ -67,8 +69,8 @@
      *    version 1 key, the string will be a C initializer; this is
      *    not true for newer key versions.
      */
-    static String print(RSAPublicKey key) throws Exception {
-        int version = check(key);
+    static String print(RSAPublicKey key, boolean useSHA256) throws Exception {
+        int version = check(key, useSHA256);
 
         BigInteger N = key.getModulus();
 
@@ -135,10 +137,27 @@
             for (int i = 0; i < args.length; i++) {
                 FileInputStream input = new FileInputStream(args[i]);
                 CertificateFactory cf = CertificateFactory.getInstance("X.509");
-                Certificate cert = cf.generateCertificate(input);
+                X509Certificate cert = (X509Certificate) cf.generateCertificate(input);
+
+                boolean useSHA256 = false;
+                String sigAlg = cert.getSigAlgName();
+                if ("SHA1withRSA".equals(sigAlg) || "MD5withRSA".equals(sigAlg)) {
+                    // SignApk has historically accepted "MD5withRSA"
+                    // certificates, but treated them as "SHA1withRSA"
+                    // anyway.  Continue to do so for backwards
+                    // compatibility.
+                  useSHA256 = false;
+                } else if ("SHA256withRSA".equals(sigAlg)) {
+                  useSHA256 = true;
+                } else {
+                  System.err.println(args[i] + ": unsupported signature algorithm \"" +
+                                     sigAlg + "\"");
+                  System.exit(1);
+                }
+
                 RSAPublicKey key = (RSAPublicKey) (cert.getPublicKey());
-                check(key);
-                System.out.print(print(key));
+                check(key, useSHA256);
+                System.out.print(print(key, useSHA256));
                 System.out.println(i < args.length - 1 ? "," : "");
             }
         } catch (Exception e) {