add (draft of) cash applet
This commit is contained in:
parent
ac3c24852f
commit
09c725dcb2
|
@ -29,7 +29,10 @@ javacard {
|
|||
aid = '0xA0:0x00:0x00:0x08:0x04:0x00:0x01:0x02'
|
||||
className = 'NDEFApplet'
|
||||
}
|
||||
|
||||
applet {
|
||||
aid = '0xA0:0x00:0x00:0x08:0x04:0x00:0x01:0x03'
|
||||
className = 'CashApplet'
|
||||
}
|
||||
version = '2.3'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
package im.status.keycard;
|
||||
|
||||
import javacard.framework.*;
|
||||
import javacard.security.*;
|
||||
|
||||
public class CashApplet extends Applet {
|
||||
private static final short SIGN_OUT_OFF = ISO7816.OFFSET_CDATA + MessageDigest.LENGTH_SHA_256;
|
||||
|
||||
private KeyPair keypair;
|
||||
private ECPublicKey publicKey;
|
||||
private ECPrivateKey privateKey;
|
||||
|
||||
private Crypto crypto;
|
||||
private SECP256k1 secp256k1;
|
||||
|
||||
private Signature signature;
|
||||
|
||||
/**
|
||||
* Invoked during applet installation. Creates an instance of this class. The installation parameters are passed in
|
||||
* the given buffer.
|
||||
*
|
||||
* @param bArray installation parameters buffer
|
||||
* @param bOffset offset where the installation parameters begin
|
||||
* @param bLength length of the installation parameters
|
||||
*/
|
||||
public static void install(byte[] bArray, short bOffset, byte bLength) {
|
||||
new CashApplet(bArray, bOffset, bLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Application constructor. All memory allocation is done here. The reason for this is two-fold: first the card might
|
||||
* not have Garbage Collection so dynamic allocation will eventually eat all memory. The second reason is to be sure
|
||||
* that if the application installs successfully, there is no risk of running out of memory because of other applets
|
||||
* allocating memory. The constructor also registers the applet with the JCRE so that it becomes selectable.
|
||||
*
|
||||
* @param bArray installation parameters buffer
|
||||
* @param bOffset offset where the installation parameters begin
|
||||
* @param bLength length of the installation parameters
|
||||
*/
|
||||
public CashApplet(byte[] bArray, short bOffset, byte bLength) {
|
||||
crypto = new Crypto();
|
||||
secp256k1 = new SECP256k1(crypto);
|
||||
|
||||
keypair = new KeyPair(KeyPair.ALG_EC_FP, SECP256k1.SECP256K1_KEY_SIZE);
|
||||
publicKey = (ECPublicKey) keypair.getPublic();
|
||||
privateKey = (ECPrivateKey) keypair.getPrivate();
|
||||
secp256k1.setCurveParameters(publicKey);
|
||||
secp256k1.setCurveParameters(privateKey);
|
||||
keypair.genKeyPair();
|
||||
|
||||
signature = Signature.getInstance(Signature.ALG_ECDSA_SHA_256, false);
|
||||
signature.init(privateKey, Signature.MODE_SIGN);
|
||||
|
||||
register(bArray, (short) (bOffset + 1), bArray[bOffset]);
|
||||
}
|
||||
|
||||
public void process(APDU apdu) throws ISOException {
|
||||
apdu.setIncomingAndReceive();
|
||||
|
||||
// Since selection can happen not only by a SELECT command, we check for that separately.
|
||||
if (selectingApplet()) {
|
||||
selectApplet(apdu);
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] apduBuffer = apdu.getBuffer();
|
||||
|
||||
try {
|
||||
switch (apduBuffer[ISO7816.OFFSET_INS]) {
|
||||
case KeycardApplet.INS_SIGN:
|
||||
sign(apdu);
|
||||
break;
|
||||
default:
|
||||
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
|
||||
break;
|
||||
}
|
||||
} catch (CryptoException ce) {
|
||||
ISOException.throwIt((short)(ISO7816.SW_UNKNOWN | ce.getReason()));
|
||||
} catch (Exception e) {
|
||||
ISOException.throwIt(ISO7816.SW_UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
private void selectApplet(APDU apdu) {
|
||||
byte[] apduBuffer = apdu.getBuffer();
|
||||
|
||||
apduBuffer[0] = KeycardApplet.TLV_PUB_KEY;
|
||||
apduBuffer[1] = (byte) publicKey.getW(apduBuffer, (short) 2);
|
||||
|
||||
apdu.setOutgoingAndSend((short) 0, (short)(apduBuffer[1] + 2));
|
||||
}
|
||||
|
||||
private void sign(APDU apdu) {
|
||||
byte[] apduBuffer = apdu.getBuffer();
|
||||
|
||||
apduBuffer[SIGN_OUT_OFF] = KeycardApplet.TLV_SIGNATURE_TEMPLATE;
|
||||
apduBuffer[(short) (SIGN_OUT_OFF + 3)] = KeycardApplet.TLV_PUB_KEY;
|
||||
short outLen = apduBuffer[(short) (SIGN_OUT_OFF + 4)] = Crypto.KEY_PUB_SIZE;
|
||||
|
||||
publicKey.getW(apduBuffer, (short) (SIGN_OUT_OFF + 5));
|
||||
|
||||
outLen += 5;
|
||||
short sigOff = (short) (SIGN_OUT_OFF + outLen);
|
||||
|
||||
outLen += signature.signPreComputedHash(apduBuffer, ISO7816.OFFSET_CDATA, MessageDigest.LENGTH_SHA_256, apduBuffer, sigOff);
|
||||
outLen += crypto.fixS(apduBuffer, sigOff);
|
||||
|
||||
apduBuffer[(short) (SIGN_OUT_OFF + 1)] = (byte) 0x81;
|
||||
apduBuffer[(short) (SIGN_OUT_OFF + 2)] = (byte) (outLen - 3);
|
||||
|
||||
apdu.setOutgoingAndSend(SIGN_OUT_OFF, outLen);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue