Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b722979d37 | ||
|
|
90133f3db2 | ||
|
|
2d40584919 | ||
|
|
e2ef06329a | ||
|
|
421a6bda42 | ||
|
|
23aa2dc66f | ||
|
|
f4f7ea8227 | ||
|
|
f5b4a4f330 | ||
|
|
588cfe84e5 |
@@ -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.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user