Skip to content

Instantly share code, notes, and snippets.

@half2me
Last active March 26, 2018 13:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save half2me/014ac4612be3d4234ef49162e47c1a60 to your computer and use it in GitHub Desktop.
Save half2me/014ac4612be3d4234ef49162e47c1a60 to your computer and use it in GitHub Desktop.
Javacard PKI
package com.fidesmo.javacard.example;
import javacard.framework.*;
import javacard.security.*;
public class ExampleCardlet extends Applet
{
private static final short MAX_LENGTH = 256;
private static final byte[] hello = {'p','k','i','t','c','h'};
// Keys
private KeyPair kp;
private Signature signature;
// Signature scratchpad
private byte[] scratchpad;
protected ExampleCardlet() {
scratchpad = new byte[256];
kp = new KeyPair(KeyPair.ALG_RSA, KeyBuilder.LENGTH_RSA_1024);
kp.genKeyPair();
signature = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1, false);
signature.init(kp.getPrivate(), Signature.MODE_SIGN);
register();
}
/**
* Installs this applet.
* @param bArray the array containing installation parameters
* @param bOffset the starting offset in bArray
* @param bLength the length in bytes of the parameter data in bArray
*/
public static void install(byte[] bArray, short bOffset, byte bLength){
new ExampleCardlet();
}
/**
* Processes an incoming APDU. Will always respond with the helloFidesmo string,
* regardless of what is received.
* @see APDU
* @param apdu the incoming APDU
* @exception ISOException with the response bytes per ISO 7816-4
*/
public void process(APDU apdu) {
byte buffer[] = apdu.getBuffer();
if (this.selectingApplet()) {
Util.arrayCopyNonAtomic(hello, (short) 0, buffer, (short) 0, (short) hello.length);
apdu.setOutgoingAndSend((short) 0, (short)hello.length);
return;
}
switch (buffer[ISO7816.OFFSET_INS]) {
case 0x01:
sendHello(apdu);
return;
case 0x02:
sendPubKeyExp(apdu);
return;
case 0x03:
sendPubKeyMod(apdu);
return;
case 0x04:
signData(apdu);
return;
case 0x05:
echo(apdu);
return;
default:
ISOException.throwIt (ISO7816.SW_INS_NOT_SUPPORTED);
}
}
private void signData(APDU apdu) {
byte[] buffer = apdu.getBuffer();
//short dataLen = apdu.setIncomingAndReceive();
short signLen = signature.sign(buffer, apdu.getOffsetCdata(), apdu.getIncomingLength(), scratchpad, (short) 0);
Util.arrayCopyNonAtomic(scratchpad, (short) 0, buffer, (short) 0, signLen);
apdu.setOutgoingAndSend((short) 0, signLen);
}
private void sendHello(APDU apdu) {
byte buffer[] = apdu.getBuffer();
Util.arrayCopyNonAtomic(hello, (short)0, buffer, (short)0, (short)hello.length);
apdu.setOutgoingAndSend((short)0, (short)hello.length);
}
private void sendPubKeyExp(APDU apdu) {
byte buffer[] = apdu.getBuffer();
RSAPublicKey pub = (RSAPublicKey) kp.getPublic();
short len = pub.getExponent(buffer, (short) 0);
apdu.setOutgoingAndSend((short)0, len);
}
private void sendPubKeyMod(APDU apdu) {
byte buffer[] = apdu.getBuffer();
RSAPublicKey pub = (RSAPublicKey) kp.getPublic();
short len = pub.getModulus(buffer, (short) 0);
apdu.setOutgoingAndSend((short)0, len);
}
private void echo(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short len = apdu.getIncomingLength();
Util.arrayFillNonAtomic(buffer, (short) 0, (short) 1, (byte) len);
apdu.setOutgoingAndSend((short) 0, (short)1);
}
}
package com.fidesmo.javacard.example;
import com.licel.jcardsim.base.Simulator;
import javacard.framework.AID;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
public class Tester {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
// 1. create simulator
Simulator simulator = new Simulator();
// 2. install applet
byte[] appletAIDBytes = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
AID appletAID = new AID(appletAIDBytes, (short) 0, (byte) appletAIDBytes.length);
simulator.installApplet(appletAID, ExampleCardlet.class);
// 3. select applet
simulator.selectApplet(appletAID);
// 4. Gut public key
BigInteger exp = new BigInteger(1, new ResponseAPDU(simulator.transmitCommand((new CommandAPDU(0x00, 0x02, 0x00, 0x00)).getBytes())).getData());
BigInteger mod = new BigInteger(1, new ResponseAPDU(simulator.transmitCommand((new CommandAPDU(0x00, 0x03, 0x00, 0x00)).getBytes())).getData());
RSAPublicKeySpec spec = new RSAPublicKeySpec(mod, exp);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pub = kf.generatePublic(spec);
// 5. Sign random data
SecureRandom random = new SecureRandom();
byte[] challenge = new byte[64];
random.nextBytes(challenge);
byte[] signature = new ResponseAPDU(simulator.transmitCommand((new CommandAPDU(0x00, 0x04, 0x00, 0x00, challenge)).getBytes())).getData();
// 6. Validate
Signature verifier = Signature.getInstance("SHA1withRSA");
verifier.initVerify(pub);
verifier.update(challenge);
boolean valid = verifier.verify(signature);
System.out.println(valid ? "Valid!" : "Invalid");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment