import java.io.*; import java.math.BigInteger; import java.security.*; import java.security.cert.*; import java.security.interfaces.*; import java.util.*; import java.security.cert.*; import java.security.spec.*; class CertoKey { private static final byte PUBLICKEYBLOB = 0x06; private static final byte CUR_BLOB_VERSION = 0x02; private static final short RESERVED = 0x0000; private static final int CALG_RSA_KEYX = 0x0000a400; private static final int CALG_RSA_SIGN = 0x00002400; private static final int AT_KEYEXCHANGE = 1; private static final int AT_SIGNATURE = 2; private static final int[] KEYSPECS = {0, CALG_RSA_KEYX, CALG_RSA_SIGN } ; private static final String MAGIC = "RSA1" ; // 0x31415352 private static final String OUTFILE1 = "_subjectpublickeyinfo" ; private static final String OUTFILE2 = "_publickeyblob" ; private static final String OUTFILE3 = "_certsignature" ; private static int bitlen = 00; private static int bytelen = 00; private static byte[] modulus = null; private static int pubexp = 0; public static void main(String[] args) { if (args.length != 1) { System.out.println("Usage: java CertoKey "); return; } String CERTFILE = args[0] ; int keyspec = AT_KEYEXCHANGE; if( !(new File(CERTFILE)).exists()) { System.out.println("Cert file '" + args[0] + "'not found!") ; System.exit(0) ; } try { InputStream inStream = new FileInputStream(CERTFILE); CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream); inStream.close(); byte [] encPublickey = cert.getPublicKey().getEncoded(); byte [] certsignature = cert.getSignature(); byte [] publickeyblob = subjectpublickeyinfoToPublickeyblob(encPublickey, keyspec) ; System.out.println(cert.toString()) ; FileOutputStream fos = new FileOutputStream(OUTFILE1); fos.write(encPublickey); fos.close(); System.out.println("Wrote SubjectPublicKeyInfo file '" + OUTFILE1 + "' (" +encPublickey.length + " bytes)") ; fos = new FileOutputStream(OUTFILE2); fos.write(publickeyblob); fos.close(); System.out.println("Wrote PUBLICKEYBLOB file '" + OUTFILE2 + "' (" +publickeyblob.length + " bytes)") ; fos = new FileOutputStream(OUTFILE3); fos.write(certsignature); fos.close(); System.out.println("Wrote pkcs#1 signature file '" + OUTFILE3 + "' (" +certsignature.length + " bytes)") ; } catch (Exception e) { System.err.println("Caught exception " + e.toString()); } } private static byte[] subjectpublickeyinfoToPublickeyblob(byte[] encodedPubkey, int keyspec) { if(encodedPubkey == null || (keyspec != AT_KEYEXCHANGE && keyspec !=AT_SIGNATURE)) return null; try{ ByteArrayOutputStream bos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(bos); X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encodedPubkey); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(pubKeySpec); BigInteger mod = pubKey.getModulus(); modulus = mod.toByteArray() ; if(modulus[0] == 0) //if high-order byte is zero, it's for sign bit; don't count in bit-size calculation bytelen = modulus.length-1 ; else bytelen = modulus.length ; bitlen = 8*bytelen; dos.write(PUBLICKEYBLOB); dos.write(CUR_BLOB_VERSION); dos.writeShort(RESERVED); writeLEInt(KEYSPECS[keyspec], dos); //write Little Endian dos.writeBytes(MAGIC) ; writeLEInt(bitlen, dos); //write Little Endian pubexp = Integer.parseInt(pubKey.getPublicExponent().toString()) ; writeLEInt(pubexp, dos); //write Little Endian byte[] data = modulus; ReverseMemory(data); //reverse array to Little Endian order; since data is same ref. as modulus, modulus is also reversed. dos.write(data, 0, bytelen) ; // note that modulus may contain an extra zero byte (highest order byte after reversing) // specifying bytelen bytes to write will drop high-order zero byte dos.flush(); dos.close(); return bos.toByteArray(); } catch(Exception e) {System.err.println(e); return null ;} } private static void writeLEInt(int i, OutputStream out) throws IOException { out.write (i & 0xFF); out.write((i >>>8) & 0xFF); out.write((i >>>16) & 0xFF); out.write((i >>>24) & 0xFF); } private static void ReverseMemory (byte[] pBuffer) { byte b ; int iLength = pBuffer.length; for (int i = 0 ; i < iLength/ 2 ; i++) { b = pBuffer [i] ; pBuffer [i] = pBuffer [iLength - i - 1] ; pBuffer [iLength - i - 1] = b ; } } }