Last active
March 26, 2018 13:22
-
-
Save half2me/014ac4612be3d4234ef49162e47c1a60 to your computer and use it in GitHub Desktop.
Javacard PKI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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