Compare commits

..
Author SHA1 Message Date
Michele Balistreri b722979d37 fix typo 2022-06-15 12:13:51 +02:00
Michele Balistreri 90133f3db2 correct import 2022-06-08 09:49:28 +02:00
Michele Balistreri 2d40584919 add g2 point compression 2022-06-01 10:10:58 +02:00
Michele Balistreri e2ef06329a fix bls 2022-05-30 09:53:34 +02:00
Michele Balistreri 421a6bda42 fixes 2022-05-26 14:41:05 +02:00
Michele Balistreri 23aa2dc66f implement toByteArray 2022-05-25 15:57:17 +02:00
Michele Balistreri f4f7ea8227 fix another typo 2022-05-25 15:20:03 +02:00
Michele Balistreri f5b4a4f330 fix typos 2022-05-25 14:54:21 +02:00
Michele Balistreri 588cfe84e5 add bls hashing 2022-05-25 11:30:47 +02:00
4 changed files with 30 additions and 169 deletions
@@ -1,106 +0,0 @@
package im.status.keycard.applet;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.util.SortedSet;
import java.util.TreeSet;
public class Metadata {
private String cardName;
private SortedSet<Long> wallets;
public static Metadata fromData(byte[] data) {
int version = (data[0] & 0xe0) >> 5;
if (version != 1) {
throw new RuntimeException("Invalid version");
}
int namelen = (data[0] & 0x1f);
int off = 1;
String cardName = new String(data, off, namelen, Charset.forName("US-ASCII"));
off += namelen;
SortedSet<Long> set = new TreeSet<>();
while(off < data.length) {
int[] start = TinyBERTLV.readNum(data, off);
int[] count = TinyBERTLV.readNum(data, start[1]);
off = count[1];
long s = start[0] & 0xffffffffl;
buildRange(set, s, (s + count[0]));
}
return new Metadata(cardName, set);
}
private static void buildRange(SortedSet<Long> set, long start, long end) {
for (long i = start; i <= end; i++) {
set.add(i);
}
}
Metadata(String cardName, SortedSet<Long> wallets) {
this.cardName = cardName;
this.wallets = wallets;
}
public Metadata(String cardName) {
this(cardName, new TreeSet<>());
}
public String getCardName() {
return cardName;
}
public void setCardName(String cardName) {
if (cardName.length() > 20) {
throw new IllegalArgumentException("card name too long");
}
this.cardName = cardName;
}
public SortedSet<Long> getWallets() {
return wallets;
}
public void addWallet(long w) {
this.wallets.add(w);
}
public void removeWallet(long w) {
this.wallets.remove(w);
}
public byte[] toByteArray() {
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] name = this.cardName.getBytes(Charset.forName("US-ASCII"));
os.write(0x20 | name.length);
os.write(name, 0, name.length);
if (wallets.isEmpty()) {
return os.toByteArray();
}
long start = wallets.first();
int len = 0;
for (Long w : wallets.tailSet(start + 1)) {
if (w == (start + len + 1)) {
len++;
} else {
TinyBERTLV.writeNum(os, (int) start);
TinyBERTLV.writeNum(os, len);
len = 0;
start = w;
}
}
TinyBERTLV.writeNum(os, (int) start);
TinyBERTLV.writeNum(os, len);
return os.toByteArray();
}
}
@@ -117,9 +117,16 @@ public class Mnemonic {
}
public static byte[] toBinarySeed(String mnemonicPhrase, String password) {
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512", "BC");
PBEKeySpec spec = new PBEKeySpec(mnemonicPhrase.toCharArray(), ("mnemonic" + password).getBytes(), 2048, 512);
SecretKey key = skf.generateSecret(spec);
SecretKey key;
try {
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512", "BC");
PBEKeySpec spec = new PBEKeySpec(mnemonicPhrase.toCharArray(), ("mnemonic" + password).getBytes(), 2048, 512);
key = skf.generateSecret(spec);
} catch (Exception e) {
throw new RuntimeException("Is Bouncycastle correctly initialized?");
}
return key.getEncoded();
}
@@ -1,6 +1,5 @@
package im.status.keycard.applet;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
/**
@@ -15,57 +14,6 @@ public class TinyBERTLV {
private byte[] buffer;
private int pos;
public static int[] readNum(byte[] buf, int off) {
int len = buf[off++] & 0xff;
int lenlen = 0;
if ((len & 0x80) == 0x80) {
lenlen = len & 0x7f;
len = readVal(buf, off, lenlen);
}
return new int[] {len, off + lenlen};
}
public static int readVal(byte[] val, int off, int len) {
switch (len) {
case 1:
return val[off] & 0xff;
case 2:
return ((val[off] & 0xff) << 8) | (val[off+1] & 0xff);
case 3:
return ((val[off] & 0xff) << 16) | ((val[off+1] & 0xff) << 8) | (val[off+2] & 0xff);
case 4:
return ((val[off] & 0xff) << 24) | ((val[off+1] & 0xff) << 16) | ((val[off+2] & 0xff) << 8) | (val[off+3] & 0xff);
default:
throw new IllegalArgumentException("Integers of length " + len + " are unsupported");
}
}
public static void writeNum(ByteArrayOutputStream os, int len) {
if ((len & 0xff000000) != 0) {
os.write(0x84);
os.write((len & 0xff000000) >> 24);
os.write((len & 0x00ff0000) >> 16);
os.write((len & 0x0000ff00) >> 8);
os.write(len & 0x000000ff);
} else if ((len & 0x00ff0000) != 0) {
os.write(0x83);
os.write((len & 0x00ff0000) >> 16);
os.write((len & 0x0000ff00) >> 8);
os.write(len & 0x000000ff);
} else if ((len & 0x0000ff00) != 0) {
os.write(0x82);
os.write((len & 0x0000ff00) >> 8);
os.write(len & 0x000000ff);
} else if ((len & 0x00000080) != 0) {
os.write(0x81);
os.write(len & 0x000000ff);
} else {
os.write(len);
}
}
public TinyBERTLV(byte[] buffer) {
this.buffer = buffer;
this.pos = 0;
@@ -116,7 +64,19 @@ public class TinyBERTLV {
*/
public int readInt() throws IllegalArgumentException {
byte[] val = readPrimitive(TLV_INT);
return TinyBERTLV.readVal(val, 0, val.length);
switch (val.length) {
case 1:
return val[0] & 0xff;
case 2:
return ((val[0] & 0xff) << 8) | (val[1] & 0xff);
case 3:
return ((val[0] & 0xff) << 16) | ((val[1] & 0xff) << 8) | (val[2] & 0xff);
case 4:
return ((val[0] & 0xff) << 24) | ((val[1] & 0xff) << 16) | ((val[2] & 0xff) << 8) | (val[3] & 0xff);
default:
throw new IllegalArgumentException("Integers of length " + val.length + " are unsupported");
}
}
/**
@@ -144,9 +104,13 @@ public class TinyBERTLV {
* @return the tag
*/
public int readLength() {
int[] len = TinyBERTLV.readNum(buffer, pos);
pos = len[1];
return len[0];
int len = buffer[pos++] & 0xff;
if (len == 0x81) {
len = buffer[pos++] & 0xff;
}
return len;
}
private void checkTag(int expected, int actual) throws IllegalArgumentException {
@@ -31,10 +31,6 @@ public class Crypto {
}
}
static {
Crypto.addBouncyCastleProvider();
}
/**
* Derives a session key for SCP02.
*