mirror of
https://github.com/status-im/status-keycard.git
synced 2025-01-13 07:14:11 +00:00
implement low-level BIP32 CKDPriv function
This commit is contained in:
parent
4c0c58ac90
commit
de91e33f74
@ -1,15 +1,159 @@
|
||||
package im.status.wallet;
|
||||
|
||||
import javacard.security.MessageDigest;
|
||||
import javacard.security.RandomData;
|
||||
import javacard.framework.JCSystem;
|
||||
import javacard.framework.Util;
|
||||
import javacard.security.*;
|
||||
|
||||
public class Crypto {
|
||||
final static private short KEY_SECRET_SIZE = 32;
|
||||
final static private short KEY_DERIVATION_INPUT_SIZE = 37;
|
||||
final static private short HMAC_OUT_SIZE = 64;
|
||||
|
||||
private static final byte HMAC_IPAD = (byte) 0x36;
|
||||
private static final byte HMAC_OPAD = (byte) 0x5c;
|
||||
private static final short HMAC_BLOCK_SIZE = (short) 128;
|
||||
private static final short HMAC_BLOCK_OFFSET = (short) KEY_DERIVATION_INPUT_SIZE + HMAC_OUT_SIZE;
|
||||
|
||||
static RandomData random;
|
||||
static MessageDigest sha256;
|
||||
|
||||
private static MessageDigest sha512;
|
||||
private static Signature hmacSHA512;
|
||||
private static HMACKey hmacKey;
|
||||
|
||||
private static byte[] tmp;
|
||||
|
||||
static void init() {
|
||||
random = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
|
||||
sha256 = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
|
||||
|
||||
short blockSize;
|
||||
|
||||
try {
|
||||
blockSize = 0;
|
||||
hmacSHA512 = Signature.getInstance(Signature.ALG_HMAC_SHA_512, false);
|
||||
hmacKey = (HMACKey) KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC_TRANSIENT_DESELECT, KEY_SECRET_SIZE, false);
|
||||
} catch (CryptoException e) {
|
||||
sha512 = MessageDigest.getInstance(MessageDigest.ALG_SHA_512, false);
|
||||
blockSize = HMAC_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
tmp = JCSystem.makeTransientByteArray((short) (HMAC_BLOCK_OFFSET + blockSize), JCSystem.CLEAR_ON_RESET);
|
||||
}
|
||||
|
||||
static boolean bip32CKDPriv(byte[] i, short iOff, ECPrivateKey privateKey, ECPublicKey publicKey, byte[] chain, short chainOff) {
|
||||
short off = 0;
|
||||
|
||||
if ((i[iOff] & (byte) 0x80) == (byte) 0x80) {
|
||||
tmp[off++] = 0;
|
||||
off += privateKey.getS(tmp, off);
|
||||
} else {
|
||||
off = (short) (publicKey.getW(tmp, (short) 0) - 1);
|
||||
tmp[0] = ((tmp[(short) off] & 1) != 0 ? (byte) 0x03 : (byte) 0x02);
|
||||
off = (short) ((short) (off / 2) + 1);
|
||||
}
|
||||
|
||||
off = Util.arrayCopyNonAtomic(i, iOff, tmp, off, (short) 4);
|
||||
|
||||
hmacSHA512(chain, chainOff, KEY_SECRET_SIZE, tmp, (short) 0, off, tmp, off);
|
||||
|
||||
if (ucmp256(tmp, off, SECP256k1.SECP256K1_R, (short) 0) >= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
privateKey.getS(tmp, (short) 0);
|
||||
|
||||
addm256(tmp, off, tmp, (short) 0, SECP256k1.SECP256K1_R, (short)0, tmp, off);
|
||||
|
||||
if (isZero256(tmp, off)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JCSystem.beginTransaction();
|
||||
privateKey.setS(tmp, off, (short) KEY_SECRET_SIZE);
|
||||
Util.arrayCopy(tmp, (short)(off + KEY_SECRET_SIZE), chain, chainOff, (short) KEY_SECRET_SIZE);
|
||||
JCSystem.commitTransaction();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void hmacSHA512(byte[] key, short keyOff, short keyLen, byte[] in, short inOff, short inLen, byte[] out, short outOff) {
|
||||
if (hmacSHA512 != null) {
|
||||
hmacKey.setKey(key, keyOff, keyLen);
|
||||
hmacSHA512.init(hmacKey, Signature.MODE_SIGN);
|
||||
hmacSHA512.sign(in, inOff, inLen, out, outOff);
|
||||
} else {
|
||||
for (byte i = 0; i < 2; i++) {
|
||||
Util.arrayFillNonAtomic(tmp, HMAC_BLOCK_OFFSET, HMAC_BLOCK_SIZE, (i == 0 ? HMAC_IPAD : HMAC_OPAD));
|
||||
|
||||
for (short j = 0; j < keyLen; j++) {
|
||||
tmp[(short)(HMAC_BLOCK_OFFSET + j)] ^= key[(short)(keyOff + j)];
|
||||
}
|
||||
|
||||
sha512.update(tmp, HMAC_BLOCK_OFFSET, HMAC_BLOCK_SIZE);
|
||||
|
||||
if (i == 0) {
|
||||
Crypto.sha512.doFinal(in, inOff, inLen, out, outOff);
|
||||
} else {
|
||||
Crypto.sha512.doFinal(out, outOff, HMAC_OUT_SIZE, out, outOff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static 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)) {
|
||||
sub256(out, outOff, n, nOff, out, outOff);
|
||||
}
|
||||
}
|
||||
|
||||
private static short ucmp256(byte[] a, short aOff, byte[] b, short bOff) {
|
||||
short ai, bi;
|
||||
for (short i = 0 ; i < 32; i++) {
|
||||
ai = (short)(a[(short)(aOff + i)] & 0x00ff);
|
||||
bi = (short)(b[(short)(bOff + i)] & 0x00ff);
|
||||
|
||||
if (ai != bi) {
|
||||
return (short)(ai - bi);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static boolean isZero256(byte[] a, short aOff) {
|
||||
boolean isZero = true;
|
||||
|
||||
for (short i = 0; i < (byte) 32; i++) {
|
||||
if (a[(short)(aOff + i)] != 0) {
|
||||
isZero = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return isZero;
|
||||
}
|
||||
|
||||
private static short add256(byte[] a, short aOff, byte[] b, short bOff, byte[] out, short outOff) {
|
||||
|
||||
short outI = 0;
|
||||
for (short i = 31 ; i >= 0 ; i--) {
|
||||
outI = (short) ((short)(a[(short)(aOff + i)] & 0x00FF) + (short)(b[(short)(bOff + i)] & 0xFF) + outI);
|
||||
out[(short)(outOff + i)] = (byte)outI ;
|
||||
outI = (short)(outI >> 8);
|
||||
}
|
||||
return outI;
|
||||
}
|
||||
|
||||
private static short sub256(byte[] a, short aOff, byte[] b, short bOff, byte[] out, short outOff) {
|
||||
short outI = 0;
|
||||
|
||||
for (short i = 31 ; i >= 0 ; i--) {
|
||||
outI = (short) ((short)(a[(short)(aOff + i)] & 0xFF) - (short)(b[(short)(bOff + i)] & 0xFF) - outI);
|
||||
out[(short)(outOff + i)] = (byte)outI ;
|
||||
outI = (short)(((outI >> 8) != 0) ? 1 : 0);
|
||||
}
|
||||
|
||||
return outI;
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import javacard.security.ECKey;
|
||||
import javacard.security.ECPrivateKey;
|
||||
import javacard.security.KeyAgreement;
|
||||
|
||||
public class SEC256k1 {
|
||||
public class SECP256k1 {
|
||||
static final byte SECP256K1_FP[] = {
|
||||
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
|
||||
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
|
@ -26,8 +26,8 @@ public class SecureChannel {
|
||||
scKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_256, false);
|
||||
|
||||
scKeypair = new KeyPair(KeyPair.ALG_EC_FP, SC_KEY_LENGTH);
|
||||
SEC256k1.setCurveParameters((ECKey) scKeypair.getPrivate());
|
||||
SEC256k1.setCurveParameters((ECKey) scKeypair.getPublic());
|
||||
SECP256k1.setCurveParameters((ECKey) scKeypair.getPrivate());
|
||||
SECP256k1.setCurveParameters((ECKey) scKeypair.getPublic());
|
||||
scKeypair.genKeyPair();
|
||||
|
||||
scAgreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH, false);
|
||||
|
@ -70,7 +70,7 @@ public class WalletApplet extends Applet {
|
||||
}
|
||||
|
||||
public WalletApplet(byte[] bArray, short bOffset, byte bLength) {
|
||||
SEC256k1.init();
|
||||
SECP256k1.init();
|
||||
Crypto.init();
|
||||
|
||||
short c9Off = (short)(bOffset + bArray[bOffset] + 1); // Skip AID
|
||||
@ -94,11 +94,11 @@ public class WalletApplet extends Applet {
|
||||
publicKey = (ECPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC, EC_KEY_SIZE, false);
|
||||
privateKey = (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, EC_KEY_SIZE, false);
|
||||
|
||||
SEC256k1.setCurveParameters(masterPublic);
|
||||
SEC256k1.setCurveParameters(masterPrivate);
|
||||
SECP256k1.setCurveParameters(masterPublic);
|
||||
SECP256k1.setCurveParameters(masterPrivate);
|
||||
|
||||
SEC256k1.setCurveParameters(publicKey);
|
||||
SEC256k1.setCurveParameters(privateKey);
|
||||
SECP256k1.setCurveParameters(publicKey);
|
||||
SECP256k1.setCurveParameters(privateKey);
|
||||
|
||||
signature = Signature.getInstance(Signature.ALG_ECDSA_SHA_256, false);
|
||||
|
||||
@ -178,7 +178,7 @@ public class WalletApplet extends Applet {
|
||||
apduBuffer[off++] = privateKey.isInitialized() ? (byte) 0x01 : (byte) 0x00;
|
||||
apduBuffer[off++] = TLV_FAST_PUBLIC_KEY_DERIVATION;
|
||||
apduBuffer[off++] = 1;
|
||||
apduBuffer[off++] = SEC256k1.hasFastECPointMultiplication() ? (byte) 0x01 : (byte) 0x00;
|
||||
apduBuffer[off++] = SECP256k1.hasFastECPointMultiplication() ? (byte) 0x01 : (byte) 0x00;
|
||||
|
||||
short len = secureChannel.encryptAPDU(apduBuffer, (short) (off - SecureChannel.SC_OUT_OFFSET));
|
||||
apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, len);
|
||||
@ -309,7 +309,7 @@ public class WalletApplet extends Applet {
|
||||
pubOffset = (short) (pubOffset + 2);
|
||||
} else {
|
||||
pubOffset = 0;
|
||||
pubLen = SEC256k1.derivePublicKey(masterPrivate, apduBuffer, pubOffset);
|
||||
pubLen = SECP256k1.derivePublicKey(masterPrivate, apduBuffer, pubOffset);
|
||||
}
|
||||
|
||||
masterPublic.setW(apduBuffer, pubOffset, pubLen);
|
||||
@ -334,7 +334,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), chainCode, (short) 0, CHAIN_CODE_SIZE);
|
||||
short pubLen = SEC256k1.derivePublicKey(masterPrivate, apduBuffer, (short) 0);
|
||||
short pubLen = SECP256k1.derivePublicKey(masterPrivate, apduBuffer, (short) 0);
|
||||
|
||||
masterPublic.setW(apduBuffer, (short) 0, pubLen);
|
||||
publicKey.setW(apduBuffer, (short) 0, pubLen);
|
||||
|
Loading…
x
Reference in New Issue
Block a user