//*************************************************************** // // MSKeytoJKey.java // CryptoAPI PUBLICKEYBLOB to Java PublicKey Bridge // // Copyright (C) 2005 Michel I. Gallant // //**************************************************************** import java.io.*; import java.security.*; import java.security.spec.*; import java.security.interfaces.*; import java.math.BigInteger; // --- Utility class to convert CryptoAPI PUBLICKEYBLOB file to Java PublicKey object // --- Writes asn.1 encoded SubjecPublicKeyInfo output file // --- Note that Java reads multi-byte data as BIG-endian (compare to little-endian for C, C# etc..) ----- // --- See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/seccrypto/security/public_key_blobs.asp class MSKeytoJKey { 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 String MAGIC = "RSA1" ; // 0x31415352 private static int keysize = 0; public static void main(String[] args) { if (args.length != 1 && args.length !=2) { System.out.println("Usage: java MSKeytoJkey [SubjectPublicKeyInfo_pubkey]"); return; } RSAPublicKey key = (RSAPublicKey) MSKeytoJKey.getPublicKey(args[0]); if(key != null) { System.out.println("\n---- Public key data for '" + args[0] + "' ----") ; System.out.println("RSA keysize: " + keysize + " bits") ; BigInteger mod = key.getModulus(); System.out.println("\nModulus: (base 10)\n" + mod.toString()); System.out.println("\nModulus: (hex)") ; displayData(mod.toByteArray()); BigInteger exp = key.getPublicExponent(); System.out.println("\nPublic Exponent:\n" + exp.toString()); System.out.println("\nSubjectPublicKeyInfo encoding:"); displayData(key.getEncoded()) ; if(args.length == 2) { try{ FileOutputStream fos = new FileOutputStream(args[1]); fos.write(key.getEncoded()); //write the ANS.1 SubjecPublickeyInfo fos.close(); System.out.println("Wrote SubjectPublicKeyInfo file '" + args[1] + "'") ; } catch(IOException ex) {System.err.println(ex);} } } else System.out.println("FAILED to get PublicKey") ; } public static PublicKey getPublicKey (String mspublickeyblobfile) { File blobfile = new File(mspublickeyblobfile) ; if (!blobfile.exists()) return null; int blobsize = ((int) blobfile.length()); byte[] blobdata = new byte[blobsize]; try { FileInputStream freader = new FileInputStream(blobfile); freader.read(blobdata, 0, blobsize) ; freader.close(); return getPublicKey(blobdata); } catch(IOException ioe) { return null; } } public static PublicKey getPublicKey (byte[] mspublickeyblob) { DataInputStream dis = null; int jint = 0 ; // int to build Java int from little-endian ordered byte data int bitlen = 0; int pubexp = 0; try { //------ Read the "BLOBHEADER" fields ------------- //displayData(mspublickeyblob) ; ByteArrayInputStream bis = new ByteArrayInputStream(mspublickeyblob); dis = new DataInputStream(bis); if(dis.readByte() != PUBLICKEYBLOB || dis.readByte() != CUR_BLOB_VERSION || dis.readShort() != RESERVED) return null; jint = 0; for (int i=0; i<4; i++) jint += dis.readUnsignedByte() *(int)Math.pow(256,i) ; if(jint != CALG_RSA_KEYX && jint != CALG_RSA_SIGN) return null; //------ Read the RSAPUBKEY struct members --------- StringBuffer magic = new StringBuffer(4); for (int i=1; i<=4; i++) magic.append((char)dis.readByte()) ; if(!magic.toString().equals(MAGIC)) return null; for (int i=0; i<4; i++) bitlen += dis.readUnsignedByte() *(int)Math.pow(256,i) ; for (int i=0; i<4; i++) pubexp += dis.readUnsignedByte() *(int)Math.pow(256,i) ; keysize = bitlen; //----- Finally, get the modulus data, and reverse bytes to get big-endian value -------- byte[] modulus = new byte[bitlen/8] ; //should be this many bytes left int modbytes = dis.read(modulus) ; if(modbytes != (bitlen/8)) return null; ReverseMemory(modulus) ; //reverse bytes to put in big-endian order //----- Create the PublicKey from modulus and public exponent -------- RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(1, modulus), BigInteger.valueOf(pubexp)); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey pubKey = keyFactory.generatePublic(pubKeySpec); return pubKey; } catch(Exception exc) { return null; } finally { try {dis.close();} catch(Exception exc) {; } } } 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 ; } } private static void displayData(byte[] data) { int bytecon = 0; //to get unsigned byte representation for(int i=1; i<=data.length ; i++){ bytecon = data[i-1] & 0xFF ; // byte-wise AND converts signed byte to unsigned. if(bytecon<16) System.out.print("0" + Integer.toHexString(bytecon).toUpperCase() + " "); // pad on left if single hex digit. else System.out.print(Integer.toHexString(bytecon).toUpperCase() + " "); // pad on left if single hex digit. if(i%16==0) System.out.println(); } System.out.println() ; } }