avoid non-primitive, non-final static references

This commit is contained in:
Michele Balistreri 2018-09-26 15:22:04 +02:00
parent 174675dba8
commit 3c5fd3bfca
4 changed files with 83 additions and 74 deletions

View File

@ -24,20 +24,17 @@ public class Crypto {
final static private byte[] KEY_BITCOIN_SEED = {'B', 'i', 't', 'c', 'o', 'i', 'n', ' ', 's', 'e', 'e', 'd'}; final static private byte[] KEY_BITCOIN_SEED = {'B', 'i', 't', 'c', 'o', 'i', 'n', ' ', 's', 'e', 'e', 'd'};
// The below 4 objects can be accessed anywhere from the entire applet // The below 4 objects can be accessed anywhere from the entire applet
static RandomData random; RandomData random;
static KeyAgreement ecdh; KeyAgreement ecdh;
static MessageDigest sha256; MessageDigest sha256;
static MessageDigest sha512; MessageDigest sha512;
private static Signature hmacSHA512; private Signature hmacSHA512;
private static HMACKey hmacKey; private HMACKey hmacKey;
private static byte[] tmp; private byte[] tmp;
/** Crypto() {
* Initializes the objects required by this class. Must be invoked exactly 1 time during application installation.
*/
static void init() {
random = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM); random = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
sha256 = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false); sha256 = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
ecdh = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH_PLAIN, false); ecdh = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH_PLAIN, false);
@ -70,7 +67,7 @@ public class Crypto {
* @param chainOff the offset in the chain code buffer * @param chainOff the offset in the chain code buffer
* @return true if successful, false otherwise * @return true if successful, false otherwise
*/ */
static boolean bip32CKDPriv(byte[] i, short iOff, ECPrivateKey privateKey, ECPublicKey publicKey, byte[] chain, short chainOff) { boolean bip32CKDPriv(byte[] i, short iOff, ECPrivateKey privateKey, ECPublicKey publicKey, byte[] chain, short chainOff) {
short off = 0; short off = 0;
if ((i[iOff] & (byte) 0x80) == (byte) 0x80) { if ((i[iOff] & (byte) 0x80) == (byte) 0x80) {
@ -113,8 +110,8 @@ public class Crypto {
* @param masterKey the output buffer * @param masterKey the output buffer
* @param keyOff the offset in the output buffer * @param keyOff the offset in the output buffer
*/ */
static void bip32MasterFromSeed(byte[] seed, short seedOff, short seedSize, byte[] masterKey, short keyOff) { void bip32MasterFromSeed(byte[] seed, short seedOff, short seedSize, byte[] masterKey, short keyOff) {
Crypto.hmacSHA512(KEY_BITCOIN_SEED, (short) 0, (short) KEY_BITCOIN_SEED.length, seed, seedOff, seedSize, masterKey, keyOff); hmacSHA512(KEY_BITCOIN_SEED, (short) 0, (short) KEY_BITCOIN_SEED.length, seed, seedOff, seedSize, masterKey, keyOff);
} }
/** /**
@ -125,7 +122,7 @@ public class Crypto {
* @param off the offset * @param off the offset
* @return the number of bytes by which the signature length changed * @return the number of bytes by which the signature length changed
*/ */
static short fixS(byte[] sig, short off) { short fixS(byte[] sig, short off) {
short sOff = (short) (sig[(short) (off + 3)] + (short) (off + 5)); short sOff = (short) (sig[(short) (off + 3)] + (short) (off + 5));
short ret = 0; short ret = 0;
@ -158,7 +155,7 @@ public class Crypto {
* @param out the output buffer * @param out the output buffer
* @param outOff the offset in the output buffer * @param outOff the offset in the output buffer
*/ */
private static void hmacSHA512(byte[] key, short keyOff, short keyLen, byte[] in, short inOff, short inLen, byte[] out, short outOff) { private void hmacSHA512(byte[] key, short keyOff, short keyLen, byte[] in, short inOff, short inLen, byte[] out, short outOff) {
if (hmacSHA512 != null) { if (hmacSHA512 != null) {
hmacKey.setKey(key, keyOff, keyLen); hmacKey.setKey(key, keyOff, keyLen);
hmacSHA512.init(hmacKey, Signature.MODE_SIGN); hmacSHA512.init(hmacKey, Signature.MODE_SIGN);
@ -174,9 +171,9 @@ public class Crypto {
sha512.update(tmp, HMAC_BLOCK_OFFSET, HMAC_BLOCK_SIZE); sha512.update(tmp, HMAC_BLOCK_OFFSET, HMAC_BLOCK_SIZE);
if (i == 0) { if (i == 0) {
Crypto.sha512.doFinal(in, inOff, inLen, out, outOff); sha512.doFinal(in, inOff, inLen, out, outOff);
} else { } else {
Crypto.sha512.doFinal(out, outOff, HMAC_OUT_SIZE, out, outOff); sha512.doFinal(out, outOff, HMAC_OUT_SIZE, out, outOff);
} }
} }
} }
@ -194,7 +191,7 @@ public class Crypto {
* @param out the output buffer * @param out the output buffer
* @param outOff the offset in the output buffer * @param outOff the offset in the output buffer
*/ */
private static void addm256(byte[] a, short aOff, byte[] b, short bOff, byte[] n, short nOff, byte[] out, short outOff) { private void addm256(byte[] a, short aOff, byte[] b, short bOff, byte[] n, short nOff, byte[] out, short outOff) {
if ((add256(a, aOff, b, bOff, out, outOff) != 0) || (ucmp256(out, outOff, n, nOff) > 0)) { if ((add256(a, aOff, b, bOff, out, outOff) != 0) || (ucmp256(out, outOff, n, nOff) > 0)) {
sub256(out, outOff, n, nOff, out, outOff); sub256(out, outOff, n, nOff, out, outOff);
} }
@ -209,7 +206,7 @@ public class Crypto {
* @param bOff the offset of the b operand * @param bOff the offset of the b operand
* @return the comparison result * @return the comparison result
*/ */
private static short ucmp256(byte[] a, short aOff, byte[] b, short bOff) { private short ucmp256(byte[] a, short aOff, byte[] b, short bOff) {
short ai, bi; short ai, bi;
for (short i = 0 ; i < 32; i++) { for (short i = 0 ; i < 32; i++) {
ai = (short)(a[(short)(aOff + i)] & 0x00ff); ai = (short)(a[(short)(aOff + i)] & 0x00ff);
@ -230,7 +227,7 @@ public class Crypto {
* @param aOff the offset of the a operand * @param aOff the offset of the a operand
* @return true if a is 0, false otherwise * @return true if a is 0, false otherwise
*/ */
private static boolean isZero256(byte[] a, short aOff) { private boolean isZero256(byte[] a, short aOff) {
boolean isZero = true; boolean isZero = true;
for (short i = 0; i < (byte) 32; i++) { for (short i = 0; i < (byte) 32; i++) {
@ -254,7 +251,7 @@ public class Crypto {
* @param outOff the offset in the output buffer * @param outOff the offset in the output buffer
* @return the carry of the addition * @return the carry of the addition
*/ */
private static short add256(byte[] a, short aOff, byte[] b, short bOff, byte[] out, short outOff) { private short add256(byte[] a, short aOff, byte[] b, short bOff, byte[] out, short outOff) {
short outI = 0; short outI = 0;
for (short i = 31 ; i >= 0 ; i--) { for (short i = 31 ; i >= 0 ; i--) {
outI = (short) ((short)(a[(short)(aOff + i)] & 0xFF) + (short)(b[(short)(bOff + i)] & 0xFF) + outI); outI = (short) ((short)(a[(short)(aOff + i)] & 0xFF) + (short)(b[(short)(bOff + i)] & 0xFF) + outI);
@ -275,7 +272,7 @@ public class Crypto {
* @param outOff the offset in the output buffer * @param outOff the offset in the output buffer
* @return the carry of the subtraction * @return the carry of the subtraction
*/ */
private static short sub256(byte[] a, short aOff, byte[] b, short bOff, byte[] out, short outOff) { private short sub256(byte[] a, short aOff, byte[] b, short bOff, byte[] out, short outOff) {
short outI = 0; short outI = 0;
for (short i = 31 ; i >= 0 ; i--) { for (short i = 31 ; i >= 0 ; i--) {

View File

@ -52,12 +52,15 @@ public class SECP256k1 {
private static final byte ALG_EC_SVDP_DH_PLAIN_XY = 6; // constant from JavaCard 3.0.5 private static final byte ALG_EC_SVDP_DH_PLAIN_XY = 6; // constant from JavaCard 3.0.5
private static KeyAgreement ecPointMultiplier; private KeyAgreement ecPointMultiplier;
private Crypto crypto;
/** /**
* Allocates objects needed by this class. Must be invoked during the applet installation exactly 1 time. * Allocates objects needed by this class. Must be invoked during the applet installation exactly 1 time.
*/ */
static void init() { SECP256k1(Crypto crypto) {
this.crypto = crypto;
try { try {
ecPointMultiplier = KeyAgreement.getInstance(ALG_EC_SVDP_DH_PLAIN_XY, false); ecPointMultiplier = KeyAgreement.getInstance(ALG_EC_SVDP_DH_PLAIN_XY, false);
} catch(CryptoException e) { } catch(CryptoException e) {
@ -70,7 +73,7 @@ public class SECP256k1 {
* *
* @param key the key where the curve parameters must be set * @param key the key where the curve parameters must be set
*/ */
static void setCurveParameters(ECKey key) { void setCurveParameters(ECKey key) {
key.setA(SECP256K1_A, (short) 0x00, (short) SECP256K1_A.length); key.setA(SECP256K1_A, (short) 0x00, (short) SECP256K1_A.length);
key.setB(SECP256K1_B, (short) 0x00, (short) SECP256K1_B.length); key.setB(SECP256K1_B, (short) 0x00, (short) SECP256K1_B.length);
key.setFieldFP(SECP256K1_FP, (short) 0x00, (short) SECP256K1_FP.length); key.setFieldFP(SECP256K1_FP, (short) 0x00, (short) SECP256K1_FP.length);
@ -88,7 +91,7 @@ public class SECP256k1 {
* @param pubOff the offset in pubOut * @param pubOff the offset in pubOut
* @return the length of the public key * @return the length of the public key
*/ */
static short derivePublicKey(ECPrivateKey privateKey, byte[] pubOut, short pubOff) { short derivePublicKey(ECPrivateKey privateKey, byte[] pubOut, short pubOff) {
return multiplyPoint(privateKey, SECP256K1_G, (short) 0, (short) SECP256K1_G.length, pubOut, pubOff); return multiplyPoint(privateKey, SECP256K1_G, (short) 0, (short) SECP256K1_G.length, pubOut, pubOff);
} }
@ -102,9 +105,9 @@ public class SECP256k1 {
* @param xOff the offset in xOut * @param xOff the offset in xOut
* @return the length of X * @return the length of X
*/ */
static short derivePublicX(ECPrivateKey privateKey, byte[] xOut, short xOff) { short derivePublicX(ECPrivateKey privateKey, byte[] xOut, short xOff) {
Crypto.ecdh.init(privateKey); crypto.ecdh.init(privateKey);
return Crypto.ecdh.generateSecret(SECP256K1_G, (short) 0, (short) SECP256K1_G.length, xOut, xOff); return crypto.ecdh.generateSecret(SECP256K1_G, (short) 0, (short) SECP256K1_G.length, xOut, xOff);
} }
/** /**
@ -119,7 +122,7 @@ public class SECP256k1 {
* @param outOff the offset in the output buffer * @param outOff the offset in the output buffer
* @return the length of the data written in the out buffer * @return the length of the data written in the out buffer
*/ */
static short multiplyPoint(ECPrivateKey privateKey, byte[] point, short pointOff, short pointLen, byte[] out, short outOff) { short multiplyPoint(ECPrivateKey privateKey, byte[] point, short pointOff, short pointLen, byte[] out, short outOff) {
assertECPointMultiplicationSupport(); assertECPointMultiplicationSupport();
ecPointMultiplier.init(privateKey); ecPointMultiplier.init(privateKey);
return ecPointMultiplier.generateSecret(point, pointOff, pointLen, out, outOff); return ecPointMultiplier.generateSecret(point, pointOff, pointLen, out, outOff);
@ -130,7 +133,7 @@ public class SECP256k1 {
* *
* @return whether the card supports EC point multiplication or not * @return whether the card supports EC point multiplication or not
*/ */
static boolean hasECPointMultiplication() { boolean hasECPointMultiplication() {
return ecPointMultiplier != null; return ecPointMultiplier != null;
} }
@ -138,7 +141,7 @@ public class SECP256k1 {
* Asserts that EC point multiplication is supported. If not, the 0x6A81 status word is returned by throwing an * Asserts that EC point multiplication is supported. If not, the 0x6A81 status word is returned by throwing an
* ISOException. * ISOException.
*/ */
static void assertECPointMultiplicationSupport() { void assertECPointMultiplicationSupport() {
if(!hasECPointMultiplication()) { if(!hasECPointMultiplication()) {
ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
} }

View File

@ -44,11 +44,17 @@ public class SecureChannel {
private byte remainingSlots; private byte remainingSlots;
private boolean mutuallyAuthenticated = false; private boolean mutuallyAuthenticated = false;
private Crypto crypto;
private SECP256k1 secp256k1;
/** /**
* Instantiates a Secure Channel. All memory allocations needed for the secure channel are performed here. The keypair * Instantiates a Secure Channel. All memory allocations needed for the secure channel are performed here. The keypair
* used for the EC-DH algorithm is also generated here. * used for the EC-DH algorithm is also generated here.
*/ */
public SecureChannel(byte pairingLimit, byte[] aPairingSecret, short off) { public SecureChannel(byte pairingLimit, byte[] aPairingSecret, short off, Crypto crypto, SECP256k1 secp256k1) {
this.crypto = crypto;
this.secp256k1 = secp256k1;
scCipher = Cipher.getInstance(Cipher.ALG_AES_CBC_ISO9797_M2,false); scCipher = Cipher.getInstance(Cipher.ALG_AES_CBC_ISO9797_M2,false);
try { try {
@ -62,8 +68,8 @@ public class SecureChannel {
scMacKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_256, false); scMacKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_256, false);
scKeypair = new KeyPair(KeyPair.ALG_EC_FP, SC_KEY_LENGTH); scKeypair = new KeyPair(KeyPair.ALG_EC_FP, SC_KEY_LENGTH);
SECP256k1.setCurveParameters((ECKey) scKeypair.getPrivate()); secp256k1.setCurveParameters((ECKey) scKeypair.getPrivate());
SECP256k1.setCurveParameters((ECKey) scKeypair.getPublic()); secp256k1.setCurveParameters((ECKey) scKeypair.getPublic());
scKeypair.genKeyPair(); scKeypair.genKeyPair();
secret = JCSystem.makeTransientByteArray((short)(SC_SECRET_LENGTH * 2), JCSystem.CLEAR_ON_DESELECT); secret = JCSystem.makeTransientByteArray((short)(SC_SECRET_LENGTH * 2), JCSystem.CLEAR_ON_DESELECT);
@ -93,20 +99,20 @@ public class SecureChannel {
pairingKeyOff++; pairingKeyOff++;
} }
Crypto.ecdh.init(scKeypair.getPrivate()); crypto.ecdh.init(scKeypair.getPrivate());
short len; short len;
try { try {
len = Crypto.ecdh.generateSecret(apduBuffer, ISO7816.OFFSET_CDATA, apduBuffer[ISO7816.OFFSET_LC], secret, (short) 0); len = crypto.ecdh.generateSecret(apduBuffer, ISO7816.OFFSET_CDATA, apduBuffer[ISO7816.OFFSET_LC], secret, (short) 0);
} catch(Exception e) { } catch(Exception e) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA); ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return; return;
} }
Crypto.random.generateData(apduBuffer, (short) 0, (short) (SC_SECRET_LENGTH + SC_BLOCK_SIZE)); crypto.random.generateData(apduBuffer, (short) 0, (short) (SC_SECRET_LENGTH + SC_BLOCK_SIZE));
Crypto.sha512.update(secret, (short) 0, len); crypto.sha512.update(secret, (short) 0, len);
Crypto.sha512.update(pairingKeys, pairingKeyOff, SC_SECRET_LENGTH); crypto.sha512.update(pairingKeys, pairingKeyOff, SC_SECRET_LENGTH);
Crypto.sha512.doFinal(apduBuffer, (short) 0, SC_SECRET_LENGTH, secret, (short) 0); crypto.sha512.doFinal(apduBuffer, (short) 0, SC_SECRET_LENGTH, secret, (short) 0);
scEncKey.setKey(secret, (short) 0); scEncKey.setKey(secret, (short) 0);
scMacKey.setKey(secret, SC_SECRET_LENGTH); scMacKey.setKey(secret, SC_SECRET_LENGTH);
Util.arrayCopyNonAtomic(apduBuffer, SC_SECRET_LENGTH, secret, (short) 0, SC_BLOCK_SIZE); Util.arrayCopyNonAtomic(apduBuffer, SC_SECRET_LENGTH, secret, (short) 0, SC_BLOCK_SIZE);
@ -139,7 +145,7 @@ public class SecureChannel {
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED); ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
} }
Crypto.random.generateData(apduBuffer, SC_OUT_OFFSET, SC_SECRET_LENGTH); crypto.random.generateData(apduBuffer, SC_OUT_OFFSET, SC_SECRET_LENGTH);
respond(apdu, len, ISO7816.SW_NO_ERROR); respond(apdu, len, ISO7816.SW_NO_ERROR);
} }
@ -195,9 +201,9 @@ public class SecureChannel {
ISOException.throwIt(ISO7816.SW_FILE_FULL); ISOException.throwIt(ISO7816.SW_FILE_FULL);
} }
Crypto.sha256.update(pairingSecret, (short) 0, SC_SECRET_LENGTH); crypto.sha256.update(pairingSecret, (short) 0, SC_SECRET_LENGTH);
Crypto.sha256.doFinal(apduBuffer, ISO7816.OFFSET_CDATA, SC_SECRET_LENGTH, apduBuffer, (short) 0); crypto.sha256.doFinal(apduBuffer, ISO7816.OFFSET_CDATA, SC_SECRET_LENGTH, apduBuffer, (short) 0);
Crypto.random.generateData(secret, (short) 0, SC_SECRET_LENGTH); crypto.random.generateData(secret, (short) 0, SC_SECRET_LENGTH);
Util.arrayCopyNonAtomic(secret, (short) 0, apduBuffer, SC_SECRET_LENGTH, SC_SECRET_LENGTH); Util.arrayCopyNonAtomic(secret, (short) 0, apduBuffer, SC_SECRET_LENGTH, SC_SECRET_LENGTH);
return (SC_SECRET_LENGTH * 2); return (SC_SECRET_LENGTH * 2);
@ -212,17 +218,17 @@ public class SecureChannel {
* @return the length of the reply * @return the length of the reply
*/ */
private short pairStep2(byte[] apduBuffer) { private short pairStep2(byte[] apduBuffer) {
Crypto.sha256.update(pairingSecret, (short) 0, SC_SECRET_LENGTH); crypto.sha256.update(pairingSecret, (short) 0, SC_SECRET_LENGTH);
Crypto.sha256.doFinal(secret, (short) 0, SC_SECRET_LENGTH, secret, (short) 0); crypto.sha256.doFinal(secret, (short) 0, SC_SECRET_LENGTH, secret, (short) 0);
if (Util.arrayCompare(apduBuffer, ISO7816.OFFSET_CDATA, secret, (short) 0, SC_SECRET_LENGTH) != 0) { if (Util.arrayCompare(apduBuffer, ISO7816.OFFSET_CDATA, secret, (short) 0, SC_SECRET_LENGTH) != 0) {
preassignedPairingOffset = -1; preassignedPairingOffset = -1;
ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED); ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
} }
Crypto.random.generateData(apduBuffer, (short) 1, SC_SECRET_LENGTH); crypto.random.generateData(apduBuffer, (short) 1, SC_SECRET_LENGTH);
Crypto.sha256.update(pairingSecret, (short) 0, SC_SECRET_LENGTH); crypto.sha256.update(pairingSecret, (short) 0, SC_SECRET_LENGTH);
Crypto.sha256.doFinal(apduBuffer, (short) 1, SC_SECRET_LENGTH, pairingKeys, (short) (preassignedPairingOffset + 1)); crypto.sha256.doFinal(apduBuffer, (short) 1, SC_SECRET_LENGTH, pairingKeys, (short) (preassignedPairingOffset + 1));
pairingKeys[preassignedPairingOffset] = 1; pairingKeys[preassignedPairingOffset] = 1;
remainingSlots--; remainingSlots--;
apduBuffer[0] = (byte) (preassignedPairingOffset / PAIRING_KEY_LENGTH); apduBuffer[0] = (byte) (preassignedPairingOffset / PAIRING_KEY_LENGTH);

View File

@ -113,6 +113,9 @@ public class WalletApplet extends Applet {
private boolean signInProgress; private boolean signInProgress;
private boolean expectPublicKey; private boolean expectPublicKey;
private Crypto crypto;
private SECP256k1 secp256k1;
/** /**
* Invoked during applet installation. Creates an instance of this class. The installation parameters are passed in * Invoked during applet installation. Creates an instance of this class. The installation parameters are passed in
* the given buffer. * the given buffer.
@ -136,11 +139,11 @@ public class WalletApplet extends Applet {
* @param bLength length of the installation parameters * @param bLength length of the installation parameters
*/ */
public WalletApplet(byte[] bArray, short bOffset, byte bLength) { public WalletApplet(byte[] bArray, short bOffset, byte bLength) {
Crypto.init(); crypto = new Crypto();
SECP256k1.init(); secp256k1 = new SECP256k1(crypto);
uid = new byte[UID_LENGTH]; uid = new byte[UID_LENGTH];
Crypto.random.generateData(uid, (short) 0, UID_LENGTH); crypto.random.generateData(uid, (short) 0, UID_LENGTH);
masterPublic = (ECPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC, EC_KEY_SIZE, false); masterPublic = (ECPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC, EC_KEY_SIZE, false);
masterPrivate = (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, EC_KEY_SIZE, false); masterPrivate = (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, EC_KEY_SIZE, false);
@ -157,22 +160,22 @@ public class WalletApplet extends Applet {
keyPath = new byte[KEY_PATH_MAX_DEPTH * 4]; keyPath = new byte[KEY_PATH_MAX_DEPTH * 4];
pinlessPath = new byte[KEY_PATH_MAX_DEPTH * 4]; pinlessPath = new byte[KEY_PATH_MAX_DEPTH * 4];
SECP256k1.setCurveParameters(masterPublic); secp256k1.setCurveParameters(masterPublic);
SECP256k1.setCurveParameters(masterPrivate); secp256k1.setCurveParameters(masterPrivate);
SECP256k1.setCurveParameters(parentPublicKey); secp256k1.setCurveParameters(parentPublicKey);
SECP256k1.setCurveParameters(parentPrivateKey); secp256k1.setCurveParameters(parentPrivateKey);
parentValid = false; parentValid = false;
SECP256k1.setCurveParameters(publicKey); secp256k1.setCurveParameters(publicKey);
SECP256k1.setCurveParameters(privateKey); secp256k1.setCurveParameters(privateKey);
signature = Signature.getInstance(Signature.ALG_ECDSA_SHA_256, false); signature = Signature.getInstance(Signature.ALG_ECDSA_SHA_256, false);
short c9Off = (short)(bOffset + bArray[bOffset] + 1); // Skip AID short c9Off = (short)(bOffset + bArray[bOffset] + 1); // Skip AID
c9Off += (short)(bArray[c9Off] + 2); // Skip Privileges and parameter length c9Off += (short)(bArray[c9Off] + 2); // Skip Privileges and parameter length
secureChannel = new SecureChannel(PAIRING_MAX_CLIENT_COUNT, bArray, (short) (c9Off + PUK_LENGTH)); secureChannel = new SecureChannel(PAIRING_MAX_CLIENT_COUNT, bArray, (short) (c9Off + PUK_LENGTH), crypto, secp256k1);
puk = new OwnerPIN(PUK_MAX_RETRIES, PUK_LENGTH); puk = new OwnerPIN(PUK_MAX_RETRIES, PUK_LENGTH);
puk.update(bArray, c9Off, PUK_LENGTH); puk.update(bArray, c9Off, PUK_LENGTH);
@ -361,7 +364,7 @@ public class WalletApplet extends Applet {
apduBuffer[off++] = privateKey.isInitialized() ? (byte) 0xFF : (byte) 0x00; apduBuffer[off++] = privateKey.isInitialized() ? (byte) 0xFF : (byte) 0x00;
apduBuffer[off++] = TLV_BOOL; apduBuffer[off++] = TLV_BOOL;
apduBuffer[off++] = 1; apduBuffer[off++] = 1;
apduBuffer[off++] = SECP256k1.hasECPointMultiplication() ? (byte) 0xFF : (byte) 0x00; apduBuffer[off++] = secp256k1.hasECPointMultiplication() ? (byte) 0xFF : (byte) 0x00;
return (short) (off - SecureChannel.SC_OUT_OFFSET); return (short) (off - SecureChannel.SC_OUT_OFFSET);
} }
@ -513,7 +516,7 @@ public class WalletApplet extends Applet {
short chainOffset = (short)(privOffset + apduBuffer[(short)(privOffset + 1)] + 2); short chainOffset = (short)(privOffset + apduBuffer[(short)(privOffset + 1)] + 2);
if (apduBuffer[pubOffset] != TLV_PUB_KEY) { if (apduBuffer[pubOffset] != TLV_PUB_KEY) {
SECP256k1.assertECPointMultiplicationSupport(); secp256k1.assertECPointMultiplicationSupport();
chainOffset = privOffset; chainOffset = privOffset;
privOffset = pubOffset; privOffset = pubOffset;
pubOffset = -1; pubOffset = -1;
@ -547,7 +550,7 @@ public class WalletApplet extends Applet {
pubOffset = (short) (pubOffset + 2); pubOffset = (short) (pubOffset + 2);
} else { } else {
pubOffset = 0; pubOffset = 0;
pubLen = SECP256k1.derivePublicKey(masterPrivate, apduBuffer, pubOffset); pubLen = secp256k1.derivePublicKey(masterPrivate, apduBuffer, pubOffset);
} }
masterPublic.setW(apduBuffer, pubOffset, pubLen); masterPublic.setW(apduBuffer, pubOffset, pubLen);
@ -569,13 +572,13 @@ public class WalletApplet extends Applet {
* @param apduBuffer the APDU buffer * @param apduBuffer the APDU buffer
*/ */
private void loadSeed(byte[] apduBuffer) { private void loadSeed(byte[] apduBuffer) {
SECP256k1.assertECPointMultiplicationSupport(); secp256k1.assertECPointMultiplicationSupport();
if (apduBuffer[ISO7816.OFFSET_LC] != BIP39_SEED_SIZE) { if (apduBuffer[ISO7816.OFFSET_LC] != BIP39_SEED_SIZE) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA); ISOException.throwIt(ISO7816.SW_WRONG_DATA);
} }
Crypto.bip32MasterFromSeed(apduBuffer, (short) ISO7816.OFFSET_CDATA, BIP39_SEED_SIZE, apduBuffer, (short) ISO7816.OFFSET_CDATA); crypto.bip32MasterFromSeed(apduBuffer, (short) ISO7816.OFFSET_CDATA, BIP39_SEED_SIZE, apduBuffer, (short) ISO7816.OFFSET_CDATA);
JCSystem.beginTransaction(); JCSystem.beginTransaction();
isExtended = true; isExtended = true;
@ -585,7 +588,7 @@ public class WalletApplet extends Applet {
Util.arrayCopy(apduBuffer, (short) (ISO7816.OFFSET_CDATA + CHAIN_CODE_SIZE), masterChainCode, (short) 0, CHAIN_CODE_SIZE); Util.arrayCopy(apduBuffer, (short) (ISO7816.OFFSET_CDATA + CHAIN_CODE_SIZE), masterChainCode, (short) 0, CHAIN_CODE_SIZE);
Util.arrayCopy(apduBuffer, (short) (ISO7816.OFFSET_CDATA + CHAIN_CODE_SIZE), chainCode, (short) 0, CHAIN_CODE_SIZE); Util.arrayCopy(apduBuffer, (short) (ISO7816.OFFSET_CDATA + CHAIN_CODE_SIZE), chainCode, (short) 0, CHAIN_CODE_SIZE);
short pubLen = SECP256k1.derivePublicKey(masterPrivate, apduBuffer, (short) 0); short pubLen = secp256k1.derivePublicKey(masterPrivate, apduBuffer, (short) 0);
masterPublic.setW(apduBuffer, (short) 0, pubLen); masterPublic.setW(apduBuffer, (short) 0, pubLen);
publicKey.setW(apduBuffer, (short) 0, pubLen); publicKey.setW(apduBuffer, (short) 0, pubLen);
@ -653,7 +656,7 @@ public class WalletApplet extends Applet {
} }
if ((len != 0) && !assistedDerivation) { if ((len != 0) && !assistedDerivation) {
SECP256k1.assertECPointMultiplicationSupport(); secp256k1.assertECPointMultiplicationSupport();
} }
short chainEnd = (short) (ISO7816.OFFSET_CDATA + len); short chainEnd = (short) (ISO7816.OFFSET_CDATA + len);
@ -669,7 +672,7 @@ public class WalletApplet extends Applet {
copyKeys(privateKey, publicKey, chainCode, parentPrivateKey, parentPublicKey, parentChainCode, apduBuffer, chainEnd); copyKeys(privateKey, publicKey, chainCode, parentPrivateKey, parentPublicKey, parentChainCode, apduBuffer, chainEnd);
if (!Crypto.bip32CKDPriv(apduBuffer, i, privateKey, publicKey, chainCode, (short) 0)) { if (!crypto.bip32CKDPriv(apduBuffer, i, privateKey, publicKey, chainCode, (short) 0)) {
ISOException.throwIt(ISO7816.SW_DATA_INVALID); ISOException.throwIt(ISO7816.SW_DATA_INVALID);
} }
@ -679,7 +682,7 @@ public class WalletApplet extends Applet {
expectPublicKey = true; expectPublicKey = true;
outputPublicX(apdu, apduBuffer); outputPublicX(apdu, apduBuffer);
} else { } else {
short pubLen = SECP256k1.derivePublicKey(privateKey, apduBuffer, chainEnd); short pubLen = secp256k1.derivePublicKey(privateKey, apduBuffer, chainEnd);
publicKey.setW(apduBuffer, chainEnd, pubLen); publicKey.setW(apduBuffer, chainEnd, pubLen);
keyPathLen += 4; keyPathLen += 4;
parentValid = true; parentValid = true;
@ -697,7 +700,7 @@ public class WalletApplet extends Applet {
* @param apduBuffer the APDU buffer. * @param apduBuffer the APDU buffer.
*/ */
private void outputPublicX(APDU apdu, byte[] apduBuffer) { private void outputPublicX(APDU apdu, byte[] apduBuffer) {
short xLen = SECP256k1.derivePublicX(privateKey, apduBuffer, (short) (SecureChannel.SC_OUT_OFFSET + 4)); short xLen = secp256k1.derivePublicX(privateKey, apduBuffer, (short) (SecureChannel.SC_OUT_OFFSET + 4));
signature.init(privateKey, Signature.MODE_SIGN); signature.init(privateKey, Signature.MODE_SIGN);
short sigLen = signature.signPreComputedHash(ASSISTED_DERIVATION_HASH, (short) 0, (short) ASSISTED_DERIVATION_HASH.length, apduBuffer, (short) (SecureChannel.SC_OUT_OFFSET + xLen + 4)); short sigLen = signature.signPreComputedHash(ASSISTED_DERIVATION_HASH, (short) 0, (short) ASSISTED_DERIVATION_HASH.length, apduBuffer, (short) (SecureChannel.SC_OUT_OFFSET + xLen + 4));
@ -774,8 +777,8 @@ public class WalletApplet extends Applet {
} }
short entLen = (short) (csLen * 4); short entLen = (short) (csLen * 4);
Crypto.random.generateData(apduBuffer, GENERATE_MNEMONIC_TMP_OFF, entLen); crypto.random.generateData(apduBuffer, GENERATE_MNEMONIC_TMP_OFF, entLen);
Crypto.sha256.doFinal(apduBuffer, GENERATE_MNEMONIC_TMP_OFF, entLen, apduBuffer, (short)(GENERATE_MNEMONIC_TMP_OFF + entLen)); crypto.sha256.doFinal(apduBuffer, GENERATE_MNEMONIC_TMP_OFF, entLen, apduBuffer, (short)(GENERATE_MNEMONIC_TMP_OFF + entLen));
entLen += GENERATE_MNEMONIC_TMP_OFF + 1; entLen += GENERATE_MNEMONIC_TMP_OFF + 1;
short outOff = SecureChannel.SC_OUT_OFFSET; short outOff = SecureChannel.SC_OUT_OFFSET;
@ -875,7 +878,7 @@ public class WalletApplet extends Applet {
ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2); ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
} }
outLen += Crypto.fixS(apduBuffer, sigOff); outLen += crypto.fixS(apduBuffer, sigOff);
apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 1)] = (byte) 0x81; apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 1)] = (byte) 0x81;
apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 2)] = (byte) (outLen - 3); apduBuffer[(short)(SecureChannel.SC_OUT_OFFSET + 2)] = (byte) (outLen - 3);