Skip to content

Commit

Permalink
Add message buffering
Browse files Browse the repository at this point in the history
  • Loading branch information
dufkan committed Jul 27, 2021
1 parent 534971b commit d9f52ca
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 53 deletions.
2 changes: 1 addition & 1 deletion applet/src/main/java/jced25519/Consts.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
public class Consts {
public static final byte CLA_ED25519 = (byte) 0x00;
public static final byte INS_KEYGEN = (byte) 0xD0;
public static final byte INS_SIGN = (byte) 0xD1;
public static final byte INS_GET_PRIV = (byte) 0xD2;
public static final byte INS_SET_PUB = (byte) 0xD3;
public static final byte INS_SIGN_INIT = (byte) 0xD4;
public static final byte INS_SIGN_NONCE = (byte) 0xD5;
public static final byte INS_SIGN_FINALIZE = (byte) 0xD6;
public static final byte INS_SIGN_UPDATE = (byte) 0xD7;

public final static short SW_Exception = (short) 0xff01;
public final static short SW_ArrayIndexOutOfBoundsException = (short) 0xff02;
Expand Down
75 changes: 24 additions & 51 deletions applet/src/main/java/jced25519/JCEd25519.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,20 @@
import jced25519.swalgs.*;

public class JCEd25519 extends Applet implements MultiSelectable {
private ECConfig ecc;
private ECCurve curve;
private Bignat privateKey, privateNonce, signature;
private Bignat transformC, transformA3, transformX, transformY, eight;
private ECPoint point;
private final ECCurve curve;
private final Bignat privateKey, privateNonce, signature;
private final Bignat transformC, transformA3, transformX, transformY, eight;
private final ECPoint point;

private byte[] masterKey = new byte[32];
private byte[] prefix = new byte[32];
private byte[] publicKey = new byte[32];
private byte[] publicNonce = new byte[32];
private final byte[] masterKey = new byte[32];
private final byte[] prefix = new byte[32];
private final byte[] publicKey = new byte[32];
private final byte[] publicNonce = new byte[32];

private MessageDigest hasher;

private byte[] ramArray = JCSystem.makeTransientByteArray(Wei25519.POINT_SIZE, JCSystem.CLEAR_ON_DESELECT);
private RandomData random = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
private final byte[] ramArray = JCSystem.makeTransientByteArray(Wei25519.POINT_SIZE, JCSystem.CLEAR_ON_DESELECT);
private final RandomData random = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);

public static void install(byte[] bArray, short bOffset, byte bLength) {
new JCEd25519(bArray, bOffset, bLength);
Expand All @@ -55,7 +54,7 @@ public JCEd25519(byte[] buffer, short offset, byte length) {
hasher = new Sha2(Sha2.SHA_512);
}

ecc = new ECConfig((short) 256);
ECConfig ecc = new ECConfig((short) 256);

privateKey = new Bignat((short) 32, JCSystem.MEMORY_TYPE_PERSISTENT, ecc.bnh);

Expand Down Expand Up @@ -88,9 +87,6 @@ public void process(APDU apdu) {
case Consts.INS_KEYGEN:
generateKeypair(apdu);
break;
case Consts.INS_SIGN:
sign(apdu);
break;

case Consts.INS_SET_PUB:
setPublicKey(apdu);
Expand All @@ -104,6 +100,9 @@ public void process(APDU apdu) {
case Consts.INS_SIGN_FINALIZE:
signFinalize(apdu);
break;
case Consts.INS_SIGN_UPDATE:
signUpdate(apdu);
break;

case Consts.INS_GET_PRIV:
Util.arrayCopyNonAtomic(privateKey.as_byte_array(), (short) 0, apdu.getBuffer(), (short) 0, (short) 32);
Expand Down Expand Up @@ -178,37 +177,10 @@ private void generateKeypair(APDU apdu) {
}
}

private void sign(APDU apdu) {
private void setPublicKey(APDU apdu) {
byte[] apduBuffer = apdu.getBuffer();

// Generate nonce R
// deterministicNonce(apduBuffer, ISO7816.OFFSET_CDATA, (short) 32);
randomNonce();
point.setW(curve.G, (short) 0, curve.POINT_SIZE);
point.multiplication(privateNonce);

// Compute challenge e
hasher.reset();
encodeEd25519(point, ramArray, (short) 0);
hasher.update(ramArray, (short) 0, curve.COORD_SIZE); // R
hasher.update(publicKey, (short) 0, curve.COORD_SIZE); // A
hasher.doFinal(apduBuffer, ISO7816.OFFSET_CDATA, (short) 32, apduBuffer, (short) 0); // m
changeEndianity(apduBuffer, (short) 0, (short) 64);
signature.set_size((short) 64);
signature.from_byte_array((short) 64, (short) 0, apduBuffer, (short) 0);
signature.mod(curve.rBN);
signature.deep_resize((short) 32);

// Compute signature s = r + ex
signature.mod_mult(privateKey, signature, curve.rBN);
signature.mod_add(privateNonce, curve.rBN);

// Return signature (R, s)
Util.arrayCopyNonAtomic(ramArray, (short) 0, apduBuffer, (short) 0, curve.COORD_SIZE);
signature.prepend_zeros(curve.COORD_SIZE, apduBuffer, curve.COORD_SIZE);
changeEndianity(apduBuffer, curve.COORD_SIZE, curve.COORD_SIZE);

apdu.setOutgoingAndSend((short) 0, (short) (curve.COORD_SIZE + curve.COORD_SIZE));
Util.arrayCopyNonAtomic(apduBuffer, ISO7816.OFFSET_CDATA, publicKey, (short) 0, (short) publicKey.length);
apdu.setOutgoing();
}

private void signInit(APDU apdu) {
Expand All @@ -219,12 +191,11 @@ private void signInit(APDU apdu) {
randomNonce();
point.setW(curve.G, (short) 0, curve.POINT_SIZE);
point.multiplication(privateNonce);
hasher.reset();
if (offload) {
hasher.reset();
point.getW(apduBuffer, (short) 0);
apdu.setOutgoingAndSend((short) 0, curve.POINT_SIZE);
} else {
hasher.reset();
encodeEd25519(point, ramArray, (short) 0);
Util.arrayCopyNonAtomic(ramArray, (short) 0, publicNonce, (short) 0, curve.COORD_SIZE);
hasher.update(ramArray, (short) 0, curve.COORD_SIZE); // R
Expand All @@ -244,7 +215,8 @@ private void signNonce(APDU apdu) {

private void signFinalize(APDU apdu) {
byte[] apduBuffer = apdu.getBuffer();
hasher.doFinal(apduBuffer, ISO7816.OFFSET_CDATA, (short) 32, apduBuffer, (short) 0); // m
short len = (short) ((short) apduBuffer[ISO7816.OFFSET_P1] & (short) 0xff);
hasher.doFinal(apduBuffer, ISO7816.OFFSET_CDATA, len, apduBuffer, (short) 0); // m
changeEndianity(apduBuffer, (short) 0, (short) 64);
signature.set_size((short) 64);
signature.from_byte_array((short) 64, (short) 0, apduBuffer, (short) 0);
Expand All @@ -262,10 +234,10 @@ private void signFinalize(APDU apdu) {
apdu.setOutgoingAndSend((short) 0, (short) (curve.COORD_SIZE + curve.COORD_SIZE));
}


private void setPublicKey(APDU apdu) {
private void signUpdate(APDU apdu) {
byte[] apduBuffer = apdu.getBuffer();
Util.arrayCopyNonAtomic(apduBuffer, ISO7816.OFFSET_CDATA, publicKey, (short) 0, (short) publicKey.length);
short len = (short) ((short) apduBuffer[ISO7816.OFFSET_P1] & (short) 0xff);
hasher.update(apduBuffer, ISO7816.OFFSET_CDATA, len);
apdu.setOutgoing();
}

Expand Down Expand Up @@ -309,6 +281,7 @@ private void changeEndianity(byte[] array, short offset, short len) {
}
}

// CAN BE USED ONLY IF NO OFFLOADING IS USED; OTHERWISE INSECURE!
private void deterministicNonce(byte[] msg, short offset, short len) {
hasher.reset();
hasher.update(prefix, (short) 0, (short) 32);
Expand Down
10 changes: 9 additions & 1 deletion applet/src/test/java/tests/AppletTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,15 @@ public byte[] sign(CardManager cm, byte[] data, boolean offload) throws Exceptio
Assert.assertNotNull(responseAPDU.getBytes());
Assert.assertEquals(0, responseAPDU.getData().length);
}
cmd = new CommandAPDU(Consts.CLA_ED25519, Consts.INS_SIGN_FINALIZE, 0, 0, data);

cmd = new CommandAPDU(Consts.CLA_ED25519, Consts.INS_SIGN_UPDATE, 0, 0, new byte[0]);
responseAPDU = cm.transmit(cmd);
Assert.assertNotNull(responseAPDU);
Assert.assertEquals(0x9000, responseAPDU.getSW());
Assert.assertNotNull(responseAPDU.getBytes());
Assert.assertEquals(0, responseAPDU.getData().length);

cmd = new CommandAPDU(Consts.CLA_ED25519, Consts.INS_SIGN_FINALIZE, data.length, 0, data);
responseAPDU = cm.transmit(cmd);
Assert.assertNotNull(responseAPDU);
Assert.assertEquals(0x9000, responseAPDU.getSW());
Expand Down

0 comments on commit d9f52ca

Please sign in to comment.