1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dumpkey; 18 19 import java.io.FileInputStream; 20 import java.math.BigInteger; 21 import java.security.cert.CertificateFactory; 22 import java.security.cert.Certificate; 23 import java.security.KeyStore; 24 import java.security.Key; 25 import java.security.PublicKey; 26 import java.security.interfaces.RSAPublicKey; 27 import sun.misc.BASE64Encoder; 28 29 /** 30 * Command line tool to extract RSA public keys from X.509 certificates 31 * and output source code with data initializers for the keys. 32 * @hide 33 */ 34 class DumpPublicKey { 35 /** 36 * @param key to perform sanity checks on 37 * @throws Exception if the key has the wrong size or public exponent 38 */ 39 static void check(RSAPublicKey key) throws Exception { 40 BigInteger pubexp = key.getPublicExponent(); 41 BigInteger modulus = key.getModulus(); 42 43 if (!pubexp.equals(BigInteger.valueOf(3))) 44 throw new Exception("Public exponent should be 3 but is " + 45 pubexp.toString(10) + "."); 46 47 if (modulus.bitLength() != 2048) 48 throw new Exception("Modulus should be 2048 bits long but is " + 49 modulus.bitLength() + " bits."); 50 } 51 52 /** 53 * @param key to output 54 * @return a C initializer representing this public key. 55 */ 56 static String print(RSAPublicKey key) throws Exception { 57 check(key); 58 59 BigInteger N = key.getModulus(); 60 61 StringBuilder result = new StringBuilder(); 62 63 int nwords = N.bitLength() / 32; // # of 32 bit integers in modulus 64 65 result.append("{"); 66 result.append(nwords); 67 68 BigInteger B = BigInteger.valueOf(0x100000000L); // 2^32 69 BigInteger N0inv = B.subtract(N.modInverse(B)); // -1 / N[0] mod 2^32 70 71 result.append(",0x"); 72 result.append(N0inv.toString(16)); 73 74 BigInteger R = BigInteger.valueOf(2).pow(N.bitLength()); 75 BigInteger RR = R.multiply(R).mod(N); // 2^4096 mod N 76 77 // Write out modulus as little endian array of integers. 78 result.append(",{"); 79 for (int i = 0; i < nwords; ++i) { 80 long n = N.mod(B).longValue(); 81 result.append(n); 82 83 if (i != nwords - 1) { 84 result.append(","); 85 } 86 87 N = N.divide(B); 88 } 89 result.append("}"); 90 91 // Write R^2 as little endian array of integers. 92 result.append(",{"); 93 for (int i = 0; i < nwords; ++i) { 94 long rr = RR.mod(B).longValue(); 95 result.append(rr); 96 97 if (i != nwords - 1) { 98 result.append(","); 99 } 100 101 RR = RR.divide(B); 102 } 103 result.append("}"); 104 105 result.append("}"); 106 return result.toString(); 107 } 108 109 public static void main(String[] args) { 110 if (args.length < 1) { 111 System.err.println("Usage: DumpPublicKey certfile ... > source.c"); 112 System.exit(1); 113 } 114 try { 115 for (int i = 0; i < args.length; i++) { 116 FileInputStream input = new FileInputStream(args[i]); 117 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 118 Certificate cert = cf.generateCertificate(input); 119 RSAPublicKey key = (RSAPublicKey) (cert.getPublicKey()); 120 check(key); 121 System.out.print(print(key)); 122 System.out.println(i < args.length - 1 ? "," : ""); 123 } 124 } catch (Exception e) { 125 e.printStackTrace(); 126 System.exit(1); 127 } 128 System.exit(0); 129 } 130 } 131