participate


Java Card - Sending RSA public key modulus to card
This question is not answered.

<<   Back to Forum  |   Give us Feedback
This topic has 30 replies on 3 pages.    1 | 2 | 3 | Next »
A_nl
Posts:46
Registered: 11/28/09
Sending RSA public key modulus to card   
03.12.2009 12:40
 
 
Hello,

I'm trying to send a public key from a java program to the javacard. I do this by sending both the exponent and the modulus of the public key to the card. However, I have some trouble sending the (large) modulus:

In the Java file:

publicKey  = (RSAPublicKey) keyPair.getPublic();
 
public byte[] getModulus() {
	return publicKey.getModulus().toByteArray();
}


I then send an APDU to the card: new CommandAPDU(CLA, INS, (byte) 0x00, (byte) 0x00, getModulus()));

private void setModulus(APDU apdu) {
	byte buf[] = apdu.getBuffer();
	short len = (short)((short) buf[(short)ISO7816.OFFSET_LC] & (short)0x00FF);
	short numBytes = apdu.setIncomingAndReceive();
 
	while (numBytes < len)
		numBytes += apdu.receiveBytes((short)((short)ISO7816.OFFSET_CDATA+numBytes)); // APS- copy more incoming bytes to APDU buffer starting at specific buffer offset 
 
	   Util.arrayCopy(buf, ISO7816.OFFSET_CDATA, MYMODULUS, (short)(MYMODULUS.length-numBytes), numBytes);
		
	// Send results
	apdu.setOutgoing();
	apdu.setOutgoingLength((short)numBytes );
	apdu.sendBytesLong(buf, (short) ISO7816.OFFSET_CDATA, (short)numBytes );
}


This seems to go okay (the above '//send results' part shows the correct modulus when I print it), however when I try to set the publickey right after that it seems not to be possible:

private void setKey(APDU apdu) {
	publicKey.clearKey();
	publicKey.setExponent(MYEXPONENT, (short)0, (short)MYEXPONENT.length);
	try { publicKey.setModulus( MYMODULUS, (short)0, (short)MYMODULUS.length); }
	catch (CryptoException e) { /*This error seems to be thrown?..*/ }
}

The exception is thrown. I'm not quite sure what's wrong here. Any help in the good direction would be appreciated.
 
A_nl
Posts:46
Registered: 11/28/09
Re: Sending RSA public key modulus to card   
03.12.2009 17:26 (reply 1 of 30)  (In reply to original post )
 
 
Also, why won't this work?

	private void setKey(APDU apdu) {
		byte buf[] = apdu.getBuffer();
		short len = (short)((short) buf[(short)ISO7816.OFFSET_LC] & (short)0x00FF);
		short numBytes = apdu.setIncomingAndReceive();
		
		while (numBytes < len)
			numBytes += apdu.receiveBytes((short)((short)ISO7816.OFFSET_CDATA+numBytes));
 
		switch(buf[ISO7816.OFFSET_P1]) {
		case MODULUS:
			publicKeyOther.setModulus(buf, ISO7816.OFFSET_CDATA, len);
			break;
		case EXPONENT:
			publicKeyOther.setExponent(buf, ISO7816.OFFSET_CDATA, len);
			break;
		case RESET:
			publicKeyOther.clearKey();
			break;
		default:
			ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
		}
	}
 
safarmer
Posts:961
Registered: 4/6/08
Re: Sending RSA public key modulus to card   
03.12.2009 17:32 (reply 2 of 30)  (In reply to #1 )
 
 
Hi,

Can you include the APDU's traffic to and from the card?

Also, try moving short numBytes = apdu.setIncomingAndReceive(); to the start of the method before accessing the buffer. This method starts the transfer process and calls getBytes to get the first lot of data from the buffer. Make sure this method is only called once. A good place to do this is in the applet process method.

Cheers,
Shane
 
A_nl
Posts:46
Registered: 11/28/09
Re: Sending RSA public key modulus to card   
03.12.2009 17:45 (reply 3 of 30)  (In reply to #2 )
 
 
I'm not exactly sure what you mean. The APDU when loading the applet to the card? I have no trouble installing. I can't see the APDU's when running from the Java program.

What I want to do is transfer a RSA public key from a Java application to a card. My initial code is to large to post here (could mail it if you wish), but I'm quite stuck. I've tried sending the exponent and the modulus to the card. The exponent is short and works okay, the modulus doesn't. I need two store in fact 2 public keys on the card. If I store 2 keys, 2 exponents, and 2 modulo, then the memory will be full right?..
 
safarmer
Posts:961
Registered: 4/6/08
Re: Sending RSA public key modulus to card   
03.12.2009 17:54 (reply 4 of 30)  (In reply to #3 )
 
 
Hi,

What I was looking for was the APDU's that your Java application is sending, not the install APDU's.

What is the RSA key size you are using? If you are using RSA 2048 bit keys, the modulus will be 256 bytes that you have to send to the card. Also if the modulus works out to be a negative number, Java will pad it with a 0x00 byte automatically making 257 bytes. This will cause you problems since you can only send 255 bytes in a single standard length APDU. You may need to implement APDU chaining.

Cheers,
Shane
 
A_nl
Posts:46
Registered: 11/28/09
Re: Sending RSA public key modulus to card   
03.12.2009 17:58 (reply 5 of 30)  (In reply to #4 )
 
 
1024 bit keys. I don't know if I need chaining, it's a 128 bytes modulus then right? Is sending the modulus/exponent to the card the way to go? Can't I just sent the key in one step? If yes, how?
 
safarmer
Posts:961
Registered: 4/6/08
Re: Sending RSA public key modulus to card   
03.12.2009 18:40 (reply 6 of 30)  (In reply to #5 )
 
 
That should be fine.

You can indeed send the key in one go. You would simply send the DER encoded key object (PKCS#1 defines the ASN.1 structure of the key). Once you send the key to the card, you will have to parse the DER-TLV. Since the key is a SEQUENCE of INTEGERS, you can extract the modulus and exponent from the stream. You still need to call setModulus and setExponent on the key object but you can do this in one APDU so it simplifies the communication with the card. You would then have some code like the following:

case SET_KEY:
    key.clearKey();
    key.setModulus(buf, modOff, modLen);
    key.setExponent(buf, expOff, expLen);


There are a few things to be aware of with RSA keys. If the modulus is negative and Java has padded the key object for you, you will need to remove the padding byte before setting the key component on card.

if(modLen % 8 != 0) {
    modLen--;
    modOff++;
}


If you are unfamiliar with ASN.1 and DER encoding, a good reference is A laymans guide to a subset of asn1

With your previous error, it would seem that either the modulus length does not match the key size of the key you created or your card does not support the algorithm. As a guess, I would say that the former is more likely (padded modulus?).

Cheers,
Shane
 
A_nl
Posts:46
Registered: 11/28/09
Re: Sending RSA public key modulus to card   
03.12.2009 18:49 (reply 7 of 30)  (In reply to #6 )
 
 
'You would simply send the DER encoded key object (PKCS#1 defines the ASN.1 structure of the key). Once you send the key to the card, you will have to parse the DER-TLV.'
Uff, this is all waaay too technical for me my friend. Surely someone has done this before right, and surely there's a simple way of doing this. I just want an example on how to do this, not an understanding of all the details.. I hope that isn't necessary to get it to work. RSA on a smartcard,... it must be possible in a non-super-technical way.
 
safarmer
Posts:961
Registered: 4/6/08
Re: Sending RSA public key modulus to card   
03.12.2009 18:55 (reply 8 of 30)  (In reply to #7 )
Helpful
 
To get the DER encoded key you just have to do the following: pubKey.getEncoded(); assuming that pubKey is an instance of an RSAPublicKey. This would be what you send as you data in the APDU.

Cheers,
Shane
 
A_nl
Posts:46
Registered: 11/28/09
Re: Sending RSA public key modulus to card   
03.12.2009 19:03 (reply 9 of 30)  (In reply to #8 )
 
 
I understand.

Meanwhile I've been playing around (while waiting for your help ;)) and made a little something:

JavaCard
package meter;
 
import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.security.KeyPair;
import javacard.security.RSAPublicKey;
 
public class Meter extends Applet {
	private static short RSA_SIZE = (short)1024;
	
	private static final byte METER_CLA = (byte)0xB0;
	
	private static final byte INS_CHANCEPUBKEY = (byte)0x01;
	private static final byte INS_GETPUBKEY    = (byte)0x02;
	
	private static final byte P1_MODULUS  = (byte)0x01;
	private static final byte P1_EXPONENT = (byte)0x02;
 
 
	RSAPublicKey publicKey;
	
	private Meter(byte bArray[], short bOffset, byte bLength) {
		KeyPair keyPair = new KeyPair(KeyPair.ALG_RSA_CRT, RSA_SIZE);
		publicKey = (RSAPublicKey) keyPair.getPublic();
		publicKey.clearKey();
 
		register(bArray, (short) (bOffset + 1), bArray[bOffset]);
	}
 
	public void process(APDU apdu) {
		if (selectingApplet()) //Return 9000 on SELECT
			return;
 
		short numBytes = apdu.setIncomingAndReceive();
		byte[] buf = apdu.getBuffer();
		
		if (buf[ISO7816.OFFSET_CLA] != (byte) METER_CLA)
			ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
		
		switch (buf[ISO7816.OFFSET_INS]) {
		case INS_CHANCEPUBKEY:
			switch (buf[ISO7816.OFFSET_P1]){
			case P1_MODULUS:
				publicKey.setModulus(buf, ISO7816.OFFSET_CDATA, numBytes);
				return;
			case P1_EXPONENT:
				publicKey.setExponent(buf, ISO7816.OFFSET_CDATA, numBytes);
				return;
			}
			return;
		case INS_GETPUBKEY:
			switch (buf[ISO7816.OFFSET_P1]){
			case P1_MODULUS:
				publicKey.getModulus(buf, ISO7816.OFFSET_CDATA);
				apdu.setOutgoing();
				apdu.setOutgoingLength((short) 128);
				apdu.sendBytesLong(buf, (short) ISO7816.OFFSET_CDATA, (short) 128);
				return;
			case P1_EXPONENT:
				publicKey.getExponent(buf, ISO7816.OFFSET_CDATA);
				apdu.setOutgoing();
				apdu.setOutgoingLength((short) 4);
				apdu.sendBytesLong(buf, (short) ISO7816.OFFSET_CDATA, (short) 4);
				return;
			}
			return;
		default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); break; //Unknown instruction
		}
	}
	
	public static void install(byte[] bArray, short bOffset, byte bLength) {
		new Meter(bArray, bOffset, bLength);
	}
}
 
A_nl
Posts:46
Registered: 11/28/09
Re: Sending RSA public key modulus to card   
03.12.2009 19:06 (reply 10 of 30)  (In reply to #9 )
 
 
Continue from last post:

Java:
package terminal;
 
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.interfaces.RSAPublicKey;
 
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CardTerminals;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
import javax.smartcardio.TerminalFactory;
 
@SuppressWarnings("restriction")
public class Consumer {
	private final static byte[] AID	= { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05 };
 
	private static short RSA_SIZE = (short)1024;
 
	private static final byte METER_CLA = (byte)0xB0;
	private static final byte INS_CHANCEPUBKEY = (byte)0x01;
	private static final byte INS_GETPUBKEY    = (byte)0x02;
	
	private static final byte P1_MODULUS  = (byte)0x01;
	private static final byte P1_EXPONENT = (byte)0x02;
	
	private CardTerminal cardTerminal = null;
	private CardChannel ch = null;
	
	RSAPublicKey publicKey;
	
	private static void arrayPrint(byte[] data) {
		System.out.print("{"); arrayPrintBytes(data); System.out.print("} ("); arrayPrintHex(data); System.out.print(")");
	}
	private static void arrayPrintBytes(byte[] data) {
		for (int i = 0; i < data.length; i++)
			System.out.print(data[i] + " ");
	}
	private static void arrayPrintHex(byte[] data) {
		StringBuffer sb = new StringBuffer();
 
		for (int i = 0; i < data.length; i++) {
			String bs = Integer.toHexString(data[i] & 0xFF);
			if (bs.length() == 1)
				sb.append(0);
			sb.append(bs);
		}
		System.out.print(sb.toString());
	}
	
	public Consumer() {
		try { createKeys();}
		catch (NoSuchAlgorithmException e) { System.out.println("No RSA available."); e.printStackTrace();}
		
		TerminalFactory tf = TerminalFactory.getDefault();
		CardTerminals ct = tf.terminals();
 
		cardTerminal = ct.getTerminal("SCM Microsystems Inc. SDI010 Smart Card Reader 0");
		System.out.println("Selected terminal");
	}
	
	private void createKeys() throws NoSuchAlgorithmException{
		KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
	    keyPairGenerator.initialize(1024);
	    KeyPair keyPair = keyPairGenerator.genKeyPair();
	    publicKey = (RSAPublicKey) keyPair.getPublic();
	}
 
	public static boolean validResponse(ResponseAPDU ra) {
		byte[] response = ra.getBytes();
		// Check if response (last 2 bytes) is 0x9000 (code for success)
		return (response[response.length - 2] == (byte)0x90 && response[response.length - 1] == (byte)0x00);
	}
 
	public void communicate() throws Exception{
		if (cardTerminal == null)
			throw new Exception(
					"ERROR: No cardterminal available to communicate.");
		try {
			while (cardTerminal.isCardPresent()) {
				Card card = null;
				if ((card = cardTerminal.connect("*")) != null)
					System.out.println("Connected to card.");
				else {
					System.out.println("ERROR: Failed to connect to card!");
					return;
				}
 
				(card.getATR()).getBytes();
 
				ch = card.getBasicChannel();
 
				/* Start sending APDUs */
				// Select the applet
				System.out.println("\nSelect applet:");
				actionSelect();
				
				actionSetPubKey();
				actionGetPubKey();
				
				card.disconnect(true);
				return;
			}
		} catch (CardException e) {
			System.out.println("Error isCardPresent()" + e.toString());
		}
	}
	
	private boolean actionSelect() {
		ResponseAPDU ra = null;
		try {
			ra = ch.transmit(new CommandAPDU((byte) 0x00, (byte) 0xA4, (byte) 0x04, (byte) 0x00, AID));
		} catch (CardException e) {
			e.printStackTrace();
		}
 
		if (validResponse(ra)) {
			System.out.println("Applet selection success!");
			return true;
		} else {
			System.out.println("ERROR: Applet selection failed!");
			return false;
		}
	}
	
	private void actionSetPubKey() throws CardException {
		ResponseAPDU ra = null;
		byte[] newmod = {
		(byte)0x01, (byte)0x02, (byte)0x03,	(byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08,
		(byte)0x09, (byte)0x10, (byte)0x11,	(byte)0x12, (byte)0x13, (byte)0x14, (byte)0x15, (byte)0x16,
		(byte)0x17, (byte)0x18, (byte)0x19, (byte)0x20, (byte)0x21, (byte)0x22, (byte)0x23, (byte)0x24,
		(byte)0x7D, (byte)0x5B, (byte)0x6D, (byte)0x03, (byte)0x7B, (byte)0xAD, (byte)0x9A, (byte)0xB4,
		(byte)0x58, (byte)0xFE, (byte)0x80, (byte)0x22, (byte)0xEC, (byte)0xF0, (byte)0xAB, (byte)0x84,
		(byte)0xF9, (byte)0x07, (byte)0x84, (byte)0x91, (byte)0xE2, (byte)0x08, (byte)0xA6, (byte)0x9B,
		(byte)0xED, (byte)0xD7, (byte)0x45, (byte)0xC9, (byte)0xDD, (byte)0xBF, (byte)0xF8, (byte)0x7A,
		(byte)0x8B, (byte)0xE1, (byte)0x17, (byte)0xCD, (byte)0x3D, (byte)0xD3, (byte)0x6F, (byte)0xB2,
		(byte)0x59, (byte)0x0C, (byte)0x0E, (byte)0x47, (byte)0x0B, (byte)0x8E, (byte)0x83, (byte)0xC5,
		(byte)0x0F, (byte)0xAF, (byte)0xD8, (byte)0x21, (byte)0x0C, (byte)0xD1, (byte)0x0B, (byte)0xB4,
		(byte)0x24, (byte)0x8D, (byte)0x66, (byte)0xAC, (byte)0x93, (byte)0xA3, (byte)0xE4, (byte)0x61,
		(byte)0xEF, (byte)0x26, (byte)0x50, (byte)0x1C, (byte)0x30, (byte)0xED, (byte)0x73, (byte)0xF1,
		(byte)0x92, (byte)0xD8, (byte)0x2C, (byte)0xC6, (byte)0x38, (byte)0xD4, (byte)0x6D, (byte)0x81,
		(byte)0x48, (byte)0x2B, (byte)0xCC, (byte)0x42, (byte)0xF8, (byte)0x60, (byte)0x61, (byte)0xAD,
		(byte)0x8D, (byte)0x7F, (byte)0x8D, (byte)0x6D, (byte)0x87, (byte)0xBF, (byte)0x7D, (byte)0x1C,
		(byte)0x61, (byte)0x2B, (byte)0xC0, (byte)0x42, (byte)0x47, (byte)0xDB, (byte)0xDD, (byte)0xC9,
		};
		
		byte[] newexp = { (byte)0x01, (byte)0x02 };
		ra = ch.transmit(new CommandAPDU(METER_CLA, INS_CHANCEPUBKEY, P1_MODULUS,  (byte) 0x00, newmod));
		ra = ch.transmit(new CommandAPDU(METER_CLA, INS_CHANCEPUBKEY, P1_EXPONENT, (byte) 0x00, newexp));
 
		if (validResponse(ra))
			System.out.print("Succesful key set.");
		else
			System.out.println("ERROR: Unable to set key.");
	}
	
	
	private void actionGetPubKey() throws CardException {
		ResponseAPDU ra = null;
		ra = ch.transmit(new CommandAPDU(METER_CLA, INS_GETPUBKEY, P1_MODULUS,  (byte) 0x00));
		arrayPrint(ra.getData());
		System.out.println();
		ra = ch.transmit(new CommandAPDU(METER_CLA, INS_GETPUBKEY, P1_EXPONENT, (byte) 0x00));
		arrayPrint(ra.getData());
	}
	
}


Output:
Selected terminal
Connected to card.
 
Select applet:
Applet selection success!
Succesful key set.{1 2 3 4 5 6 7 ...more } (01020304050607 ...more)
{1 2 0 0 } (01020000)


Any obvious flaws (besides the fast 'n messy coding style ;))
 
safarmer
Posts:961
Registered: 4/6/08
Re: Sending RSA public key modulus to card      
03.12.2009 19:14 (reply 11 of 30)  (In reply to #9 )
 
 
You might want to change the following code in the constructor from

KeyPair keyPair = new KeyPair(KeyPair.ALG_RSA_CRT, RSA_SIZE);
publicKey = (RSAPublicKey) keyPair.getPublic();
publicKey.clearKey();


to

publicKey = (RSAPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, KeyBuilder.LENGTH_RSA_1024, false);


Cheers,
Shane
 
A_nl
Posts:46
Registered: 11/28/09
Re: Sending RSA public key modulus to card   
03.12.2009 19:23 (reply 12 of 30)  (In reply to #11 )
 
 
Thanks, you're a great help (especially since it's 4:22 at night..)

Now, for enc/decryption I will follow the RunTest8 and 9 from http://forums.sun.com/thread.jspa?messageID=1737235#1737235. That seems appropriate?
 
safarmer
Posts:961
Registered: 4/6/08
Re: Sending RSA public key modulus to card   
03.12.2009 19:33 (reply 13 of 30)  (In reply to #12 )
 
 
That is a good place to start. Just remember that you applet will only do encryption. The host application (J2SE) will do the decryption with the private key.

Cheers,
Shane
 
A_nl
Posts:46
Registered: 11/28/09
Re: Sending RSA public key modulus to card   
03.12.2009 19:47 (reply 14 of 30)  (In reply to #13 )
 
 
Right. I'm having my card communicate with a host application (host1), and also another application (host2). I want secure connections between the card and host1, and between host1 and host2 (card and host2 do not directly communicate).

I'm not sure why the applet should only do encryption?
 
This topic has 30 replies on 3 pages.    1 | 2 | 3 | Next »
Back to Forum
 
Read the Developer Forums Code of Conduct

Click to email this message Email this Topic

Edit this Topic
  
 
 
Forums Statistics

    About Sun forums
    • Sun Forums is a large collection of user generated discussions. It is here to help you ask questions, find answers, and participate in discussions.

      Check out our guide on Getting started with Sun Forums for a full walkthrough of how to best leverage the benefits of this community.

    Powered by Jive Forums