make right shift work on both simulator and JavaCard

This commit is contained in:
Michele Balistreri 2017-10-11 13:26:50 +03:00
parent f134be461c
commit b2543239aa
2 changed files with 37 additions and 7 deletions

View File

@ -360,13 +360,13 @@ public class WalletApplet extends Applet {
for (short i = GENERATE_MNEMONIC_TMP_OFF; i < entLen; i += 2) {
short w = Util.getShort(apduBuffer, i);
Util.setShort(apduBuffer, outOff, (short)((short)(((short)(vp | ((short) (w >>> rShift)))) >>> 5) & (short) 0x7ff));
Util.setShort(apduBuffer, outOff, logicrShift((short) (vp | logicrShift(w, rShift)), (short) 5));
outOff += 2;
rShift += 5;
vp = (short) (w << (16 - rShift));
if (rShift >= 11) {
Util.setShort(apduBuffer, outOff, (short)((short) (vp >>> 5) & (short) 0x7ff));
Util.setShort(apduBuffer, outOff, logicrShift(vp, (short) 5));
outOff += 2;
rShift = (short) (rShift - 11);
vp = (short) (w << (16 - rShift));
@ -381,6 +381,20 @@ public class WalletApplet extends Applet {
apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, outLen);
}
// This works on simulator AND on JavaCard. Since we do not do a lot of these operations, the performance hit is non-existent
private short logicrShift(short v, short amount) {
if (amount == 0) return v; // short circuit on 0
short tmp = (short) (v & 0x7fff);
if (tmp == v) {
return (short) (v >>> amount);
}
tmp = (short) (tmp >>> amount);
return (short) ((short)((short) 0x4000 >>> (short) (amount - 1)) | tmp);
}
private void sign(APDU apdu) {
apdu.setIncomingAndReceive();

View File

@ -30,6 +30,7 @@ import java.security.*;
import java.util.Arrays;
import java.util.Random;
import static org.apache.commons.codec.digest.DigestUtils.sha256;
import static org.junit.jupiter.api.Assertions.*;
@DisplayName("Test the Wallet Applet")
@ -560,18 +561,33 @@ public class WalletAppletTest {
}
private void assertMnemonic(int expectedLength, byte[] data) {
short[] shorts = new short[data.length/2];
short[] shorts = new short[data.length / 2];
assertEquals(expectedLength, shorts.length);
ByteBuffer.wrap(data).order(ByteOrder.BIG_ENDIAN).asShortBuffer().get(shorts);
boolean[] bits = new boolean[11 * shorts.length];
int i = 0;
for (short mIdx : shorts) {
assertTrue(mIdx >= 0 && mIdx < 2048);
for (int j = 0; j < 11; ++j) {
bits[i++] = (mIdx & (1 << (10 - j))) > 0;
}
}
// TODO: the checksum should be validated. The problem is that the simulator should generate wrong values because of
// the bitwise operator extends the type to int, while JavaCard does not support int at all. If we make it work on
// the simulator then the code will not convert to CAP file at all. This means that the checksum can be tested only
// on a real card.
data = new byte[bits.length / 33 * 4];
for (i = 0; i < bits.length / 33 * 32; ++i) {
data[i / 8] |= (bits[i] ? 1 : 0) << (7 - (i % 8));
}
byte[] check = sha256(data);
for (i = bits.length / 33 * 32; i < bits.length; ++i) {
if ((check[(i - bits.length / 33 * 32) / 8] & (1 << (7 - (i % 8))) ^ (bits[i] ? 1 : 0) << (7 - (i % 8))) != 0) {
fail("Checksum is invalid");
}
}
}
private Sign.SignatureData signMessage(byte[] message) throws Exception {