document Crypto utility class
This commit is contained in:
parent
a216b29b97
commit
10a429bf6d
|
@ -166,7 +166,8 @@ signing sessions, if any. Unless a DERIVE KEY is sent, a subsequent SIGN command
|
|||
* Data = a sequence of 32-bit integers (most significant byte first). Empty if the master key must be used. On assisted
|
||||
derivation contains a public key when P2 = 0x02.
|
||||
* Response SW = 0x9000 on success, 0x6A80 if the format is invalid, 0x6A81 if public key derivation is not supported and
|
||||
bit 0 of P1 is set, 0x6A86 if P2 = 0x01 and bit 0 of P1 is not set.
|
||||
bit 0 of P1 is set, 0x6A86 if P2 = 0x01 and bit 0 of P1 is not set, 0x6984 if one of the components in the path
|
||||
generates an invalid key.
|
||||
* Response Data = On assisted derivation and P2 = 0x01 the key derivation template. Empty otherwise.
|
||||
* Preconditions: Secure Channel must be opened, user PIN must be verified (if no PIN-less key is defined), an extended keyset must be loaded
|
||||
|
||||
|
@ -176,7 +177,9 @@ SIGN sessions. Because JavaCard does not offer native EC point multiplication be
|
|||
alternative mode of operation where the public key is partially derived off-card and loaded back on card. In this mode
|
||||
of operation only 1 derivation step at the time can be completed and as such during assisted derivation the data can
|
||||
contain a single 32-bit integer, instead of a sequence. The maximum depth of derivation from the master key is 10. Any
|
||||
attempt to get deeper results in 0x6A80 being returned.
|
||||
attempt to get deeper results in 0x6A80 being returned. The BIP32 specifications define a few checks which must be
|
||||
performed on the derived keys. If these fail, the 0x6984 is returned and the invalid key is discarded. A client should
|
||||
perform a GET STATUS command to get the actual current key path and resume derivation using a different path.
|
||||
|
||||
P1:
|
||||
* bit 0 = if 0 derive autonomously (only works if public key derivation is supported), if 1 do assisted derivation
|
||||
|
|
|
@ -4,6 +4,10 @@ import javacard.framework.JCSystem;
|
|||
import javacard.framework.Util;
|
||||
import javacard.security.*;
|
||||
|
||||
/**
|
||||
* Crypto utilities, mostly BIP32 related. The init method must be called during application installation. This class
|
||||
* is not meant to be instantiated.
|
||||
*/
|
||||
public class Crypto {
|
||||
final static private short KEY_SECRET_SIZE = 32;
|
||||
final static private short KEY_DERIVATION_INPUT_SIZE = 37;
|
||||
|
@ -14,6 +18,7 @@ public class Crypto {
|
|||
private static final short HMAC_BLOCK_SIZE = (short) 128;
|
||||
private static final short HMAC_BLOCK_OFFSET = (short) KEY_DERIVATION_INPUT_SIZE + HMAC_OUT_SIZE;
|
||||
|
||||
// The below two objects are meant to be access from the entire applet
|
||||
static RandomData random;
|
||||
static MessageDigest sha256;
|
||||
|
||||
|
@ -23,6 +28,9 @@ public class Crypto {
|
|||
|
||||
private static byte[] tmp;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
sha256 = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
|
||||
|
@ -42,6 +50,19 @@ public class Crypto {
|
|||
tmp = JCSystem.makeTransientByteArray((short) (HMAC_BLOCK_OFFSET + blockSize), JCSystem.CLEAR_ON_RESET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Derives a private key according to the algorithm defined in BIP32. The BIP32 specifications define some checks
|
||||
* to be performed on the derived keys. In the very unlikely event that these checks fail this key is not considered
|
||||
* to be valid so the derived key is discarded and this method returns false.
|
||||
*
|
||||
* @param i the buffer containing the key path element (a 32-bit big endian integer)
|
||||
* @param iOff the offset in the buffer
|
||||
* @param privateKey the parent private key
|
||||
* @param publicKey the parent public key
|
||||
* @param chain the chain code
|
||||
* @param chainOff the offset in the chain code buffer
|
||||
* @return true if successful, false otherwise
|
||||
*/
|
||||
static boolean bip32CKDPriv(byte[] i, short iOff, ECPrivateKey privateKey, ECPublicKey publicKey, byte[] chain, short chainOff) {
|
||||
short off = 0;
|
||||
|
||||
|
@ -76,6 +97,19 @@ public class Crypto {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the HMAC-SHA512 with the given key and data. Uses a software implementation which only requires SHA-512
|
||||
* to be supported on cards which do not have native HMAC-SHA512.
|
||||
*
|
||||
* @param key the HMAC key
|
||||
* @param keyOff the offset of the key
|
||||
* @param keyLen the length of the key
|
||||
* @param in the input data
|
||||
* @param inOff the offset of the input data
|
||||
* @param inLen the length of the input data
|
||||
* @param out 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) {
|
||||
if (hmacSHA512 != null) {
|
||||
hmacKey.setKey(key, keyOff, keyLen);
|
||||
|
@ -100,12 +134,33 @@ public class Crypto {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modulo addition of two 256-bit numbers.
|
||||
*
|
||||
* @param a the a operand
|
||||
* @param aOff the offset of the a operand
|
||||
* @param b the b operand
|
||||
* @param bOff the offset of the b operand
|
||||
* @param n the modulo
|
||||
* @param nOff the offset of the modulo
|
||||
* @param out 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) {
|
||||
if ((add256(a, aOff, b, bOff, out, outOff) != 0) || (ucmp256(out, outOff, n, nOff) > 0)) {
|
||||
sub256(out, outOff, n, nOff, out, outOff);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two 256-bit numbers. Returns 1 if a > b, -1 if a < b and 0 if a = b.
|
||||
*
|
||||
* @param a the a operand
|
||||
* @param aOff the offset of the a operand
|
||||
* @param b the b operand
|
||||
* @param bOff the offset of the b operand
|
||||
* @return the comparison result
|
||||
*/
|
||||
private static short ucmp256(byte[] a, short aOff, byte[] b, short bOff) {
|
||||
short ai, bi;
|
||||
for (short i = 0 ; i < 32; i++) {
|
||||
|
@ -120,6 +175,13 @@ public class Crypto {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given 256-bit number is 0.
|
||||
*
|
||||
* @param a the a operand
|
||||
* @param aOff the offset of the a operand
|
||||
* @return true if a is 0, false otherwise
|
||||
*/
|
||||
private static boolean isZero256(byte[] a, short aOff) {
|
||||
boolean isZero = true;
|
||||
|
||||
|
@ -133,6 +195,17 @@ public class Crypto {
|
|||
return isZero;
|
||||
}
|
||||
|
||||
/**
|
||||
* Addition of two 256-bit numbers.
|
||||
*
|
||||
* @param a the a operand
|
||||
* @param aOff the offset of the a operand
|
||||
* @param b the b operand
|
||||
* @param bOff the offset of the b operand
|
||||
* @param out the output buffer
|
||||
* @param outOff the offset in the output buffer
|
||||
* @return the carry of the addition
|
||||
*/
|
||||
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--) {
|
||||
|
@ -143,6 +216,17 @@ public class Crypto {
|
|||
return outI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtraction of two 256-bit numbers.
|
||||
*
|
||||
* @param a the a operand
|
||||
* @param aOff the offset of the a operand
|
||||
* @param b the b operand
|
||||
* @param bOff the offset of the b operand
|
||||
* @param out the output buffer
|
||||
* @param outOff the offset in the output buffer
|
||||
* @return the carry of the subtraction
|
||||
*/
|
||||
private static short sub256(byte[] a, short aOff, byte[] b, short bOff, byte[] out, short outOff) {
|
||||
short outI = 0;
|
||||
|
||||
|
|
|
@ -580,7 +580,11 @@ public class WalletApplet extends Applet {
|
|||
|
||||
for (short i = ISO7816.OFFSET_CDATA; i < chainEnd; i += 4) {
|
||||
JCSystem.beginTransaction();
|
||||
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);
|
||||
}
|
||||
|
||||
Util.arrayCopy(apduBuffer, i, keyPath, keyPathLen, (short) 4);
|
||||
|
||||
if (assistedDerivation) {
|
||||
|
|
Loading…
Reference in New Issue