1dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/* 2dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 3dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * 4dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * you may not use this file except in compliance with the License. 6dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * You may obtain a copy of the License at 7dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * 8dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * 10dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * See the License for the specific language governing permissions and 14dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * limitations under the License. 15dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 16dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 17dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectpackage com.android.dumpkey; 18dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 19dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectimport java.io.FileInputStream; 20dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectimport java.math.BigInteger; 21dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectimport java.security.cert.CertificateFactory; 22dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectimport java.security.cert.Certificate; 23dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectimport java.security.KeyStore; 24dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectimport java.security.Key; 25dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectimport java.security.PublicKey; 26dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectimport java.security.interfaces.RSAPublicKey; 27dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 28dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** 29dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Command line tool to extract RSA public keys from X.509 certificates 30dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * and output source code with data initializers for the keys. 31dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * @hide 32dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 33dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectclass DumpPublicKey { 34dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /** 35dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * @param key to perform sanity checks on 3635d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker * @return version number of key. Supported versions are: 3735d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker * 1: 2048-bit key with e=3 3835d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker * 2: 2048-bit key with e=65537 39dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * @throws Exception if the key has the wrong size or public exponent 4035d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker 41dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 4235d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker static int check(RSAPublicKey key) throws Exception { 43dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project BigInteger pubexp = key.getPublicExponent(); 44dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project BigInteger modulus = key.getModulus(); 4535d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker int version; 46dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 4735d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker if (pubexp.equals(BigInteger.valueOf(3))) { 4835d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker version = 1; 4935d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker } else if (pubexp.equals(BigInteger.valueOf(65537))) { 5035d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker version = 2; 5135d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker } else { 5235d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker throw new Exception("Public exponent should be 3 or 65537 but is " + 5335d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker pubexp.toString(10) + "."); 5435d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker } 55dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 5635d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker if (modulus.bitLength() != 2048) { 57dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project throw new Exception("Modulus should be 2048 bits long but is " + 58dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project modulus.bitLength() + " bits."); 5935d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker } 6035d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker 6135d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker return version; 62dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 63dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 64dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /** 65dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * @param key to output 6635d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker * @return a String representing this public key. If the key is a 6735d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker * version 1 key, the string will be a C initializer; this is 6835d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker * not true for newer key versions. 69dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */ 70dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project static String print(RSAPublicKey key) throws Exception { 7135d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker int version = check(key); 72dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 73dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project BigInteger N = key.getModulus(); 74dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 75dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project StringBuilder result = new StringBuilder(); 76dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 77dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int nwords = N.bitLength() / 32; // # of 32 bit integers in modulus 78dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 7935d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker if (version > 1) { 8035d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker result.append("v"); 8135d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker result.append(Integer.toString(version)); 8235d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker result.append(" "); 8335d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker } 8435d9ad5ae72de846967b91aed97060f0e8558661Doug Zongker 85dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result.append("{"); 86dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result.append(nwords); 87dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 88dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project BigInteger B = BigInteger.valueOf(0x100000000L); // 2^32 89dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project BigInteger N0inv = B.subtract(N.modInverse(B)); // -1 / N[0] mod 2^32 90dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 91dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result.append(",0x"); 92dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result.append(N0inv.toString(16)); 93dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 94dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project BigInteger R = BigInteger.valueOf(2).pow(N.bitLength()); 95dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project BigInteger RR = R.multiply(R).mod(N); // 2^4096 mod N 96dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 97dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // Write out modulus as little endian array of integers. 98dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result.append(",{"); 99dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project for (int i = 0; i < nwords; ++i) { 1005e12d739c6b86b79d761f45a1c0399e0d42d1cb5Doug Zongker long n = N.mod(B).longValue(); 101dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result.append(n); 102dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 103dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (i != nwords - 1) { 104dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result.append(","); 105dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 106dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 107dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project N = N.divide(B); 108dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 109dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result.append("}"); 110dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 111dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // Write R^2 as little endian array of integers. 112dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result.append(",{"); 113dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project for (int i = 0; i < nwords; ++i) { 1145e12d739c6b86b79d761f45a1c0399e0d42d1cb5Doug Zongker long rr = RR.mod(B).longValue(); 115dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result.append(rr); 116dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 117dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (i != nwords - 1) { 118dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result.append(","); 119dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 120dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 121dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project RR = RR.divide(B); 122dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 123dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result.append("}"); 124dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 125dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project result.append("}"); 126dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return result.toString(); 127dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 128dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 129dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project public static void main(String[] args) { 130dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (args.length < 1) { 131dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project System.err.println("Usage: DumpPublicKey certfile ... > source.c"); 132dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project System.exit(1); 133dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 134dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project try { 135dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project for (int i = 0; i < args.length; i++) { 136dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project FileInputStream input = new FileInputStream(args[i]); 137dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project CertificateFactory cf = CertificateFactory.getInstance("X.509"); 138dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project Certificate cert = cf.generateCertificate(input); 139dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project RSAPublicKey key = (RSAPublicKey) (cert.getPublicKey()); 140dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project check(key); 141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project System.out.print(print(key)); 142dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project System.out.println(i < args.length - 1 ? "," : ""); 143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } catch (Exception e) { 145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project e.printStackTrace(); 146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project System.exit(1); 147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project System.exit(0); 149dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 151