Skip to content
Snippets Groups Projects
Commit 4232b0a6 authored by da1l6's avatar da1l6
Browse files

Update Javacard source provided by Martin + Fixes by da1l6

parent cc81ba57
Branches master
No related tags found
No related merge requests found
/**
*
*/
package ms.warpzone.tuer.applet;
import javacard.framework.APDU;
import javacard.framework.ISO7816;
import javacard.framework.Applet;
import javacard.framework.ISOException;
import javacard.framework.JCSystem;
import javacard.framework.Util;
import javacard.security.MessageDigest;
import javacard.security.RandomData;
/**
* @author warpzone
*
*/
public class TuereApplet extends Applet {
static final byte CURRENT_VERSION = 1;
static final byte CHAL_LEN = 32;
// Warnung: Alignment beachten (Vielfaches von 64 Bytes) oder SHA-Code anpassen.
static final byte SECRET_LEN = 64;
MessageDigest md_sha = MessageDigest.getInstance(MessageDigest.ALG_SHA, false);
RandomData devurandom = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
// Backup-Secret wird fr trseitigen Fehler vorgehalten. secretBackup wird verwendet gdw. secretBackupActive==true
byte[] secret = new byte[SECRET_LEN];
byte[] secretBackup = new byte[SECRET_LEN]; // Backupsecret fr trseitigen Schlssel-Aktualisierungsfehler.
boolean[] secretBackupActive = JCSystem.makeTransientBooleanArray((short)1, JCSystem.CLEAR_ON_DESELECT);
// Hlt das Challenge, das wir in 0x02 an die Tr gestellt haben.
byte[] challenge = JCSystem.makeTransientByteArray(CHAL_LEN, JCSystem.CLEAR_ON_DESELECT);
public TuereApplet() {
for(byte i=0; i<SECRET_LEN; i++){
secret[i] = 0x00;
secretBackup[i] = 0x00;
}
}
public static void install(byte[] bArray, short bOffset, byte bLength) {
new TuereApplet().register(bArray, (short) (bOffset + 1),
bArray[bOffset]);
}
public boolean select() {
secretBackupActive[0] = true;
return super.select();
}
public void process(APDU apdu) {
// Good practice: Return 9000 on SELECT
if (selectingApplet()) {
return;
}
byte[] buf = apdu.getBuffer();
short recv;
short responseApduStartOffset;
short hashSize;
// Schlssel alternieren bei Misserfolg.
byte[] currentSecret = secretBackupActive[0] ? secretBackup : secret;
switch (buf[ISO7816.OFFSET_INS]) {
/**
* Out = Versionsnummer dieses Applets
* #Out = 1
*/
case (byte) 0x00:
buf[0] = CURRENT_VERSION;
apdu.setOutgoingAndSend((short)0, (short)1);
break;
/**
* In = Neues Secret
* #In = 64
*
* Die Karte wird mit dem neuen bergebenen Secret initialisiert.
* Dieser Vorgang wird genau einmal zugelassen.
*/
case (byte) 0x01:
for(byte i=0; i<SECRET_LEN; i++){
if(secret[i] != 0x00){
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
}
if(buf[ISO7816.OFFSET_LC] != SECRET_LEN){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
recv = apdu.setIncomingAndReceive();
if(recv != SECRET_LEN){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
// Voraussetzungen erfllt.
JCSystem.beginTransaction();
Util.arrayCopy(buf, ISO7816.OFFSET_CDATA, secret, (short)0, SECRET_LEN);
JCSystem.commitTransaction();
break;
/**
* In = Challenge fr Auth der Karte
* #In = 32
* Out = sha(secret+salt) + Challenge fr Auth der Tr
* #Out = 20 32 = 52
*/
case (byte) 0x02:
if(buf[ISO7816.OFFSET_LC] != CHAL_LEN){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
recv = apdu.setIncomingAndReceive();
if(recv != CHAL_LEN){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
short le = (short)((short)buf[ISO7816.OFFSET_CDATA + CHAL_LEN] & 0x00FF);
if(le < md_sha.getLength()){
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
}
// Voraussetzungen erfllt.
// Schlssel alternieren bei Misserfolg.
secretBackupActive[0] = !secretBackupActive[0];
currentSecret = secretBackupActive[0] ? secretBackup : secret;
md_sha.reset();
md_sha.update(currentSecret, (short)0, SECRET_LEN);
responseApduStartOffset = ISO7816.OFFSET_CDATA + CHAL_LEN + 1;
// Wir werden hier gleich Platz im APDU-Puffer brauchen. Ist der da?
if(buf.length - responseApduStartOffset < md_sha.getLength() + CHAL_LEN){
ISOException.throwIt(ISO7816.SW_BYTES_REMAINING_00);
}
hashSize = md_sha.doFinal(buf, ISO7816.OFFSET_CDATA, CHAL_LEN, buf, responseApduStartOffset);
devurandom.generateData(challenge, (short)0, CHAL_LEN);
Util.arrayCopyNonAtomic(challenge, (short)0, buf, (short)(responseApduStartOffset + hashSize), CHAL_LEN);
apdu.setOutgoingAndSend(responseApduStartOffset, (short)(hashSize + CHAL_LEN));
break;
/**
* In = Neues Secret gexored mit altem + Antwort auf Challenge aus 0x02
* #In = 64 20 = 84
*
* Bei Erfolg: secret := CDATA xor secret
*/
case (byte) 0x03:
if(buf[ISO7816.OFFSET_LC] != SECRET_LEN + md_sha.getLength()){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
recv = apdu.setIncomingAndReceive();
if(recv != SECRET_LEN + md_sha.getLength()){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
responseApduStartOffset = (short)(ISO7816.OFFSET_CDATA + SECRET_LEN + md_sha.getLength());
md_sha.reset();
md_sha.update(currentSecret, (short)0, SECRET_LEN);
md_sha.doFinal(challenge, (short)0, CHAL_LEN, buf, responseApduStartOffset);
if(Util.arrayCompare(buf, (short)(ISO7816.OFFSET_CDATA + SECRET_LEN), buf, responseApduStartOffset, md_sha.getLength()) != 0) {
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
}
//Response passt; Tr authentifiziert.
for(byte i=0; i<SECRET_LEN; i++){
buf[responseApduStartOffset+i] = (byte)(currentSecret[i] ^ buf[ISO7816.OFFSET_CDATA + i]);
}
JCSystem.beginTransaction();
Util.arrayCopy(currentSecret, (short)0, secretBackup, (short)0, SECRET_LEN);
Util.arrayCopy(buf, responseApduStartOffset, secret, (short)0, SECRET_LEN);
secretBackupActive[0] = true;
JCSystem.commitTransaction();
break;
/**
* Keyausgabe fr Debugzwecke.
*
* Out = Secret + Backup-Secret
*/
case (byte) 0xFE:
responseApduStartOffset = ISO7816.OFFSET_CDATA;
Util.arrayCopyNonAtomic(secret, (short)0, buf, responseApduStartOffset, SECRET_LEN);
Util.arrayCopyNonAtomic(secretBackup, (short)0, buf, (short)(responseApduStartOffset+SECRET_LEN), SECRET_LEN);
apdu.setOutgoingAndSend(responseApduStartOffset, (short)(2*SECRET_LEN));
break;
/**
* Secrets nullen fr Debugzwecke.
*/
case (byte) 0xFF:
JCSystem.beginTransaction();
for(byte i=0; i<SECRET_LEN; i++){
secret[i] = 0x00;
secretBackup[i] = 0x00;
}
JCSystem.commitTransaction();
break;
/**
* Unbekannte Instruktion (INS).
*/
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
}
/**
*
*/
package ms.warpzone.tuer.applet;
import javacard.framework.APDU;
import javacard.framework.ISO7816;
import javacard.framework.Applet;
import javacard.framework.ISOException;
import javacard.framework.JCSystem;
import javacard.framework.Util;
import javacard.security.MessageDigest;
import javacard.security.RandomData;
public class TuereApplet extends Applet {
static final byte CURRENT_VERSION = 1;
static final byte CHAL_LEN = 32;
// Warnung: Alignment beachten (Vielfaches von 64 Bytes) oder SHA-Code anpassen.
static final byte SECRET_LEN = 64;
MessageDigest md_sha = MessageDigest.getInstance(MessageDigest.ALG_SHA, false);
RandomData devurandom = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
static byte[] store = new byte[2*SECRET_LEN];
// Backup-Secret wird für türseitigen Fehler vorgehalten. secretBackup wird verwendet gdw. secretBackupActive==true
boolean[] secretBackupActive = JCSystem.makeTransientBooleanArray((short)1, JCSystem.CLEAR_ON_DESELECT);
// Hält das Challenge, das wir in 0x02 an die Tür gestellt haben.
byte[] challenge = JCSystem.makeTransientByteArray(CHAL_LEN, JCSystem.CLEAR_ON_DESELECT);
public TuereApplet() {
//Initialisierung erfolgt oben und im KeyStore.
}
public static void install(byte[] bArray, short bOffset, byte bLength) {
new TuereApplet().register(bArray, (short) (bOffset + 1),
bArray[bOffset]);
}
public boolean select() {
secretBackupActive[0] = true;
return super.select();
}
public void process(APDU apdu) {
// Good practice: Return 9000 on SELECT
if (selectingApplet()) {
return;
}
byte[] buf = apdu.getBuffer();
short recv;
short responseApduStartOffset;
short hashSize;
// Schlüssel alternieren bei Misserfolg.
// byte[] currentSecret = secretBackupActive[0] ? secretBackup : secret;
short secretOffset = secretBackupActive[0] ? SECRET_LEN : 0;
switch (buf[ISO7816.OFFSET_INS]) {
/**
* Out = Versionsnummer dieses Applets
* #Out = 1
*/
case (byte) 0x00:
buf[0] = CURRENT_VERSION;
apdu.setOutgoingAndSend((short)0, (short)1);
break;
/**
* In = Neues Secret
* #In = 64
*
* Die Karte wird mit dem neuen übergebenen Secret initialisiert.
* Dieser Vorgang wird genau einmal zugelassen.
*/
case (byte) 0x01:
for(short i=0; i<store.length; i++){
if(store[i] != 0x00){
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
}
if(buf[ISO7816.OFFSET_LC] != SECRET_LEN){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
recv = apdu.setIncomingAndReceive();
if(recv != SECRET_LEN){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
// Voraussetzungen erfüllt.
JCSystem.beginTransaction();
Util.arrayCopy(buf, ISO7816.OFFSET_CDATA, store, (short)0, SECRET_LEN);
JCSystem.commitTransaction();
break;
/**
* In = Challenge für Auth der Karte
* #In = 32
* Out = sha(secret+salt) + Challenge für Auth der Tür
* #Out = 20 32 = 52
*/
case (byte) 0x02:
if(buf[ISO7816.OFFSET_LC] != CHAL_LEN){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
recv = apdu.setIncomingAndReceive();
if(recv != CHAL_LEN){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
short le = (short)((short)buf[ISO7816.OFFSET_CDATA + CHAL_LEN] & 0x00FF);
if(le < md_sha.getLength()){
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
}
// Voraussetzungen erfüllt.
// Schlüssel alternieren bei Misserfolg.
secretBackupActive[0] = !secretBackupActive[0];
secretOffset = secretBackupActive[0] ? SECRET_LEN : 0;
md_sha.reset();
md_sha.update(store, (short)secretOffset, SECRET_LEN);
responseApduStartOffset = ISO7816.OFFSET_CDATA + CHAL_LEN + 1;
// Wir werden hier gleich Platz im APDU-Puffer brauchen. Ist der da?
if(buf.length - responseApduStartOffset < md_sha.getLength() + CHAL_LEN){
ISOException.throwIt(ISO7816.SW_BYTES_REMAINING_00);
}
hashSize = md_sha.doFinal(buf, ISO7816.OFFSET_CDATA, CHAL_LEN, buf, responseApduStartOffset);
devurandom.generateData(challenge, (short)0, CHAL_LEN);
Util.arrayCopyNonAtomic(challenge, (short)0, buf, (short)(responseApduStartOffset + hashSize), CHAL_LEN);
apdu.setOutgoingAndSend(responseApduStartOffset, (short)(hashSize + CHAL_LEN));
break;
/**
* In = Neues Secret gexored mit altem + Antwort auf Challenge aus 0x02
* #In = 64 20 = 84
*
* Bei Erfolg: secret := CDATA xor secret
*/
case (byte) 0x03:
if(buf[ISO7816.OFFSET_LC] != SECRET_LEN + md_sha.getLength()){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
recv = apdu.setIncomingAndReceive();
if(recv != SECRET_LEN + md_sha.getLength()){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
responseApduStartOffset = (short)(ISO7816.OFFSET_CDATA + SECRET_LEN + md_sha.getLength());
md_sha.reset();
md_sha.update(store, (short)secretOffset, SECRET_LEN);
md_sha.doFinal(challenge, (short)0, CHAL_LEN, buf, responseApduStartOffset);
if(Util.arrayCompare(buf, (short)(ISO7816.OFFSET_CDATA + SECRET_LEN), buf, responseApduStartOffset, md_sha.getLength()) != 0) {
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
}
//Response passt; Tür authentifiziert.
for(byte i=0; i<SECRET_LEN; i++){
buf[responseApduStartOffset+i] = (byte)(store[i+secretOffset] ^ buf[ISO7816.OFFSET_CDATA + i]);
}
JCSystem.beginTransaction();
Util.arrayCopy(store, (short)secretOffset, store, secretOffset==SECRET_LEN ? 0 : SECRET_LEN, SECRET_LEN);
Util.arrayCopy(buf, responseApduStartOffset, store, (short)0, SECRET_LEN); //hier wird auf jeden Fall ins erste Secret kopiert.
secretBackupActive[0] = true;
JCSystem.commitTransaction();
break;
/**
* Keyausgabe für Debugzwecke.
*
* Out = Secret + Backup-Secret
*/
case (byte) 0xFE:
responseApduStartOffset = ISO7816.OFFSET_CDATA;
Util.arrayCopyNonAtomic(store, (short)0, buf, responseApduStartOffset, (short)(2*SECRET_LEN));
apdu.setOutgoingAndSend(responseApduStartOffset, (short)(2*SECRET_LEN));
break;
/**
* Secrets nullen für Debugzwecke.
*/
case (byte) 0xFF:
JCSystem.beginTransaction();
Util.arrayFillNonAtomic(store, (short)0, (short)store.length, (byte)0);
JCSystem.commitTransaction();
break;
/**
* Unbekannte Instruktion (INS).
*/
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment