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