123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- /*
- * Compilation Instruction:
- * javac -cp bcprov-jdk15on-152.jar DumpPublicKey.java
- *
- * Run Instruction:
- * java -cp bcprov-jdk15on-152.jar:. DumpPublicKey PubKey.pem > source.c
- * java -cp bcprov-jdk15on-152.jar:. DumpPublicKey PubKey.pem OutKey.bin
- *
- */
- /*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- //package com.android.dumpkey;
- import org.bouncycastle.jce.provider.BouncyCastleProvider;
- import java.io.FileInputStream;
- import java.math.BigInteger;
- import java.security.cert.CertificateFactory;
- import java.security.cert.X509Certificate;
- import java.security.KeyStore;
- import java.security.Key;
- import java.security.PublicKey;
- import java.security.Security;
- import java.security.interfaces.ECPublicKey;
- import java.security.interfaces.RSAPublicKey;
- import java.security.spec.ECPoint;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.security.KeyFactory;
- import java.security.NoSuchAlgorithmException;
- import java.security.NoSuchProviderException;
- import java.security.PrivateKey;
- import java.security.spec.InvalidKeySpecException;
- import java.security.spec.PKCS8EncodedKeySpec;
- import java.security.spec.X509EncodedKeySpec;
- import java.io.InputStreamReader;
- import org.bouncycastle.util.io.pem.PemObject;
- import org.bouncycastle.util.io.pem.PemReader;
- import java.io.FileOutputStream;
- import java.nio.ByteBuffer;
- import java.nio.ByteOrder;
- import java.nio.channels.FileChannel;
- class PemFile {
- private PemObject pemObject;
- public PemFile(String filename) throws FileNotFoundException, IOException {
- PemReader pemReader = new PemReader(new InputStreamReader(new FileInputStream(filename)));
- try {
- this.pemObject = pemReader.readPemObject();
- } finally {
- pemReader.close();
- }
- }
- public PemObject getPemObject() {
- return pemObject;
- }
- }
- class PemKey {
- protected KeyFactory factory;
- public PemKey() throws NoSuchAlgorithmException {
- factory = KeyFactory.getInstance("RSA");
- }
- public PrivateKey generatePrivateKey(String filename) throws InvalidKeySpecException, FileNotFoundException, IOException{
- PemFile pemFile = new PemFile(filename);
- byte[] content = pemFile.getPemObject().getContent();
- PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
- return factory.generatePrivate(privKeySpec);
- }
- public PublicKey generatePublicKey(String filename) throws InvalidKeySpecException, FileNotFoundException, IOException {
- PemFile pemFile = new PemFile(filename);
- byte[] content = pemFile.getPemObject().getContent();
- X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
- return factory.generatePublic(pubKeySpec);
- }
- }
- /**
- * Command line tool to extract RSA public keys from X.509 certificates
- * and output source code with data initializers for the keys.
- * @hide
- */
- class DumpPublicKey {
- /**
- * @param key to perform sanity checks on
- * @return version number of key. Supported versions are:
- * 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 checkRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
- BigInteger pubexp = key.getPublicExponent();
- BigInteger modulus = key.getModulus();
- int version;
- if (pubexp.equals(BigInteger.valueOf(65537))) {
- version = useSHA256 ? 4 : 2;
- } else {
- throw new Exception("Public exponent should be 65537 but is " +
- pubexp.toString(10) + ".");
- }
- if (modulus.bitLength() != 2048) {
- throw new Exception("Modulus should be 2048 bits long but is " +
- modulus.bitLength() + " bits.");
- }
- return version;
- }
- /**
- * @param key to perform sanity checks on
- * @return version number of key. Supported versions are:
- * 5: 256-bit EC key with curve NIST P-256
- * @throws Exception if the key has the wrong size or public exponent
- */
- static int checkEC(ECPublicKey key) throws Exception {
- if (key.getParams().getCurve().getField().getFieldSize() != 256) {
- throw new Exception("Curve must be NIST P-256");
- }
- return 5;
- }
- /**
- * Perform sanity check on public key.
- */
- static int check(PublicKey key, boolean useSHA256) throws Exception {
- if (key instanceof RSAPublicKey) {
- return checkRSA((RSAPublicKey) key, useSHA256);
- } else if (key instanceof ECPublicKey) {
- if (!useSHA256) {
- throw new Exception("Must use SHA-256 with EC keys!");
- }
- return checkEC((ECPublicKey) key);
- } else {
- throw new Exception("Unsupported key class: " + key.getClass().getName());
- }
- }
- /**
- * @param key to output
- * @return a String representing this public key. If the key is a
- * version 1 key, the string will be a C initializer; this is
- * not true for newer key versions.
- */
- static String printRSA(RSAPublicKey key, boolean useSHA256, String binfile) throws Exception {
- int version = check(key, useSHA256);
- final String tabpos = " ";
- FileOutputStream os = null;
- ByteBuffer bbuf = null;
- if (binfile != null) {
- try {
- os = new FileOutputStream(binfile);
- bbuf = ByteBuffer.allocate(1024);
- bbuf.order(ByteOrder.LITTLE_ENDIAN);
- } catch (Exception e) {
- e.printStackTrace();
- System.exit(1);
- }
- }
- BigInteger N = key.getModulus();
- StringBuilder result = new StringBuilder();
- int nwords = N.bitLength() / 32; // # of 32 bit integers in modulus
- BigInteger B = BigInteger.valueOf(0x100000000L); // 2^32
- BigInteger N0inv = B.subtract(N.modInverse(B)); // -1 / N[0] mod 2^32
- result.append("{\n");
- result.append(tabpos);
- result.append("0x");
- result.append(N0inv.toString(16));
- if (bbuf != null) {
- bbuf.putInt(N0inv.intValue());
- }
- result.append(",\n");
- BigInteger R = BigInteger.valueOf(2).pow(N.bitLength());
- BigInteger RR = R.multiply(R).mod(N); // 2^4096 mod N
- // Write out modulus as little endian array of integers.
- result.append(tabpos);
- result.append("{\n");
- result.append(tabpos);
- result.append(tabpos);
- for (int i = 0; i < nwords; ++i) {
- long n = N.mod(B).longValue();
- result.append(String.format("0x%08x, ", n));
- if (bbuf != null) {
- bbuf.putInt((int)n);
- }
- if ((i + 1) % 4 == 0) {
- result.append("\n");
- if (i + 1 != nwords) {
- result.append(tabpos);
- result.append(tabpos);
- }
- }
- N = N.divide(B);
- }
- result.append(tabpos);
- result.append("},\n");
- // Write R^2 as little endian array of integers.
- result.append(tabpos);
- result.append("{\n");
- result.append(tabpos);
- result.append(tabpos);
- for (int i = 0; i < nwords; ++i) {
- long rr = RR.mod(B).longValue();
- result.append(String.format("0x%08x, ", rr));
- if (bbuf != null) {
- bbuf.putInt((int)rr);
- }
- if ((i + 1) % 4 == 0) {
- result.append("\n");
- if (i + 1 != nwords) {
- result.append(tabpos);
- result.append(tabpos);
- }
- }
- RR = RR.divide(B);
- }
- if (os != null) {
- bbuf.flip();
- FileChannel out = os.getChannel();
- out.write(bbuf);
- out.close();
- }
- result.append(tabpos);
- result.append("},\n");
- result.append("},\n");
- return result.toString();
- }
- /**
- * @param key to output
- * @return a String representing this public key. If the key is a
- * version 1 key, the string will be a C initializer; this is
- * not true for newer key versions.
- */
- static String printEC(ECPublicKey key) throws Exception {
- int version = checkEC(key);
- StringBuilder result = new StringBuilder();
- result.append("v");
- result.append(Integer.toString(version));
- result.append(" ");
- BigInteger X = key.getW().getAffineX();
- BigInteger Y = key.getW().getAffineY();
- int nbytes = key.getParams().getCurve().getField().getFieldSize() / 8; // # of 32 bit integers in X coordinate
- result.append("{");
- result.append(nbytes);
- BigInteger B = BigInteger.valueOf(0x100L); // 2^8
- // Write out Y coordinate as array of characters.
- result.append(",{");
- for (int i = 0; i < nbytes; ++i) {
- long n = X.mod(B).longValue();
- result.append(n);
- if (i != nbytes - 1) {
- result.append(",");
- }
- X = X.divide(B);
- }
- result.append("}");
- // Write out Y coordinate as array of characters.
- result.append(",{");
- for (int i = 0; i < nbytes; ++i) {
- long n = Y.mod(B).longValue();
- result.append(n);
- if (i != nbytes - 1) {
- result.append(",");
- }
- Y = Y.divide(B);
- }
- result.append("}");
- result.append("}");
- return result.toString();
- }
- static String print(PublicKey key, boolean useSHA256, String binfile) throws Exception {
- if (key instanceof RSAPublicKey) {
- return printRSA((RSAPublicKey) key, useSHA256, binfile);
- } else if (key instanceof ECPublicKey) {
- return printEC((ECPublicKey) key);
- } else {
- throw new Exception("Unsupported key class: " + key.getClass().getName());
- }
- }
- public static void main(String[] args) {
- if (args.length != 1 && args.length != 2) {
- System.err.println("Usage:");
- System.err.println("\tDumpPublicKey PubKey.pem [OutKey.bin] > source.c");
- System.exit(1);
- }
- Security.addProvider(new BouncyCastleProvider());
- try {
- PemKey pem = new PemKey();
- PublicKey key = pem.generatePublicKey(args[0]);
- check(key, true);
- if (args.length == 1) {
- System.out.print(print(key, true, null));
- } else {
- System.out.print(print(key, true, args[1]));
- }
- } catch (Exception e) {
- e.printStackTrace();
- System.exit(1);
- }
- System.exit(0);
- }
- }
|