DumpPublicKey.java revision ede5cf6533387a02b4a726cf577bfcb22374ad9a
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 17package com.android.dumpkey; 18 19import java.io.FileInputStream; 20import java.math.BigInteger; 21import java.security.cert.CertificateFactory; 22import java.security.cert.Certificate; 23import java.security.KeyStore; 24import java.security.Key; 25import java.security.PublicKey; 26import java.security.interfaces.RSAPublicKey; 27 28/** 29 * Command line tool to extract RSA public keys from X.509 certificates 30 * and output source code with data initializers for the keys. 31 * @hide 32 */ 33class DumpPublicKey { 34 /** 35 * @param key to perform sanity checks on 36 * @return version number of key. Supported versions are: 37 * 1: 2048-bit key with e=3 38 * 2: 2048-bit key with e=65537 39 * @throws Exception if the key has the wrong size or public exponent 40 41 */ 42 static int check(RSAPublicKey key) throws Exception { 43 BigInteger pubexp = key.getPublicExponent(); 44 BigInteger modulus = key.getModulus(); 45 int version; 46 47 if (pubexp.equals(BigInteger.valueOf(3))) { 48 version = 1; 49 } else if (pubexp.equals(BigInteger.valueOf(65537))) { 50 version = 2; 51 } else { 52 throw new Exception("Public exponent should be 3 or 65537 but is " + 53 pubexp.toString(10) + "."); 54 } 55 56 if (modulus.bitLength() != 2048) { 57 throw new Exception("Modulus should be 2048 bits long but is " + 58 modulus.bitLength() + " bits."); 59 } 60 61 return version; 62 } 63 64 /** 65 * @param key to output 66 * @return a String representing this public key. If the key is a 67 * version 1 key, the string will be a C initializer; this is 68 * not true for newer key versions. 69 */ 70 static String print(RSAPublicKey key) throws Exception { 71 int version = check(key); 72 73 BigInteger N = key.getModulus(); 74 75 StringBuilder result = new StringBuilder(); 76 77 int nwords = N.bitLength() / 32; // # of 32 bit integers in modulus 78 79 if (version > 1) { 80 result.append("v"); 81 result.append(Integer.toString(version)); 82 result.append(" "); 83 } 84 85 result.append("{"); 86 result.append(nwords); 87 88 BigInteger B = BigInteger.valueOf(0x100000000L); // 2^32 89 BigInteger N0inv = B.subtract(N.modInverse(B)); // -1 / N[0] mod 2^32 90 91 result.append(",0x"); 92 result.append(N0inv.toString(16)); 93 94 BigInteger R = BigInteger.valueOf(2).pow(N.bitLength()); 95 BigInteger RR = R.multiply(R).mod(N); // 2^4096 mod N 96 97 // Write out modulus as little endian array of integers. 98 result.append(",{"); 99 for (int i = 0; i < nwords; ++i) { 100 long n = N.mod(B).longValue(); 101 result.append(n); 102 103 if (i != nwords - 1) { 104 result.append(","); 105 } 106 107 N = N.divide(B); 108 } 109 result.append("}"); 110 111 // Write R^2 as little endian array of integers. 112 result.append(",{"); 113 for (int i = 0; i < nwords; ++i) { 114 long rr = RR.mod(B).longValue(); 115 result.append(rr); 116 117 if (i != nwords - 1) { 118 result.append(","); 119 } 120 121 RR = RR.divide(B); 122 } 123 result.append("}"); 124 125 result.append("}"); 126 return result.toString(); 127 } 128 129 public static void main(String[] args) { 130 if (args.length < 1) { 131 System.err.println("Usage: DumpPublicKey certfile ... > source.c"); 132 System.exit(1); 133 } 134 try { 135 for (int i = 0; i < args.length; i++) { 136 FileInputStream input = new FileInputStream(args[i]); 137 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 138 Certificate cert = cf.generateCertificate(input); 139 RSAPublicKey key = (RSAPublicKey) (cert.getPublicKey()); 140 check(key); 141 System.out.print(print(key)); 142 System.out.println(i < args.length - 1 ? "," : ""); 143 } 144 } catch (Exception e) { 145 e.printStackTrace(); 146 System.exit(1); 147 } 148 System.exit(0); 149 } 150} 151