diff --git a/src/org/satochip/applet/CardEdge.java b/src/org/satochip/applet/CardEdge.java
index e1fbf8e..037dedb 100644
--- a/src/org/satochip/applet/CardEdge.java
+++ b/src/org/satochip/applet/CardEdge.java
@@ -58,20 +58,19 @@
import javacard.security.AESKey;
import javacard.security.ECPrivateKey;
import javacard.security.ECPublicKey;
-//import javacard.security.HMACKey;
+import javacard.security.CryptoException;
import javacard.security.Key;
import javacard.security.KeyAgreement;
import javacard.security.KeyBuilder;
import javacard.security.Signature;
import javacard.security.MessageDigest;
import javacard.security.RandomData;
-import javacardx.apdu.ExtendedLength; //debugXL //TODO: remove
import javacardx.crypto.Cipher;
/**
* Implements MUSCLE's Card Edge Specification.
*/
-public class CardEdge extends javacard.framework.Applet implements ExtendedLength {
+public class CardEdge extends javacard.framework.Applet {
/* constants declaration */
@@ -95,8 +94,12 @@ public class CardEdge extends javacard.framework.Applet implements ExtendedLengt
// 0.8-0.1: add APDUs to reset the seed/eckey/2FA. 2FA required to sign tx/msg and reset seed/eckey/2FA. 2FA can only be disabled when all privkeys are cleared.
// 0.9-0.1: Message signing for altcoin.
// 0.10-0.1: add method SignTransactionHash()
+ // 0.10-0.2: support for native sha512
+ // 0.10-0.3: ECkey recovery optimisation: support ALG_EC_SVDP_DH_PLAIN_XY
+ // 0.10-0.4: Cleanup: optimised code only, removed legacy sha512 implementation and slow pubkey recovery
+ // 0.11-0.1: support (mandatory) secure channel
private final static byte PROTOCOL_MAJOR_VERSION = (byte) 0;
- private final static byte PROTOCOL_MINOR_VERSION = (byte) 10;
+ private final static byte PROTOCOL_MINOR_VERSION = (byte) 11;
private final static byte APPLET_MAJOR_VERSION = (byte) 0;
private final static byte APPLET_MINOR_VERSION = (byte) 1;
@@ -156,20 +159,20 @@ public class CardEdge extends javacard.framework.Applet implements ExtendedLengt
private final static byte INS_CRYPT_TRANSACTION_2FA = (byte) 0x76;
private final static byte INS_SET_2FA_KEY = (byte) 0x79;
private final static byte INS_RESET_2FA_KEY = (byte) 0x78;
+ private final static byte INS_SIGN_TRANSACTION_HASH= (byte) 0x7A;
- private final static byte INS_SIGN_TRANSACTION_HASH= (byte) 0x7A;
-
- // debug
- private final static byte INS_TEST_SHA1 = (byte) 0x80;
- private final static byte INS_COMPUTE_SHA512 = (byte) 0x6A;
- private final static byte INS_COMPUTE_HMAC= (byte) 0x6B;
- private final static byte INS_BIP32_SET_EXTENDED_KEY= (byte) 0x70;
+ // secure channel
+ private final static byte INS_INIT_SECURE_CHANNEL = (byte) 0x81;
+ private final static byte INS_PROCESS_SECURE_CHANNEL = (byte) 0x82;
+
+ /****************************************
+ * Error codes *
+ ****************************************/
-
- /** There have been memory problems on the card */
- private final static short SW_NO_MEMORY_LEFT = Bip32ObjectManager.SW_NO_MEMORY_LEFT;
/** Entered PIN is not correct */
- private final static short SW_AUTH_FAILED = (short) 0x9C02;
+ private final static short SW_PIN_FAILED = (short)0x63C0;// includes number of tries remaining
+ ///** DEPRECATED - Entered PIN is not correct */
+ //private final static short SW_AUTH_FAILED = (short) 0x9C02;
/** Required operation is not allowed in actual circumstances */
private final static short SW_OPERATION_NOT_ALLOWED = (short) 0x9C03;
/** Required setup is not not done */
@@ -177,13 +180,16 @@ public class CardEdge extends javacard.framework.Applet implements ExtendedLengt
/** Required setup is already done */
private final static short SW_SETUP_ALREADY_DONE = (short) 0x9C07;
/** Required feature is not (yet) supported */
- private final static short SW_UNSUPPORTED_FEATURE = (short) 0x9C05;
+ final static short SW_UNSUPPORTED_FEATURE = (short) 0x9C05;
/** Required operation was not authorized because of a lack of privileges */
private final static short SW_UNAUTHORIZED = (short) 0x9C06;
/** Algorithm specified is not correct */
private final static short SW_INCORRECT_ALG = (short) 0x9C09;
- /** Required object is missing */
- private final static short SW_OBJECT_NOT_FOUND= (short) 0x9C07;
+
+ /** There have been memory problems on the card */
+ private final static short SW_NO_MEMORY_LEFT = Bip32ObjectManager.SW_NO_MEMORY_LEFT;
+ ///** DEPRECATED - Required object is missing */
+ //private final static short SW_OBJECT_NOT_FOUND= (short) 0x9C07;
/** Incorrect P1 parameter */
private final static short SW_INCORRECT_P1 = (short) 0x9C10;
@@ -209,8 +215,8 @@ public class CardEdge extends javacard.framework.Applet implements ExtendedLengt
private final static short SW_BIP32_UNINITIALIZED_SEED = (short) 0x9C14;
/** Bip32 seed is already initialized (must be reset before change)*/
private final static short SW_BIP32_INITIALIZED_SEED = (short) 0x9C17;
- /** Bip32 authentikey pubkey is not initialized*/
- private final static short SW_BIP32_UNINITIALIZED_AUTHENTIKEY_PUBKEY= (short) 0x9C16;
+ //** DEPRECATED - Bip32 authentikey pubkey is not initialized*/
+ //private final static short SW_BIP32_UNINITIALIZED_AUTHENTIKEY_PUBKEY= (short) 0x9C16;
/** Incorrect transaction hash */
private final static short SW_INCORRECT_TXHASH = (short) 0x9C15;
@@ -219,6 +225,19 @@ public class CardEdge extends javacard.framework.Applet implements ExtendedLengt
/** 2FA uninitialized*/
private final static short SW_2FA_UNINITIALIZED_KEY = (short) 0x9C19;
+ /** HMAC errors */
+ static final short SW_HMAC_UNSUPPORTED_KEYSIZE = (short) 0x9c1E;
+ static final short SW_HMAC_UNSUPPORTED_MSGSIZE = (short) 0x9c1F;
+
+ /** Secure channel */
+ private final static short SW_SECURE_CHANNEL_REQUIRED = (short) 0x9C20;
+ private final static short SW_SECURE_CHANNEL_UNINITIALIZED = (short) 0x9C21;
+ private final static short SW_SECURE_CHANNEL_WRONG_IV= (short) 0x9C22;
+ private final static short SW_SECURE_CHANNEL_WRONG_MAC= (short) 0x9C23;
+
+ /** For instructions that have been deprecated*/
+ private final static short SW_INS_DEPRECATED = (short) 0x9C26;
+
/** For debugging purposes 2 */
private final static short SW_DEBUG_FLAG = (short) 0x9FFF;
@@ -233,6 +252,7 @@ public class CardEdge extends javacard.framework.Applet implements ExtendedLengt
// JC API 2.2.2 does not define these constants:
private final static byte ALG_ECDSA_SHA_256= (byte) 33;
private final static byte ALG_EC_SVDP_DH_PLAIN= (byte) 3; //https://javacard.kenai.com/javadocs/connected/javacard/security/KeyAgreement.html#ALG_EC_SVDP_DH_PLAIN
+ private final static byte ALG_EC_SVDP_DH_PLAIN_XY= (byte) 6; //https://docs.oracle.com/javacard/3.0.5/api/javacard/security/KeyAgreement.html#ALG_EC_SVDP_DH_PLAIN_XY
private final static short LENGTH_EC_FP_256= (short) 256;
/****************************************
@@ -356,6 +376,24 @@ public class CardEdge extends javacard.framework.Applet implements ExtendedLengt
private Cipher aes128_cbc;
private AESKey key_2FA;
+ // secure channel
+ private static final byte[] CST_SC = {'s','c','_','k','e','y', 's','c','_','m','a','c'};
+ private boolean needs_secure_channel= true;
+ private boolean initialized_secure_channel= false;
+ private ECPrivateKey sc_ephemeralkey;
+ private AESKey sc_sessionkey;
+ private Cipher sc_aes128_cbc;
+ private byte[] sc_buffer;
+ private static final byte OFFSET_SC_IV=0;
+ private static final byte OFFSET_SC_IV_RANDOM=OFFSET_SC_IV;
+ private static final byte OFFSET_SC_IV_COUNTER=12;
+ private static final byte OFFSET_SC_MACKEY=16;
+ private static final byte SIZE_SC_MACKEY=20;
+ private static final byte SIZE_SC_IV= 16;
+ private static final byte SIZE_SC_IV_RANDOM=12;
+ private static final byte SIZE_SC_IV_COUNTER=SIZE_SC_IV-SIZE_SC_IV_RANDOM;
+ private static final byte SIZE_SC_BUFFER=SIZE_SC_MACKEY+SIZE_SC_IV;
+
// additional options
private short option_flags;
@@ -378,6 +416,45 @@ private CardEdge(byte[] bArray, short bOffset, byte bLength) {
pins[0] = new OwnerPIN((byte) 3, (byte) PIN_INIT_VALUE.length);
pins[0].update(PIN_INIT_VALUE, (short) 0, (byte) PIN_INIT_VALUE.length);
+ // Temporary working arrays
+ try {
+ tmpBuffer = JCSystem.makeTransientByteArray((short) TMP_BUFFER_SIZE, JCSystem.CLEAR_ON_DESELECT);
+ } catch (SystemException e) {
+ tmpBuffer = new byte[TMP_BUFFER_SIZE];
+ }
+ // Initialize the extended APDU buffer
+ try {
+ // Try to allocate the extended APDU buffer on RAM memory
+ recvBuffer = JCSystem.makeTransientByteArray((short) EXT_APDU_BUFFER_SIZE, JCSystem.CLEAR_ON_DESELECT);
+ } catch (SystemException e) {
+ // Allocate the extended APDU buffer on EEPROM memory
+ // This is the fallback method, but its usage is really not
+ // recommended as after ~ 100000 writes it will kill the EEPROM cells...
+ recvBuffer = new byte[EXT_APDU_BUFFER_SIZE];
+ }
+
+ // common cryptographic objects
+ randomData = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
+ sigECDSA= Signature.getInstance(ALG_ECDSA_SHA_256, false);
+ HmacSha160.init(tmpBuffer);
+ try {
+ keyAgreement = KeyAgreement.getInstance(ALG_EC_SVDP_DH_PLAIN_XY, false);
+ } catch (CryptoException e) {
+ ISOException.throwIt(SW_UNSUPPORTED_FEATURE);// unsupported feature => use a more recent card!
+ }
+
+ //secure channel objects
+ try {
+ sc_buffer = JCSystem.makeTransientByteArray((short) SIZE_SC_BUFFER, JCSystem.CLEAR_ON_DESELECT);
+ } catch (SystemException e) {
+ sc_buffer = new byte[SIZE_SC_BUFFER];
+ }
+ //sc_IV= new byte[(short)16];//todo make transient and combine?
+ //sc_mackey= new byte[(short)20];
+ sc_sessionkey= (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false); // todo: make transient?
+ sc_ephemeralkey= (ECPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, LENGTH_EC_FP_256, false);
+ sc_aes128_cbc= Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
+
// debug
register();
} // end of constructor
@@ -391,6 +468,10 @@ public boolean select() {
* Application has been selected: Do session cleanup operation
*/
LogOutAll();
+
+ //todo: clear secure channel values?
+ initialized_secure_channel=false;
+
return true;
}
@@ -409,7 +490,7 @@ public void process(APDU apdu) {
// The interface javacard.framework.ISO7816
// declares constants to denote the offset of
// these bytes in the APDU buffer
-
+
if (selectingApplet())
ISOException.throwIt(ISO7816.SW_NO_ERROR);
@@ -424,107 +505,153 @@ public void process(APDU apdu) {
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
byte ins = buffer[ISO7816.OFFSET_INS];
+
+ // prepare APDU buffer
+ if (ins != (byte) INS_GET_STATUS){
+ short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
+ if (bytesLeft != apdu.setIncomingAndReceive())
+ ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
+ }
+
+ // only 3 commands are allowed, the others must be wrapped in a secure channel command
+ // the 3 commands are: get_status, initialize_secure_channel & process_secure_channel
+ short sizeout=(short)0;
+ if (ins == (byte) INS_GET_STATUS){
+ sizeout= GetStatus(apdu, buffer);
+ apdu.setOutgoingAndSend((short) 0, sizeout);
+ return;
+ }
+ else if (ins == (byte) INS_INIT_SECURE_CHANNEL){
+ sizeout= InitiateSecureChannel(apdu, buffer);
+ apdu.setOutgoingAndSend((short) 0, sizeout);
+ return;
+ }
+ else if (ins == (byte) INS_PROCESS_SECURE_CHANNEL){
+ sizeout= ProcessSecureChannel(apdu, buffer);
+ //todo: check if sizeout and buffer[ISO7816.OFFSET_LC] matches...
+ //if sizeout>4, buffer[ISO7816.OFFSET_LC] should be equal to (sizeout-5)
+ //todo: remove padding ? (it is actually not used)
+ }
+ else if (needs_secure_channel){
+ ISOException.throwIt(SW_SECURE_CHANNEL_REQUIRED);
+ }
+
+ // at this point, the encrypted content has been deciphered in the buffer
+ ins = buffer[ISO7816.OFFSET_INS];
+ // check setup status
if (!setupDone && (ins != (byte) INS_SETUP))
ISOException.throwIt(SW_SETUP_NOT_DONE);
if (setupDone && (ins == (byte) INS_SETUP))
ISOException.throwIt(SW_SETUP_ALREADY_DONE);
-
+
switch (ins) {
case INS_SETUP:
- setup(apdu, buffer);
+ sizeout= setup(apdu, buffer);
break;
case INS_IMPORT_KEY:
- ImportKey(apdu, buffer);
+ sizeout= ImportKey(apdu, buffer);
break;
case INS_RESET_KEY:
- ResetKey(apdu, buffer);
+ sizeout= ResetKey(apdu, buffer);
break;
case INS_GET_PUBLIC_FROM_PRIVATE:
- getPublicKeyFromPrivate(apdu, buffer);
+ sizeout= getPublicKeyFromPrivate(apdu, buffer);
break;
case INS_VERIFY_PIN:
- VerifyPIN(apdu, buffer);
+ sizeout= VerifyPIN(apdu, buffer);
break;
case INS_CREATE_PIN:
- CreatePIN(apdu, buffer);
+ sizeout= CreatePIN(apdu, buffer);
break;
case INS_CHANGE_PIN:
- ChangePIN(apdu, buffer);
+ sizeout= ChangePIN(apdu, buffer);
break;
case INS_UNBLOCK_PIN:
- UnblockPIN(apdu, buffer);
+ sizeout= UnblockPIN(apdu, buffer);
break;
case INS_LOGOUT_ALL:
- LogOutAll();
+ sizeout= LogOutAll();
break;
case INS_LIST_PINS:
- ListPINs(apdu, buffer);
+ sizeout= ListPINs(apdu, buffer);
break;
case INS_GET_STATUS:
- GetStatus(apdu, buffer);
+ sizeout= GetStatus(apdu, buffer);
break;
case INS_BIP32_IMPORT_SEED:
- importBIP32Seed(apdu, buffer);
+ sizeout= importBIP32Seed(apdu, buffer);
break;
case INS_BIP32_RESET_SEED:
- resetBIP32Seed(apdu, buffer);
+ sizeout= resetBIP32Seed(apdu, buffer);
break;
case INS_BIP32_GET_AUTHENTIKEY:
- getBIP32AuthentiKey(apdu, buffer);
+ sizeout= getBIP32AuthentiKey(apdu, buffer);
break;
case INS_BIP32_SET_AUTHENTIKEY_PUBKEY:
- setBIP32AuthentikeyPubkey(apdu, buffer);
+ sizeout= setBIP32AuthentikeyPubkey(apdu, buffer);
break;
case INS_BIP32_GET_EXTENDED_KEY:
- getBIP32ExtendedKey(apdu, buffer);
+ sizeout= getBIP32ExtendedKey(apdu, buffer);
break;
case INS_BIP32_SET_EXTENDED_PUBKEY:
- setBIP32ExtendedPubkey(apdu, buffer);
+ sizeout= setBIP32ExtendedPubkey(apdu, buffer);
break;
case INS_SIGN_MESSAGE:
- signMessage(apdu, buffer);
+ sizeout= signMessage(apdu, buffer);
break;
case INS_SIGN_SHORT_MESSAGE:
- signShortMessage(apdu, buffer);
+ //sizeout= signShortMessage(apdu, buffer);
+ ISOException.throwIt(SW_INS_DEPRECATED);
break;
case INS_SIGN_TRANSACTION:
- SignTransaction(apdu, buffer);
+ sizeout= SignTransaction(apdu, buffer);
break;
case INS_SIGN_TRANSACTION_HASH:
- SignTransactionHash(apdu, buffer);
+ sizeout= SignTransactionHash(apdu, buffer);
break;
case INS_PARSE_TRANSACTION:
- ParseTransaction(apdu, buffer);
+ sizeout= ParseTransaction(apdu, buffer);
break;
case INS_SET_2FA_KEY:
- set2FAKey(apdu, buffer);
+ sizeout= set2FAKey(apdu, buffer);
break;
case INS_RESET_2FA_KEY:
- reset2FAKey(apdu, buffer);
+ sizeout= reset2FAKey(apdu, buffer);
break;
case INS_CRYPT_TRANSACTION_2FA:
- CryptTransaction2FA(apdu, buffer);
+ sizeout= CryptTransaction2FA(apdu, buffer);
break;
- // only for debugging purpose
- case INS_BIP32_SET_EXTENDED_KEY:
- ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); // only for debug purpose
- //setBIP32ExtendedKey(apdu, buffer);
- break;
- case INS_COMPUTE_SHA512:
- ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); // only for debug purpose
- //computeSha512(apdu, buffer);
- break;
- case INS_COMPUTE_HMAC:
- ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); // only for debug purpose
- //computeHmac(apdu, buffer);
- break;
- case INS_TEST_SHA1:
- ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); // only for debug purpose
- //testSha512(apdu, buffer)
- break;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
+ }//end of switch
+
+ // Prepare buffer for return
+ if (sizeout==0){
+ return;
+ }
+ else if ((ins == (byte) INS_GET_STATUS) || (ins == (byte) INS_INIT_SECURE_CHANNEL)) {
+ apdu.setOutgoingAndSend((short) 0, sizeout);
+ }
+ else if (needs_secure_channel) { // encrypt response
+ // buffer contains the data (sizeout)
+ // for encryption, data is padded with PKCS#7
+ short blocksize=(short)16;
+ short padsize= (short) (blocksize - (sizeout%blocksize));
+
+ Util.arrayCopy(buffer, (short)0, tmpBuffer, (short)0, sizeout);
+ Util.arrayFillNonAtomic(tmpBuffer, sizeout, padsize, (byte)padsize);//padding
+ Util.arrayCopy(sc_buffer, OFFSET_SC_IV, buffer, (short)0, SIZE_SC_IV);
+ sc_aes128_cbc.init(sc_sessionkey, Cipher.MODE_ENCRYPT, sc_buffer, OFFSET_SC_IV, SIZE_SC_IV);
+ short sizeoutCrypt=sc_aes128_cbc.doFinal(tmpBuffer, (short)0, (short)(sizeout+padsize), buffer, (short) (18));
+ Util.setShort(buffer, (short)16, sizeoutCrypt);
+ sizeout= (short)(18+sizeoutCrypt);
+ //send back
+ apdu.setOutgoingAndSend((short) 0, sizeout);
+ }
+ else {
+ apdu.setOutgoingAndSend((short) 0, sizeout);
}
+
} // end of process method
/**
@@ -555,11 +682,8 @@ public void process(APDU apdu) {
*
* return: none
*/
- private void setup(APDU apdu, byte[] buffer) {
+ private short setup(APDU apdu, byte[] buffer) {
short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
- if (bytesLeft != apdu.setIncomingAndReceive())
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
-
short base = (short) (ISO7816.OFFSET_CDATA);
byte numBytes = buffer[base++];
@@ -569,12 +693,12 @@ private void setup(APDU apdu, byte[] buffer) {
if (!CheckPINPolicy(buffer, base, numBytes))
ISOException.throwIt(SW_INVALID_PARAMETER);
-
- if (pin.getTriesRemaining() == (byte) 0x00)
+
+ byte triesRemaining = pin.getTriesRemaining();
+ if (triesRemaining == (byte) 0x00)
ISOException.throwIt(SW_IDENTITY_BLOCKED);
-
if (!pin.check(buffer, base, numBytes))
- ISOException.throwIt(SW_AUTH_FAILED);
+ ISOException.throwIt((short)(SW_PIN_FAILED + triesRemaining - 1));
base += numBytes;
bytesLeft-=numBytes;
@@ -644,33 +768,12 @@ private void setup(APDU apdu, byte[] buffer) {
eckeys = new Key[MAX_NUM_KEYS];
logged_ids = 0x0000; // No identities logged in
- // Initialize the extended APDU buffer
- try {
- // Try to allocate the extended APDU buffer on RAM memory
- recvBuffer = JCSystem.makeTransientByteArray((short) EXT_APDU_BUFFER_SIZE, JCSystem.CLEAR_ON_DESELECT);
- } catch (SystemException e) {
- // Allocate the extended APDU buffer on EEPROM memory
- // This is the fallback method, but its usage is really not
- // recommended as after ~ 100000 writes it will kill the EEPROM cells...
- recvBuffer = new byte[EXT_APDU_BUFFER_SIZE];
- }
- // temporary buffer
- try {
- tmpBuffer = JCSystem.makeTransientByteArray((short) TMP_BUFFER_SIZE, JCSystem.CLEAR_ON_DESELECT);
- } catch (SystemException e) {
- tmpBuffer = new byte[TMP_BUFFER_SIZE];
- }
-
// shared cryptographic objects
- keyAgreement = KeyAgreement.getInstance(ALG_EC_SVDP_DH_PLAIN, false);
- sigECDSA= Signature.getInstance(ALG_ECDSA_SHA_256, false);
aes128= Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, false);
// HD wallet
- Sha512.init();
HmacSha512.init(tmpBuffer);
- //EccComputation.init(tmpBuffer); //debug
-
+
// bip32 material
bip32_seeded= false;
bip32_master_compbyte=0x04;
@@ -693,7 +796,6 @@ private void setup(APDU apdu, byte[] buffer) {
// Transaction signing
Transaction.init();
- HmacSha160.init(tmpBuffer);
transactionData= new byte[OFFSET_TRANSACTION_SIZE];
// parse options
@@ -712,8 +814,7 @@ private void setup(APDU apdu, byte[] buffer) {
base+=(short)8;
bytesLeft-=(short)8;
// set 2FA variables
- randomData = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
- aes128_cbc= Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
+ aes128_cbc= Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
key_2FA= (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES, KeyBuilder.LENGTH_AES_128, false);
// hmac derivation for id_2FA & key_2FA
HmacSha160.computeHmacSha160(data2FA, OFFSET_2FA_HMACKEY, (short)20, CST_2FA, (short)0, (short)6, data2FA, OFFSET_2FA_ID);
@@ -725,6 +826,7 @@ private void setup(APDU apdu, byte[] buffer) {
}
setupDone = true;
+ return (short)0;//nothing to return
}
/********** UTILITY FUNCTIONS **********/
@@ -786,7 +888,7 @@ private boolean CheckPINPolicy(byte[] pin_buffer, short pin_offset, byte pin_siz
* data: [key_encoding(1) | key_type(1) | key_size(2) | RFU(6) | key_blob | (option)HMAC-2FA(20b)]
* return: none
*/
- private void ImportKey(APDU apdu, byte[] buffer) {
+ private short ImportKey(APDU apdu, byte[] buffer) {
// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
ISOException.throwIt(SW_UNAUTHORIZED);
@@ -798,8 +900,6 @@ private void ImportKey(APDU apdu, byte[] buffer) {
ISOException.throwIt(SW_INCORRECT_P1);
short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
- if (bytesLeft != apdu.setIncomingAndReceive())
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
/*** Start reading key blob header***/
// blob header= [ key_encoding(1) | key_type(1) | key_size(2) | RFU(6)]
@@ -820,7 +920,7 @@ private void ImportKey(APDU apdu, byte[] buffer) {
bytesLeft--;
short key_size = Util.getShort(buffer, dataOffset);
if (key_size != LENGTH_EC_FP_256)
- ISOException.throwIt(key_size);
+ ISOException.throwIt(SW_INVALID_PARAMETER );
dataOffset += (short) 2; // Skip Key Size
bytesLeft -= (short) 2;
dataOffset += (short) 6; // Skip ACL (deprecated)
@@ -856,8 +956,9 @@ private void ImportKey(APDU apdu, byte[] buffer) {
tmpkey.setS(buffer, dataOffset, blob_size);
// compute the corresponding partial public key...
keyAgreement.init(tmpkey);
- keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, recvBuffer, (short)0); // compute x coordinate of public key as k*G
- // hmac of 64-bytes msg: (pubkey-x | 32bytes (0x10^key_nb)-padding)
+ keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, tmpBuffer, (short)0); //pubkey in uncompressed form
+ Util.arrayCopy(tmpBuffer, (short)1, recvBuffer, (short)0, (short)32);
+ // hmac of 64-bytes msg: (pubkey-x | 32bytes (0x10^key_nb)-padding)
Util.arrayFillNonAtomic(recvBuffer, (short)32, (short)32, (byte)(0x10^key_nb));
HmacSha160.computeHmacSha160(data2FA, OFFSET_2FA_HMACKEY, (short)20, recvBuffer, (short)0, (short)64, recvBuffer, (short)64);
if (Util.arrayCompare(buffer, (short)(dataOffset+blob_size), recvBuffer, (short)64, (short)20)!=0)
@@ -867,6 +968,7 @@ private void ImportKey(APDU apdu, byte[] buffer) {
// set key from secret value & set flag
ec_prv_key.setS(buffer, dataOffset, blob_size);
eckeys_flag |= (short) (0x0001 << key_nb);// set corresponding bit flag;
+ return (short)0;
}
/**
@@ -879,7 +981,7 @@ private void ImportKey(APDU apdu, byte[] buffer) {
* data: [ (option)HMAC-2FA(20b)]
* return: none
*/
- private void ResetKey(APDU apdu, byte[] buffer) {
+ private short ResetKey(APDU apdu, byte[] buffer) {
// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
ISOException.throwIt(SW_UNAUTHORIZED);
@@ -898,16 +1000,15 @@ private void ResetKey(APDU apdu, byte[] buffer) {
// check 2FA if required
if (needs_2FA){
short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
- if (bytesLeft != apdu.setIncomingAndReceive())
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
if (bytesLeft < (short)20)
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
// compute the corresponding partial public key...
keyAgreement.init((ECPrivateKey)key);
- keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, recvBuffer, (short)0); // compute x coordinate of public key as k*G
- // hmac of 64-bytes msg: (pubkey-x | 32bytes (0x20^key_nb)-padding)
+ keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, tmpBuffer, (short)0); //pubkey in uncompressed form
+ Util.arrayCopy(tmpBuffer, (short)1, recvBuffer, (short)0, (short)32);
+ // hmac of 64-bytes msg: (pubkey-x | 32bytes (0x20^key_nb)-padding)
Util.arrayFillNonAtomic(recvBuffer, (short)32, (short)32, (byte) (0x20^key_nb));
HmacSha160.computeHmacSha160(data2FA, OFFSET_2FA_HMACKEY, (short)20, recvBuffer, (short)0, (short)64, recvBuffer, (short)64);
if (Util.arrayCompare(buffer, ISO7816.OFFSET_CDATA, recvBuffer, (short)64, (short)20)!=0)
@@ -917,6 +1018,8 @@ private void ResetKey(APDU apdu, byte[] buffer) {
// clear key & reset flag
key.clearKey();
eckeys_flag &= (short) ~(0x0001 << key_nb);// reset corresponding bit flag;
+
+ return (short)0;
}
/**
@@ -929,16 +1032,14 @@ private void ResetKey(APDU apdu, byte[] buffer) {
* data: none
* return(SECP256K1): [coordx_size(2b) | pubkey_coordx | sig_size(2b) | sig]
*/
- private void getPublicKeyFromPrivate(APDU apdu, byte[] buffer) {
+ private short getPublicKeyFromPrivate(APDU apdu, byte[] buffer) {
// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
ISOException.throwIt(SW_UNAUTHORIZED);
if (buffer[ISO7816.OFFSET_P2] != (byte) 0x00)
ISOException.throwIt(SW_INCORRECT_P2);
- short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
- if (bytesLeft != apdu.setIncomingAndReceive())
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
+
byte key_nb = buffer[ISO7816.OFFSET_P1];
if ((key_nb < 0) || (key_nb >= MAX_NUM_KEYS))
ISOException.throwIt(SW_INCORRECT_P1);
@@ -957,8 +1058,9 @@ private void getPublicKeyFromPrivate(APDU apdu, byte[] buffer) {
// compute the corresponding partial public key...
keyAgreement.init((ECPrivateKey)key);
- short coordx_size = keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, buffer, (short)2); // compute x coordinate of public key as k*G
- Util.setShort(buffer, (short)0, coordx_size);
+ short coordx_size=(short)32;
+ keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, buffer, (short)1); //pubkey in uncompressed form
+ Util.setShort(buffer, (short)0, coordx_size);
// sign fixed message
sigECDSA.init(key, Signature.MODE_SIGN);
@@ -968,7 +1070,7 @@ private void getPublicKeyFromPrivate(APDU apdu, byte[] buffer) {
// return x-coordinate of public key+signature
// the client can recover full public-key from the signature or
// by guessing the compression value () and verifying the signature...
- apdu.setOutgoingAndSend((short) 0, (short)(2+coordx_size+2+sign_size));
+ return (short)(2+coordx_size+2+sign_size);
}
/**
@@ -983,7 +1085,7 @@ private void getPublicKeyFromPrivate(APDU apdu, byte[] buffer) {
* data: [PIN_size(1b) | PIN | UBLK_size(1b) | UBLK]
* return: none
*/
- private void CreatePIN(APDU apdu, byte[] buffer) {
+ private short CreatePIN(APDU apdu, byte[] buffer) {
// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
ISOException.throwIt(SW_UNAUTHORIZED);
@@ -994,19 +1096,17 @@ private void CreatePIN(APDU apdu, byte[] buffer) {
if ((pin_nb < 0) || (pin_nb >= MAX_NUM_PINS) || (pins[pin_nb] != null))
ISOException.throwIt(SW_INCORRECT_P1);
/* Allow pin lengths > 127 (useful at all ?) */
- short avail = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
- if (apdu.setIncomingAndReceive() != avail)
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
+ short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
// At least 1 character for PIN and 1 for unblock code (+ lengths)
- if (avail < 4)
+ if (bytesLeft < 4)
ISOException.throwIt(SW_INVALID_PARAMETER);
byte pin_size = buffer[ISO7816.OFFSET_CDATA];
- if (avail < (short) (1 + pin_size + 1))
+ if (bytesLeft < (short) (1 + pin_size + 1))
ISOException.throwIt(SW_INVALID_PARAMETER);
if (!CheckPINPolicy(buffer, (short) (ISO7816.OFFSET_CDATA + 1), pin_size))
ISOException.throwIt(SW_INVALID_PARAMETER);
byte ucode_size = buffer[(short) (ISO7816.OFFSET_CDATA + 1 + pin_size)];
- if (avail != (short) (1 + pin_size + 1 + ucode_size))
+ if (bytesLeft != (short) (1 + pin_size + 1 + ucode_size))
ISOException.throwIt(SW_INVALID_PARAMETER);
if (!CheckPINPolicy(buffer, (short) (ISO7816.OFFSET_CDATA + 1 + pin_size + 1), ucode_size))
ISOException.throwIt(SW_INVALID_PARAMETER);
@@ -1016,6 +1116,8 @@ private void CreatePIN(APDU apdu, byte[] buffer) {
// Recycle variable pin_size
pin_size = (byte) (ISO7816.OFFSET_CDATA + 1 + pin_size + 1);
ublk_pins[pin_nb].update(buffer, pin_size, ucode_size);
+
+ return (short)0;
}
/**
@@ -1030,7 +1132,7 @@ private void CreatePIN(APDU apdu, byte[] buffer) {
* data: [PIN]
* return: none (throws an exception in case of wrong PIN)
*/
- private void VerifyPIN(APDU apdu, byte[] buffer) {
+ private short VerifyPIN(APDU apdu, byte[] buffer) {
byte pin_nb = buffer[ISO7816.OFFSET_P1];
if ((pin_nb < 0) || (pin_nb >= MAX_NUM_PINS))
ISOException.throwIt(SW_INCORRECT_P1);
@@ -1039,24 +1141,26 @@ private void VerifyPIN(APDU apdu, byte[] buffer) {
ISOException.throwIt(SW_INCORRECT_P1);
if (buffer[ISO7816.OFFSET_P2] != 0x00)
ISOException.throwIt(SW_INCORRECT_P2);
- short numBytes = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
+ short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
/*
* Here I suppose the PIN code is small enough to enter in the buffer
* TODO: Verify the assumption and eventually adjust code to support
* reading PIN in multiple read()s
*/
- if (numBytes != apdu.setIncomingAndReceive())
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
- if (!CheckPINPolicy(buffer, ISO7816.OFFSET_CDATA, (byte) numBytes))
+ if (!CheckPINPolicy(buffer, ISO7816.OFFSET_CDATA, (byte) bytesLeft))
ISOException.throwIt(SW_INVALID_PARAMETER);
- if (pin.getTriesRemaining() == (byte) 0x00)
+ byte triesRemaining = pin.getTriesRemaining();
+ if (triesRemaining == (byte) 0x00)
ISOException.throwIt(SW_IDENTITY_BLOCKED);
- if (!pin.check(buffer, (short) ISO7816.OFFSET_CDATA, (byte) numBytes)) {
+ if (!pin.check(buffer, (short) ISO7816.OFFSET_CDATA, (byte) bytesLeft)) {
LogoutIdentity(pin_nb);
- ISOException.throwIt(SW_AUTH_FAILED);
+ ISOException.throwIt((short)(SW_PIN_FAILED + triesRemaining - 1));
}
+
// Actually register that PIN has been successfully verified.
logged_ids |= (short) (0x0001 << pin_nb);
+
+ return (short)0;
}
@@ -1070,7 +1174,7 @@ private void VerifyPIN(APDU apdu, byte[] buffer) {
* data: [PIN_size(1b) | old_PIN | PIN_size(1b) | new_PIN ]
* return: none (throws an exception in case of wrong PIN)
*/
- private void ChangePIN(APDU apdu, byte[] buffer) {
+ private short ChangePIN(APDU apdu, byte[] buffer) {
/*
* Here I suppose the PIN code is small enough that 2 of them enter in
* the buffer TODO: Verify the assumption and eventually adjust code to
@@ -1084,31 +1188,34 @@ private void ChangePIN(APDU apdu, byte[] buffer) {
ISOException.throwIt(SW_INCORRECT_P1);
if (buffer[ISO7816.OFFSET_P2] != (byte) 0x00)
ISOException.throwIt(SW_INCORRECT_P2);
- short avail = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
- if (apdu.setIncomingAndReceive() != avail)
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
+ short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
// At least 1 character for each PIN code
- if (avail < 4)
+ if (bytesLeft < 4)
ISOException.throwIt(SW_INVALID_PARAMETER);
byte pin_size = buffer[ISO7816.OFFSET_CDATA];
- if (avail < (short) (1 + pin_size + 1))
+ if (bytesLeft < (short) (1 + pin_size + 1))
ISOException.throwIt(SW_INVALID_PARAMETER);
if (!CheckPINPolicy(buffer, (short) (ISO7816.OFFSET_CDATA + 1), pin_size))
ISOException.throwIt(SW_INVALID_PARAMETER);
byte new_pin_size = buffer[(short) (ISO7816.OFFSET_CDATA + 1 + pin_size)];
- if (avail < (short) (1 + pin_size + 1 + new_pin_size))
+ if (bytesLeft < (short) (1 + pin_size + 1 + new_pin_size))
ISOException.throwIt(SW_INVALID_PARAMETER);
if (!CheckPINPolicy(buffer, (short) (ISO7816.OFFSET_CDATA + 1 + pin_size + 1), new_pin_size))
ISOException.throwIt(SW_INVALID_PARAMETER);
- if (pin.getTriesRemaining() == (byte) 0x00)
+
+ byte triesRemaining = pin.getTriesRemaining();
+ if (triesRemaining == (byte) 0x00)
ISOException.throwIt(SW_IDENTITY_BLOCKED);
if (!pin.check(buffer, (short) (ISO7816.OFFSET_CDATA + 1), pin_size)) {
LogoutIdentity(pin_nb);
- ISOException.throwIt(SW_AUTH_FAILED);
+ ISOException.throwIt((short)(SW_PIN_FAILED + triesRemaining - 1));
}
+
pin.update(buffer, (short) (ISO7816.OFFSET_CDATA + 1 + pin_size + 1), new_pin_size);
// JC specifies this resets the validated flag. So we do.
logged_ids &= (short) ((short) 0xFFFF ^ (0x01 << pin_nb));
+
+ return (short)0;
}
/**
@@ -1121,7 +1228,7 @@ private void ChangePIN(APDU apdu, byte[] buffer) {
* data: [PUK]
* return: none (throws an exception in case of wrong PUK)
*/
- private void UnblockPIN(APDU apdu, byte[] buffer) {
+ private short UnblockPIN(APDU apdu, byte[] buffer) {
byte pin_nb = buffer[ISO7816.OFFSET_P1];
if ((pin_nb < 0) || (pin_nb >= MAX_NUM_PINS))
ISOException.throwIt(SW_INCORRECT_P1);
@@ -1136,27 +1243,33 @@ private void UnblockPIN(APDU apdu, byte[] buffer) {
ISOException.throwIt(SW_OPERATION_NOT_ALLOWED);
if (buffer[ISO7816.OFFSET_P2] != 0x00)
ISOException.throwIt(SW_INCORRECT_P2);
- short numBytes = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
+ short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
/*
* Here I suppose the PIN code is small enough to fit into the buffer
* TODO: Verify the assumption and eventually adjust code to support
* reading PIN in multiple read()s
*/
- if (numBytes != apdu.setIncomingAndReceive())
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
- if (!CheckPINPolicy(buffer, ISO7816.OFFSET_CDATA, (byte) numBytes))
+ if (!CheckPINPolicy(buffer, ISO7816.OFFSET_CDATA, (byte) bytesLeft))
ISOException.throwIt(SW_INVALID_PARAMETER);
- if (!ublk_pin.check(buffer, ISO7816.OFFSET_CDATA, (byte) numBytes))
- ISOException.throwIt(SW_AUTH_FAILED);
+ byte triesRemaining = ublk_pin.getTriesRemaining();
+ if (triesRemaining == (byte) 0x00)
+ ISOException.throwIt(SW_IDENTITY_BLOCKED);
+ if (!ublk_pin.check(buffer, ISO7816.OFFSET_CDATA, (byte) bytesLeft))
+ ISOException.throwIt((short)(SW_PIN_FAILED + triesRemaining - 1));
+
pin.resetAndUnblock();
+
+ return (short)0;
}
- private void LogOutAll() {
+ private short LogOutAll() {
logged_ids = (short) 0x0000; // Nobody is logged in
byte i;
for (i = (byte) 0; i < MAX_NUM_PINS; i++)
if (pins[i] != null)
pins[i].reset();
+
+ return (short)0;
}
/**
@@ -1169,7 +1282,7 @@ private void LogOutAll() {
* data: none
* return: [RFU(1b) | PIN_mask(1b)]
*/
- private void ListPINs(APDU apdu, byte[] buffer) {
+ private short ListPINs(APDU apdu, byte[] buffer) {
// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
ISOException.throwIt(SW_UNAUTHORIZED);
@@ -1191,7 +1304,7 @@ private void ListPINs(APDU apdu, byte[] buffer) {
// Fill the buffer
Util.setShort(buffer, (short) 0, mask);
// Send response
- apdu.setOutgoingAndSend((short) 0, (short) 2);
+ return (short)2;
}
/**
@@ -1203,9 +1316,9 @@ private void ListPINs(APDU apdu, byte[] buffer) {
* p1: 0x00
* p2: 0x00
* data: none
- * return: [versions(4b) | PIN0-PUK0-PIN1-PUK1 tries (4b) | needs2FA (1b) | is_seeded(1b) ]
+ * return: [versions(4b) | PIN0-PUK0-PIN1-PUK1 tries (4b) | needs2FA (1b) | is_seeded(1b) | setupDone(1b) | needs_secure_channel(1b)]
*/
- private void GetStatus(APDU apdu, byte[] buffer) {
+ private short GetStatus(APDU apdu, byte[] buffer) {
// check that PIN[0] has been entered previously
//if (!pins[0].isValidated())
// ISOException.throwIt(SW_UNAUTHORIZED);
@@ -1214,16 +1327,24 @@ private void GetStatus(APDU apdu, byte[] buffer) {
ISOException.throwIt(SW_INCORRECT_P1);
if (buffer[ISO7816.OFFSET_P2] != (byte) 0x00)
ISOException.throwIt(SW_INCORRECT_P2);
+
short pos = (short) 0;
buffer[pos++] = (byte) PROTOCOL_MAJOR_VERSION; // Major Card Edge Protocol version n.
buffer[pos++] = (byte) PROTOCOL_MINOR_VERSION; // Minor Card Edge Protocol version n.
buffer[pos++] = (byte) APPLET_MAJOR_VERSION; // Major Applet version n.
buffer[pos++] = (byte) APPLET_MINOR_VERSION; // Minor Applet version n.
// PIN/PUK remaining tries available
- buffer[pos++] = pins[0].getTriesRemaining();
- buffer[pos++] = ublk_pins[0].getTriesRemaining();
- buffer[pos++] = pins[1].getTriesRemaining();
- buffer[pos++] = ublk_pins[1].getTriesRemaining();
+ if (setupDone){
+ buffer[pos++] = pins[0].getTriesRemaining();
+ buffer[pos++] = ublk_pins[0].getTriesRemaining();
+ buffer[pos++] = pins[1].getTriesRemaining();
+ buffer[pos++] = ublk_pins[1].getTriesRemaining();
+ } else {
+ buffer[pos++] = (byte) 0;
+ buffer[pos++] = (byte) 0;
+ buffer[pos++] = (byte) 0;
+ buffer[pos++] = (byte) 0;
+ }
if (needs_2FA)
buffer[pos++] = (byte)0x01;
else
@@ -1232,7 +1353,16 @@ private void GetStatus(APDU apdu, byte[] buffer) {
buffer[pos++] = (byte)0x01;
else
buffer[pos++] = (byte)0x00;
- apdu.setOutgoingAndSend((short) 0, pos);
+ if (setupDone)
+ buffer[pos++] = (byte)0x01;
+ else
+ buffer[pos++] = (byte)0x00;
+ if (needs_secure_channel)
+ buffer[pos++] = (byte)0x01;
+ else
+ buffer[pos++] = (byte)0x00;
+
+ return pos;
}
/**
@@ -1250,7 +1380,7 @@ private void GetStatus(APDU apdu, byte[] buffer) {
* data: [seed_data (seed_size)]
* return: [coordx_size(2b) | coordx | sig_size(2b) | sig]
*/
- private void importBIP32Seed(APDU apdu, byte[] buffer){
+ private short importBIP32Seed(APDU apdu, byte[] buffer){
// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
ISOException.throwIt(SW_UNAUTHORIZED);
@@ -1261,8 +1391,6 @@ private void importBIP32Seed(APDU apdu, byte[] buffer){
ISOException.throwIt(SW_BIP32_INITIALIZED_SEED);
short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
- if (bytesLeft != apdu.setIncomingAndReceive())
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
// get seed bytesize (max 64 bytes)
byte bip32_seedsize = buffer[ISO7816.OFFSET_P1];
@@ -1291,9 +1419,9 @@ private void importBIP32Seed(APDU apdu, byte[] buffer){
// compute the partial authentikey public key...
keyAgreement.init(bip32_authentikey);
- authentikey_pubkey[0]=0x00; // 0x00 means coordy is not set (yet), otherwise 0x04
- short coordx_size = keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, authentikey_pubkey, (short)1); // compute x coordinate of public key as k*G
- Util.setShort(buffer, (short)0, coordx_size);
+ short coordx_size= (short)32;
+ keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, authentikey_pubkey, (short)0); //pubkey in uncompressed form
+ Util.setShort(buffer, (short)0, coordx_size);
Util.arrayCopyNonAtomic(authentikey_pubkey, (short)1, buffer, (short)2, coordx_size);
// self signed public key
sigECDSA.init(bip32_authentikey, Signature.MODE_SIGN);
@@ -1304,7 +1432,7 @@ private void importBIP32Seed(APDU apdu, byte[] buffer){
// the client can recover full public-key from the signature or
// by guessing the compression value () and verifying the signature...
// buffer= [coordx_size(2) | coordx | sigsize(2) | sig]
- apdu.setOutgoingAndSend((short) 0, (short)(2+coordx_size+2+sign_size));
+ return (short)(2+coordx_size+2+sign_size);
}
/**
@@ -1318,11 +1446,9 @@ private void importBIP32Seed(APDU apdu, byte[] buffer){
* data: [PIN | optional-hmac(20b)]
* return: (none)
*/
- private void resetBIP32Seed(APDU apdu, byte[] buffer){
+ private short resetBIP32Seed(APDU apdu, byte[] buffer){
short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
- if (bytesLeft != apdu.setIncomingAndReceive())
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
// check provided PIN
byte pin_size= buffer[ISO7816.OFFSET_P1];
@@ -1331,11 +1457,13 @@ private void resetBIP32Seed(APDU apdu, byte[] buffer){
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
if (!CheckPINPolicy(buffer, ISO7816.OFFSET_CDATA, pin_size))
ISOException.throwIt(SW_INVALID_PARAMETER);
- if (pin.getTriesRemaining() == (byte) 0x00)
+
+ byte triesRemaining = pin.getTriesRemaining();
+ if (triesRemaining == (byte) 0x00)
ISOException.throwIt(SW_IDENTITY_BLOCKED);
if (!pin.check(buffer, (short) ISO7816.OFFSET_CDATA, (byte) pin_size)) {
LogoutIdentity((byte)0x00);
- ISOException.throwIt(SW_AUTH_FAILED);
+ ISOException.throwIt((short)(SW_PIN_FAILED + triesRemaining - 1));
}
// check if seeded
@@ -1368,7 +1496,7 @@ private void resetBIP32Seed(APDU apdu, byte[] buffer){
Secp256k1.setCommonCurveParameters(bip32_authentikey);// keep public params!
Util.arrayFillNonAtomic(authentikey_pubkey, (short)0, (short)(2*BIP32_KEY_SIZE+1), (byte)0x00);
LogOutAll();
- return;
+ return (short)0;
}
/**
@@ -1382,7 +1510,7 @@ private void resetBIP32Seed(APDU apdu, byte[] buffer){
* data: none
* return: [coordx_size(2b) | coordx | sig_size(2b) | sig]
*/
- private void getBIP32AuthentiKey(APDU apdu, byte[] buffer){
+ private short getBIP32AuthentiKey(APDU apdu, byte[] buffer){
// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
ISOException.throwIt(SW_UNAUTHORIZED);
@@ -1392,9 +1520,10 @@ private void getBIP32AuthentiKey(APDU apdu, byte[] buffer){
ISOException.throwIt(SW_BIP32_UNINITIALIZED_SEED);
// compute the partial authentikey public key...
- keyAgreement.init(bip32_authentikey);
- short coordx_size = keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, buffer, (short)2); // compute x coordinate of public key as k*G
- Util.setShort(buffer, (short)0, coordx_size);
+ keyAgreement.init(bip32_authentikey);
+ short coordx_size= (short)32;
+ keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, buffer, (short)1); //pubkey in uncompressed form
+ Util.setShort(buffer, (short)0, coordx_size);
// self signed public key
sigECDSA.init(bip32_authentikey, Signature.MODE_SIGN);
short sign_size= sigECDSA.sign(buffer, (short)0, (short)(coordx_size+2), buffer, (short)(coordx_size+4));
@@ -1404,10 +1533,13 @@ private void getBIP32AuthentiKey(APDU apdu, byte[] buffer){
// the client can recover full public-key from the signature or
// by guessing the compression value () and verifying the signature...
// buffer= [coordx_size(2) | coordx | sigsize(2) | sig]
- apdu.setOutgoingAndSend((short) 0, (short)(coordx_size+sign_size+4));
+ return (short)(coordx_size+sign_size+4);
}
/**
+ * DEPRECATED - Not necessary anymore when recovering the pubkey with ALG_EC_SVDP_DH_PLAIN_XY
+ * A minimalist API is maintained for backward compatibility.
+ *
* This function allows to compute the authentikey pubkey externally and
* store it in the secure memory cache for future use.
* This allows to speed up computation during derivation of non-hardened child.
@@ -1419,60 +1551,24 @@ private void getBIP32AuthentiKey(APDU apdu, byte[] buffer){
*
* returns: none
*/
- private void setBIP32AuthentikeyPubkey(APDU apdu, byte[] buffer){
+ private short setBIP32AuthentikeyPubkey(APDU apdu, byte[] buffer){
// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
ISOException.throwIt(SW_UNAUTHORIZED);
- // check whether the seed is initialized
- if (!bip32_seeded)
- ISOException.throwIt(SW_BIP32_UNINITIALIZED_SEED);
-
- // input
- short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
- if (bytesLeft != apdu.setIncomingAndReceive())
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
-
- short offset= (short) ISO7816.OFFSET_CDATA;
- short coordx_size= Util.getShort(buffer, offset);
- offset+=2;
- offset+=coordx_size;
- short sig_size= Util.getShort(buffer, offset);
- offset+=2;
- short offset_sig=offset;
- offset+=sig_size;
- short coordy_size= Util.getShort(buffer, offset);
- offset+=2;
- // copy pubkey coordy
- Util.arrayCopyNonAtomic(buffer, offset, recvBuffer, (short)(1+coordx_size), coordy_size);
- offset+=coordy_size;
- // copy pubkey coordx from trusted source
- recvBuffer[0]=0x04;
- Util.arrayCopyNonAtomic(authentikey_pubkey, (short)1, recvBuffer, (short)(1), BIP32_KEY_SIZE);
-
- // verify that authentikey signature is valid
- bip32_pubkey.setW(recvBuffer, (short)(0), (short)(1+coordx_size+coordy_size));
- sigECDSA.init(bip32_pubkey, Signature.MODE_VERIFY);
- boolean verify= sigECDSA.verify(buffer, (short)ISO7816.OFFSET_CDATA, (short)(2+coordx_size), buffer, offset_sig, sig_size);
- if (!verify)
- ISOException.throwIt(SW_SIGNATURE_INVALID);
- // copy coordy to secure memory
- authentikey_pubkey[0]=0x04;
- Util.arrayCopyNonAtomic(recvBuffer, (short)(1+BIP32_KEY_SIZE), authentikey_pubkey, (short)(1+BIP32_KEY_SIZE), BIP32_KEY_SIZE);
-
short pos=0;
Util.setShort(buffer, pos, bip32_om.nb_elem_free); // number of slot available
pos += (short) 2;
Util.setShort(buffer, pos, bip32_om.nb_elem_used); // number of slot used
pos += (short) 2;
- apdu.setOutgoingAndSend((short) 0, pos);
+ return pos;
}// end of setBIP32AuthentikeyPubkey
/**
* The function computes the Bip32 extended key derived from the master key and returns the
* x-coordinate of the public key signed by the authentikey.
* Extended key is stored in the chip in a temporary EC key, along with corresponding ACL
- * Extended key and chaincode is also cached as a Bip32 object is secure memory
+ * Extended key and chaincode is also cached as a Bip32 object in secure memory
*
* ins: 0x6D
* p1: depth of the extended key (master is depth 0, m/i is depht 1). Max depth is 10
@@ -1486,7 +1582,7 @@ private void setBIP32AuthentikeyPubkey(APDU apdu, byte[] buffer){
* returns: [chaincode(32b) | coordx_size(2b) | coordx | sig_size(2b) | sig | sig_size(2b) | sig2]
*
* */
- private void getBIP32ExtendedKey(APDU apdu, byte[] buffer){
+ private short getBIP32ExtendedKey(APDU apdu, byte[] buffer){
// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
ISOException.throwIt(SW_UNAUTHORIZED);
@@ -1497,13 +1593,11 @@ private void getBIP32ExtendedKey(APDU apdu, byte[] buffer){
// input
short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
- if (bytesLeft != apdu.setIncomingAndReceive())
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
byte bip32_depth = buffer[ISO7816.OFFSET_P1];
if ((bip32_depth < 0) || (bip32_depth > MAX_BIP32_DEPTH) )
ISOException.throwIt(SW_INCORRECT_P1);
- if (bytesLeft < 4*bip32_depth)
+ if (bytesLeft < (short)(4*bip32_depth))
ISOException.throwIt(SW_INVALID_PARAMETER);
// P2 option flags
@@ -1523,7 +1617,6 @@ private void getBIP32ExtendedKey(APDU apdu, byte[] buffer){
short parent_base=Bip32ObjectManager.NULL_OFFSET;
// iterate on indexes provided
- short exit_early=0x0000;
for (byte i=1; i<=bip32_depth; i++){
//compute SHA of the extended key address up to depth i (only the last bytes are actually used)
@@ -1551,44 +1644,17 @@ private void getBIP32ExtendedKey(APDU apdu, byte[] buffer){
// compute coord x from privkey
bip32_extendedkey.setS(recvBuffer, BIP32_OFFSET_PARENT_KEY, BIP32_KEY_SIZE);
keyAgreement.init(bip32_extendedkey);
- short coordx_size= keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, recvBuffer, BIP32_OFFSET_PUBX);
- // compute compbyte from coord y if necessary (slow!)
- if (compbyte==0x04 && (opts & 0x40)!=0x40){
- // coord y= square root of X^3+7 mod p => 2 solutions!
- EccComputation.SqrtRootOpt(recvBuffer, BIP32_OFFSET_PUBX, recvBuffer, BIP32_OFFSET_PUBY);
- recvBuffer[BIP32_OFFSET_PUB]=0x04;
- // sign a dummy message
- sigECDSA.init(bip32_extendedkey, Signature.MODE_SIGN);
- short sigsize=sigECDSA.sign(recvBuffer, (short)0, (short)32, buffer, BIP32_OFFSET_SIG);
- // verify sig with pubkey (x,y) & recover compression byte
- bip32_pubkey.setW(recvBuffer, BIP32_OFFSET_PUB, (short)(2*BIP32_KEY_SIZE+1)) ;
- sigECDSA.init(bip32_pubkey, Signature.MODE_VERIFY);
- boolean verify= sigECDSA.verify(recvBuffer, (short)0, (short)32, buffer, BIP32_OFFSET_SIG, sigsize);
- boolean parity= ((recvBuffer[(short)(BIP32_OFFSET_PUBY+31)]&0x01)==0);
- compbyte= (verify^parity)?(byte)0x03:(byte)0x02;
- // save compbyte in parent's object for future use
- if (parent_base==Bip32ObjectManager.NULL_OFFSET)
- bip32_master_compbyte= compbyte;
- else
- bip32_om.setByte(parent_base, (short)(BIP32_OBJECT_SIZE-1), compbyte);//bip32_mem.setByte(parent_base, (short)(BIP32_OBJECT_SIZE-1), compbyte);//debugOM
- }
- // compute compbyte from coord y externally (faster!)
- if (compbyte==0x04 && (opts & 0x40)==0x40){
- // exit the for loop prematurely
- // the data returned is related to the parent with non-hardened child
- // we can then compute the coord-y externally
- // save hash of parent path (or 000...0 if masterkey)
- if (parent_base==Bip32ObjectManager.NULL_OFFSET){
- Util.arrayFillNonAtomic(buffer, (short)0, (short)32, (byte)0);
- }else{
- sha256.reset();
- sha256.doFinal(recvBuffer, BIP32_OFFSET_PATH, (short)(4*(i-1)), buffer, (byte)0);
- }
- exit_early=(short)0x8000;
- break;
- }
-
+ // keyAgreement.generateSecret() recovers X and Y coordinates
+ keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, recvBuffer, BIP32_OFFSET_PUB); //pubkey in uncompressed form
+ boolean parity= ((recvBuffer[(short)(BIP32_OFFSET_PUBY+31)]&0x01)==0);
+ compbyte= (parity)?(byte)0x02:(byte)0x03;
+ // save compbyte in parent's object for future use
+ if (parent_base==Bip32ObjectManager.NULL_OFFSET)
+ bip32_master_compbyte= compbyte;
+ else
+ bip32_om.setByte(parent_base, (short)(BIP32_OBJECT_SIZE-1), compbyte);
+
// compute HMAC of compressed pubkey + index
recvBuffer[BIP32_OFFSET_PUB]= compbyte;
Util.arrayCopyNonAtomic(recvBuffer, (short)(BIP32_OFFSET_PATH+4*(i-1)), recvBuffer, BIP32_OFFSET_PUBY, (short)4);
@@ -1650,17 +1716,15 @@ private void getBIP32ExtendedKey(APDU apdu, byte[] buffer){
// instantiate elliptic curve with last extended key + copy ACL
bip32_extendedkey.setS(recvBuffer, BIP32_OFFSET_PARENT_KEY, BIP32_KEY_SIZE);
- if (exit_early==0x0000){
- // save chaincode to buffer, otherwise buffer already contains hash of path
- Util.arrayCopyNonAtomic(recvBuffer, (short)BIP32_OFFSET_PARENT_CHAINCODE, buffer, (short)0, BIP32_KEY_SIZE);
- }
- // clear recvBuffer
+ // save chaincode to buffer then clear recvBuffer
+ Util.arrayCopyNonAtomic(recvBuffer, (short)BIP32_OFFSET_PARENT_CHAINCODE, buffer, (short)0, BIP32_KEY_SIZE);
Util.arrayFillNonAtomic(recvBuffer, BIP32_OFFSET_PARENT_CHAINCODE, BIP32_OFFSET_END, (byte)0);
// compute the corresponding partial public key...
keyAgreement.init(bip32_extendedkey);
- short coordx_size = keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, buffer, (short)34); // compute x coordinate of public key as k*G
- Util.setShort(buffer, BIP32_KEY_SIZE, (short)(coordx_size^exit_early)); //exit_early flag signals we want to compute pubkey externaly
+ short coordx_size= (short)32;
+ keyAgreement.generateSecret(Secp256k1.SECP256K1, Secp256k1.OFFSET_SECP256K1_G, (short) 65, buffer, (short)33); //pubkey in uncompressed form
+ Util.setShort(buffer, BIP32_KEY_SIZE, (short)(coordx_size));
// self-sign coordx
sigECDSA.init(bip32_extendedkey, Signature.MODE_SIGN);
@@ -1675,11 +1739,14 @@ private void getBIP32ExtendedKey(APDU apdu, byte[] buffer){
// return x-coordinate of public key+signatures
// the client can recover full public-key by guessing the compression value () and verifying the signature...
// buffer=[chaincode(32) | coordx_size(2) | coordx | sign_size(2) | self-sign | sign_size(2) | auth_sign]
- apdu.setOutgoingAndSend((short) 0, (short)(BIP32_KEY_SIZE+coordx_size+sign_size+sign_size2+6));
+ return (short)(BIP32_KEY_SIZE+coordx_size+sign_size+sign_size2+6);
}// end of getBip32ExtendedKey()
/**
+ * DEPRECATED - Not necessary anymore when recovering the pubkey with ALG_EC_SVDP_DH_PLAIN_XY
+ * A minimalist API is maintained for backward compatibility.
+ *
* This function allows to compute an extended pubkey externally and
* store it in the secure BIP32 memory cache for future use.
* This allows to speed up computation during derivation of non-hardened child.
@@ -1691,80 +1758,17 @@ private void getBIP32ExtendedKey(APDU apdu, byte[] buffer){
* [ coordy_size(2b) | coordy]
* returns: none
*/
- private void setBIP32ExtendedPubkey(APDU apdu, byte[] buffer){
+ private short setBIP32ExtendedPubkey(APDU apdu, byte[] buffer){
// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
ISOException.throwIt(SW_UNAUTHORIZED);
- // check whether the seed is initialized
- if (!bip32_seeded)
- ISOException.throwIt(SW_BIP32_UNINITIALIZED_SEED);
-
- // input
- short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
- if (bytesLeft != apdu.setIncomingAndReceive())
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);//ISOException.throwIt(bytesLeft);//
-
- short offset= (short) ISO7816.OFFSET_CDATA;
- offset+=32;
- short coordx_size= Util.getShort(buffer, offset);
- // check that the correct flag is set on msb of coordx_size
- if ((coordx_size & (short)0x8000) == (short)0x8000)
- coordx_size= (short)(coordx_size & 0x7fff);
- else
- ISOException.throwIt(SW_OPERATION_NOT_ALLOWED);
- offset+=2;
- //copy pubkey
- recvBuffer[0]=0x04;
- Util.arrayCopyNonAtomic(buffer, offset, recvBuffer, (short)1, coordx_size);
- offset+=coordx_size;
- short sig_size= Util.getShort(buffer, offset);
- offset+=2;
- short offset_sig=offset;
- offset+=sig_size;
- short authsig_size= Util.getShort(buffer, offset);
- offset+=2;
- short offset_authsig=offset;
- offset+=authsig_size;
- short coordy_size= Util.getShort(buffer, offset);
- offset+=2;
- // copy pubkey
- Util.arrayCopyNonAtomic(buffer, offset, recvBuffer, (short)(1+coordx_size), coordy_size);
- offset+=coordy_size;
-
- // verify that authentikey signature is valid
- if (authentikey_pubkey[0]!=(byte)0x04)
- ISOException.throwIt(SW_BIP32_UNINITIALIZED_AUTHENTIKEY_PUBKEY);
- bip32_pubkey.setW(authentikey_pubkey, (short)(0), (short)(1+2*BIP32_KEY_SIZE));
- sigECDSA.init(bip32_pubkey, Signature.MODE_VERIFY);
- boolean verify= sigECDSA.verify(buffer, (short)ISO7816.OFFSET_CDATA, (short)(32+2+coordx_size+2+sig_size), buffer, offset_authsig, authsig_size);
- if (!verify)
- ISOException.throwIt(SW_SIGNATURE_INVALID);
- // verify that coordy is legit
- bip32_pubkey.setW(recvBuffer, (short)(0), (short)(1+coordx_size+coordy_size));
- sigECDSA.init(bip32_pubkey, Signature.MODE_VERIFY);
- verify= sigECDSA.verify(buffer, (short)ISO7816.OFFSET_CDATA, (short)(32+2+coordx_size), buffer, offset_sig, sig_size);
- if (!verify)
- ISOException.throwIt(SW_SIGNATURE_INVALID);
- // save compression byte from coordy
- // if hash is 00...00, compbyte relates to master key
- byte compbyte= (byte)( (recvBuffer[(short)(1+coordx_size+coordy_size-1)]&0x01)+0x02);
- if (Util.arrayCompare(buffer, (short)(ISO7816.OFFSET_CDATA+32-BIP32_ANTICOLLISION_LENGTH), bip32_om.empty, (short)0, BIP32_ANTICOLLISION_LENGTH)==0){
- bip32_master_compbyte=compbyte;
- }
- else{
- short base=bip32_om.getBaseAddress(buffer, (short)(ISO7816.OFFSET_CDATA+32-BIP32_ANTICOLLISION_LENGTH));
- if (base==Bip32ObjectManager.NULL_OFFSET)
- ISOException.throwIt(SW_OBJECT_NOT_FOUND);
- bip32_om.setByte(base, (short)(BIP32_OBJECT_SIZE-1), compbyte);
- }
-
- short pos=0;
+ short pos=0;
Util.setShort(buffer, pos, bip32_om.nb_elem_free); // number of slot available
pos += (short) 2;
Util.setShort(buffer, pos, bip32_om.nb_elem_used); // number of slot used
pos += (short) 2;
- apdu.setOutgoingAndSend((short) 0, pos);
+ return pos;
}// end of setBIP32ExtendedPubkey
/**
@@ -1781,7 +1785,7 @@ private void setBIP32ExtendedPubkey(APDU apdu, byte[] buffer){
* return(finalize): [sig]
*
*/
- private void signMessage(APDU apdu, byte[] buffer){
+ private short signMessage(APDU apdu, byte[] buffer){
// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
ISOException.throwIt(SW_UNAUTHORIZED);
@@ -1794,8 +1798,6 @@ private void signMessage(APDU apdu, byte[] buffer){
if (p2 <= (byte) 0x00 || p2 > (byte) 0x03)
ISOException.throwIt(SW_INCORRECT_P2);
short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
- if (bytesLeft != apdu.setIncomingAndReceive())
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
// check whether the seed is initialized
if (key_nb==(byte)0xFF && !bip32_seeded)
@@ -1819,7 +1821,7 @@ else if (bytesLeft==(short)4){
offset+=4;
byte altcoinSize= buffer[offset];
offset++;
- if (bytesLeft!=(5+altcoinSize))
+ if (bytesLeft!=(short)(5+altcoinSize))
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
recvBuffer[0]= (byte) (altcoinSize+17);
Util.arrayCopyNonAtomic(buffer, offset, recvBuffer, (short)1, (short)altcoinSize);
@@ -1834,7 +1836,7 @@ else if (bytesLeft==(short)4){
sha256.reset();
sha256.update(recvBuffer, (short) 0, recvOffset);
sign_flag= true; // set flag
- break;
+ return (short)0;
// update (optionnal)
case OP_PROCESS:
@@ -1846,7 +1848,7 @@ else if (bytesLeft==(short)4){
chunk_size=Util.getShort(buffer, offset);
offset+=2;
sha256.update(buffer, (short) offset, chunk_size);
- break;
+ return (short)0;
// final
case OP_FINALIZE:
@@ -1889,12 +1891,16 @@ else if (bytesLeft==(short)4){
sigECDSA.init(key, Signature.MODE_SIGN);
}
short sign_size= sigECDSA.sign(recvBuffer, (short)0, (short)32, buffer, (short)0);
- apdu.setOutgoingAndSend((short) 0, sign_size);
- break;
- }
+ return sign_size;
+
+ } //end switch
+
+ return (short)0;
}
/**
+ * DEPRECATED - the generic signMessage() should be used instead!
+ *
* This function signs short Bitcoin message using std or Bip32 extended key in 1 APDU
*
* ins: 0x72
@@ -1905,71 +1911,69 @@ else if (bytesLeft==(short)4){
* return: [sig]
*
*/
- private void signShortMessage(APDU apdu, byte[] buffer){
- // check that PIN[0] has been entered previously
- if (!pins[0].isValidated())
- ISOException.throwIt(SW_UNAUTHORIZED);
-
- byte key_nb = buffer[ISO7816.OFFSET_P1];
- if ( (key_nb!=(byte)0xFF) && ((key_nb < 0)||(key_nb >= MAX_NUM_KEYS)) ) // debug!!
- ISOException.throwIt(SW_INCORRECT_P1);
- if (buffer[ISO7816.OFFSET_P2] != (byte) 0x00)
- ISOException.throwIt(SW_INCORRECT_P2);
- short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
- if (bytesLeft != apdu.setIncomingAndReceive())
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
-
- // check whether the seed is initialized
- if (key_nb==(byte)0xFF && !bip32_seeded)
- ISOException.throwIt(SW_BIP32_UNINITIALIZED_SEED);
-
- // copy message header to tmp buffer
- Util.arrayCopyNonAtomic(BITCOIN_SIGNED_MESSAGE_HEADER, (short)0, recvBuffer, (short)0, (short)BITCOIN_SIGNED_MESSAGE_HEADER.length);
- short recvOffset= (short)BITCOIN_SIGNED_MESSAGE_HEADER.length;
-
- // buffer data = [2-byte size | n-byte message to sign]
- short offset= (short)ISO7816.OFFSET_CDATA;
- short msgSize= Util.getShort(buffer, offset);
- recvOffset+= Biginteger.encodeShortToVarInt(msgSize, recvBuffer, recvOffset);
- offset+=2;
- bytesLeft-=2;
- Util.arrayCopyNonAtomic(buffer, offset, recvBuffer, recvOffset, msgSize);
- offset+= msgSize;
- recvOffset+= msgSize;
- bytesLeft-= msgSize;
-
- // hash SHA-256
- sha256.reset();
- sha256.doFinal(recvBuffer, (short) 0, recvOffset, recvBuffer, (short) 0);
-
- // check 2FA if required
- if(needs_2FA){
- if (bytesLeft<(short)20)
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
- // hmac of 64-bytes msg: (sha256(btcheader+msg) | 32bytes 0xBB-padding)
- Util.arrayFillNonAtomic(recvBuffer, (short)32, (short)32, (byte)0xBB);
- HmacSha160.computeHmacSha160(data2FA, OFFSET_2FA_HMACKEY, (short)20, recvBuffer, (short)0, (short)64, recvBuffer, (short)64);
- if (Util.arrayCompare(buffer, offset, recvBuffer, (short)64, (short)20)!=0)
- ISOException.throwIt(SW_SIGNATURE_INVALID);
- }
-
- // set key & sign
- if (key_nb==(byte)0xFF)
- sigECDSA.init(bip32_extendedkey, Signature.MODE_SIGN);
- else{
- Key key= eckeys[key_nb];
- // check type and size
- if ((key == null) || !key.isInitialized())
- ISOException.throwIt(SW_INCORRECT_P1);
- if (key.getType() != KeyBuilder.TYPE_EC_FP_PRIVATE)
- ISOException.throwIt(SW_INCORRECT_ALG);
- if (key.getSize()!= LENGTH_EC_FP_256)
- ISOException.throwIt(SW_INCORRECT_ALG);
- sigECDSA.init(key, Signature.MODE_SIGN);
- }
- short sign_size= sigECDSA.sign(recvBuffer, (short)0, (short)32, buffer, (short)0);
- apdu.setOutgoingAndSend((short) 0, sign_size);
- }
+// private short signShortMessage(APDU apdu, byte[] buffer){
+// // check that PIN[0] has been entered previously
+// if (!pins[0].isValidated())
+// ISOException.throwIt(SW_UNAUTHORIZED);
+//
+// byte key_nb = buffer[ISO7816.OFFSET_P1];
+// if ( (key_nb!=(byte)0xFF) && ((key_nb < 0)||(key_nb >= MAX_NUM_KEYS)) )
+// ISOException.throwIt(SW_INCORRECT_P1);
+// if (buffer[ISO7816.OFFSET_P2] != (byte) 0x00)
+// ISOException.throwIt(SW_INCORRECT_P2);
+// short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
+//
+// // check whether the seed is initialized
+// if (key_nb==(byte)0xFF && !bip32_seeded)
+// ISOException.throwIt(SW_BIP32_UNINITIALIZED_SEED);
+//
+// // copy message header to tmp buffer
+// Util.arrayCopyNonAtomic(BITCOIN_SIGNED_MESSAGE_HEADER, (short)0, recvBuffer, (short)0, (short)BITCOIN_SIGNED_MESSAGE_HEADER.length);
+// short recvOffset= (short)BITCOIN_SIGNED_MESSAGE_HEADER.length;
+//
+// // buffer data = [2-byte size | n-byte message to sign]
+// short offset= (short)ISO7816.OFFSET_CDATA;
+// short msgSize= Util.getShort(buffer, offset);
+// recvOffset+= Biginteger.encodeShortToVarInt(msgSize, recvBuffer, recvOffset);
+// offset+=2;
+// bytesLeft-=2;
+// Util.arrayCopyNonAtomic(buffer, offset, recvBuffer, recvOffset, msgSize);
+// offset+= msgSize;
+// recvOffset+= msgSize;
+// bytesLeft-= msgSize;
+//
+// // hash SHA-256
+// sha256.reset();
+// sha256.doFinal(recvBuffer, (short) 0, recvOffset, recvBuffer, (short) 0);
+//
+// // check 2FA if required
+// if(needs_2FA){
+// if (bytesLeft<(short)20)
+// ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
+// // hmac of 64-bytes msg: (sha256(btcheader+msg) | 32bytes 0xBB-padding)
+// Util.arrayFillNonAtomic(recvBuffer, (short)32, (short)32, (byte)0xBB);
+// HmacSha160.computeHmacSha160(data2FA, OFFSET_2FA_HMACKEY, (short)20, recvBuffer, (short)0, (short)64, recvBuffer, (short)64);
+// if (Util.arrayCompare(buffer, offset, recvBuffer, (short)64, (short)20)!=0)
+// ISOException.throwIt(SW_SIGNATURE_INVALID);
+// }
+//
+// // set key & sign
+// if (key_nb==(byte)0xFF)
+// sigECDSA.init(bip32_extendedkey, Signature.MODE_SIGN);
+// else{
+// Key key= eckeys[key_nb];
+// // check type and size
+// if ((key == null) || !key.isInitialized())
+// ISOException.throwIt(SW_INCORRECT_P1);
+// if (key.getType() != KeyBuilder.TYPE_EC_FP_PRIVATE)
+// ISOException.throwIt(SW_INCORRECT_ALG);
+// if (key.getSize()!= LENGTH_EC_FP_256)
+// ISOException.throwIt(SW_INCORRECT_ALG);
+// sigECDSA.init(key, Signature.MODE_SIGN);
+// }
+// short sign_size= sigECDSA.sign(recvBuffer, (short)0, (short)32, buffer, (short)0);
+// return sign_size;
+// }
/**
* This function parses a raw transaction and returns the corresponding double SHA-256
@@ -1985,7 +1989,7 @@ private void signShortMessage(APDU apdu, byte[] buffer){
* where:
* needs_confirm is 0x01 if a hmac-sha1 of the hash must be provided for tx signing
*/
- private void ParseTransaction(APDU apdu, byte[] buffer){
+ private short ParseTransaction(APDU apdu, byte[] buffer){
// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
ISOException.throwIt(SW_UNAUTHORIZED);
@@ -2044,8 +2048,7 @@ else if (result == Transaction.RESULT_MORE) {
// offset+=2;
// }
- apdu.setOutgoingAndSend((short)0, offset);
- return;
+ return offset;
}
else if (result == Transaction.RESULT_FINISHED) {
@@ -2115,10 +2118,10 @@ else if (result == Transaction.RESULT_FINISHED) {
// buffer= [tx_hash(32) | sign_size(2) | signature | tx context(20 - 46)] //deprecated
// buffer= [(hash_size+2)(2b) | tx_hash(32b) | need2fa(2b) | sig_size(2b) | sig(sig_size) | txcontext]
Transaction.resetTransaction();
- apdu.setOutgoingAndSend((short)0, offset);
+ return offset;
}
- return;
+ return 0; //should not happen!
}
/**
@@ -2135,7 +2138,7 @@ else if (result == Transaction.RESULT_FINISHED) {
* return: [sig ]
*
*/
- private void SignTransaction(APDU apdu, byte[] buffer){
+ private short SignTransaction(APDU apdu, byte[] buffer){
// check that PIN[0] has been entered previously
if (!pins[0].isValidated())
ISOException.throwIt(SW_UNAUTHORIZED);
@@ -2145,8 +2148,6 @@ private void SignTransaction(APDU apdu, byte[] buffer){
ISOException.throwIt(SW_INCORRECT_P1);
short bytesLeft = Util.makeShort((byte) 0x00, buffer[ISO7816.OFFSET_LC]);
- if (bytesLeft != apdu.setIncomingAndReceive())
- ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
if (bytesLeft.
- *
- */
-package org.satochip.applet;
-
-import javacard.framework.Util;
-import javacard.security.KeyBuilder;
-import javacard.security.RSAPublicKey;
-import javacard.security.RandomData;
-import javacardx.crypto.Cipher;
-
-public class EccComputation {
-
- private static final short EXP2=0;
- private static final short EXP3=1;
- private static final short EXP4=2;
- private static final short EXP6=3;
- private static final short EXP8=4;
- private static final short EXP12=5;
- private static final short EXP16=6;
- private static final short EXP24=7;
- private static final short EXP32=8;
- private static final short EXP48=9;
- private static final short EXP96=10;
- private static final short DECR=11;
-
- // Q decomposition: divide by a factor of 96 (2^5*3) or decrement then repeat
- private final static byte[] QDECOMP={
- EXP4, DECR, EXP2, DECR, EXP32, DECR, EXP2, DECR,
- EXP2, DECR, EXP2, DECR, EXP2, DECR, EXP2, DECR,
- EXP2, DECR, EXP2, DECR, EXP2, DECR, EXP2, DECR,
- EXP2, DECR, EXP2, DECR, EXP2, DECR, EXP2, DECR,
- EXP2, DECR, EXP2, DECR, EXP2, DECR, EXP2, DECR,
- EXP2, DECR, EXP2, DECR, EXP2, DECR, EXP2, DECR,
- EXP4, DECR, EXP6, EXP3, DECR, EXP6, DECR, EXP96,
- DECR, EXP6, EXP3, DECR, EXP2, DECR, EXP2, DECR,
- EXP2, DECR, EXP4, DECR, EXP48, DECR, EXP6, DECR,
- EXP8, DECR, EXP2, DECR, EXP2, DECR, EXP2, DECR,
- EXP2, DECR, EXP4, DECR, EXP6, DECR, EXP16, DECR,
- EXP6, DECR, EXP2, DECR, EXP2, DECR, EXP4, DECR,
- EXP6, EXP3, EXP3, DECR, EXP24, DECR, EXP2, DECR,
- EXP4, DECR, EXP6, EXP3, DECR, EXP6, DECR, EXP16,
- DECR, EXP48, DECR, EXP6, EXP3, EXP3, DECR, EXP2,
- DECR, EXP2, DECR, EXP2, DECR, EXP4, DECR, EXP6,
- EXP3, DECR, EXP6, EXP3, DECR, EXP12, DECR, EXP2,
- DECR, EXP4, DECR, EXP24, EXP3, DECR, EXP2, DECR,
- EXP8, DECR, EXP8, DECR, EXP8, DECR, EXP2, DECR,
- EXP2, DECR, EXP2, DECR, EXP32, EXP8, DECR, EXP6,
- DECR, EXP96, DECR, EXP12, EXP3, DECR, EXP12, DECR,
- EXP4, DECR, EXP6, DECR, EXP6, DECR, EXP6, EXP3,
- EXP3, DECR, EXP6, DECR, EXP48, DECR, EXP12, EXP3,
- EXP3, EXP3, DECR, EXP4, DECR, EXP6, EXP3, EXP3,
- DECR, EXP32, EXP8, DECR, EXP6, DECR, EXP2, DECR,
- EXP2, DECR, EXP2, DECR, EXP16, DECR, EXP6, DECR,
- EXP12, DECR, EXP2, DECR, EXP2, DECR, EXP2, DECR,
- EXP4, DECR, EXP12, DECR
- };
-
- private final static byte[] EXP={
- (byte)2, (byte)3, (byte)4, (byte)6,
- (byte)8, (byte)12, (byte)16, (byte)24,
- (byte)32, (byte)48, (byte)96};
-
- private final static short[] EXPOFF={
- (short)48, (short)64, (short)72, (short)80,
- (short)84, (short)88, (short)90, (short)92,
- (short)93, (short)94, (short)95};
-
- private final static byte[] SECP256K1_P =
- {(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,
- (byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF, (byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
- (byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFE, (byte)0xFF,(byte)0xFF,(byte)0xFC,(byte)0x2F};
-
- // q= (p+1)/4
-// private final static byte[] Q=
-// {(byte)0x3f,(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,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
-// (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xbf,(byte)0xff,(byte)0xff,(byte)0x0c};
-
- private static byte[] tmpBuffer;
- private static final short REG0=(short)0;
- private static final short REG1=(short)128;
- private static final short REG2=(short)160;
- private static final short REG3=(short)192;
- private static final short REG4=(short)224;
- //private static final short REG5=(short)256;
- private static final short OPLENGTH=(short)32;
-
- private static RSAPublicKey rsa_PublicKey = null;
- private static Cipher m_encryptCipherRSA = null;
- public static final byte ALG_RSA_NOPAD = 12;
-
- public static void init(byte[] tmp){
- tmpBuffer=tmp;
-
- // Allocate objects if not allocated yet
- if (rsa_PublicKey == null) {
- rsa_PublicKey = (RSAPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC,KeyBuilder.LENGTH_RSA_1024,false);
- }
- if (m_encryptCipherRSA == null) {
- m_encryptCipherRSA = Cipher.getInstance(ALG_RSA_NOPAD, false);
- }
-
- // set SECP256K1_P*2^96
- Util.arrayFillNonAtomic(tmpBuffer, REG0, (short)128, (byte)0);
- Util.arrayCopyNonAtomic(SECP256K1_P, (short)0, tmpBuffer, REG0, (short)SECP256K1_P.length);
- rsa_PublicKey.setModulus(tmpBuffer, REG0, (short)128);
- }
-
-
- // uses REG3 & REG4
- public static void SqrtRootOpt(byte[] src, short srcOff, byte[] dst, short dstOff){ //, short ctrstop){
- // y^2 = z = x^3+7 (mod p)
- // y= sqrt(z)= z^((p+1)/4) (mod p)
-
- // z= x^3+7
- ModularExp32b(src, srcOff, tmpBuffer, REG4, EXP3);
- Util.arrayFillNonAtomic(tmpBuffer, REG2, OPLENGTH, (byte)0);
- tmpBuffer[(short)(REG2+31)]=(byte)7; //LSB
- if(Biginteger.add_carry(tmpBuffer, REG4, tmpBuffer, REG2, OPLENGTH)){
- Biginteger.subtract(tmpBuffer, REG4, SECP256K1_P, (short)0, OPLENGTH);
- }
-
- Util.arrayFillNonAtomic(tmpBuffer, REG3, OPLENGTH, (byte)0);
- tmpBuffer[(short)(REG3+31)]=(byte)1; //LSB
-
- for(short i=0; iBLOCKSIZE || key_length<0){
- ISOException.throwIt(SW_UNSUPPORTED_KEYSIZE); // don't accept keys bigger than block size
+ ISOException.throwIt(CardEdge.SW_HMAC_UNSUPPORTED_KEYSIZE); // don't accept keys bigger than block size
}
if (message_length>MAXMSGSIZE || message_length<0){
- ISOException.throwIt(SW_UNSUPPORTED_MSGSIZE);
+ ISOException.throwIt(CardEdge.SW_HMAC_UNSUPPORTED_MSGSIZE);
}
// compute inner hash
diff --git a/src/org/satochip/applet/HmacSha512.java b/src/org/satochip/applet/HmacSha512.java
index 4d8942a..c57b8fa 100644
--- a/src/org/satochip/applet/HmacSha512.java
+++ b/src/org/satochip/applet/HmacSha512.java
@@ -23,19 +23,25 @@
import javacard.framework.ISOException;
import javacard.framework.JCSystem;
import javacard.framework.Util;
+import javacard.security.CryptoException;
+import javacard.security.MessageDigest;
// very limited Hmac-SHA512 implementation
public class HmacSha512 {
public static final short BLOCKSIZE=128; // 128 bytes
public static final short HASHSIZE=64;
- private static final short SW_UNSUPPORTED_KEYSIZE = (short) 0x9c0E;
- private static final short SW_UNSUPPORTED_MSGSIZE = (short) 0x9c0F;
private static byte[] data;
+ private static MessageDigest sha512;
public static void init(byte[] tmp){
data= tmp;
+ try {
+ sha512 = MessageDigest.getInstance(MessageDigest.ALG_SHA_512, false);
+ } catch (CryptoException e) {
+ ISOException.throwIt(CardEdge.SW_UNSUPPORTED_FEATURE); // unsupported feature => use a more recent card!
+ }
}
public static short computeHmacSha512(byte[] key, short key_offset, short key_length,
@@ -43,10 +49,10 @@ public static short computeHmacSha512(byte[] key, short key_offset, short key_le
byte[] mac, short mac_offset){
if (key_length>BLOCKSIZE || key_length<0){
- ISOException.throwIt(SW_UNSUPPORTED_KEYSIZE); // don't accept keys bigger than block size
+ ISOException.throwIt(CardEdge.SW_HMAC_UNSUPPORTED_KEYSIZE); // don't accept keys bigger than block size
}
if (message_length>HASHSIZE || message_length<0){
- ISOException.throwIt(SW_UNSUPPORTED_MSGSIZE); // don't accept messsage bigger than block size (should be sufficient for BIP32)
+ ISOException.throwIt(CardEdge.SW_HMAC_UNSUPPORTED_MSGSIZE); // don't accept message bigger than block size (should be sufficient for BIP32)
}
// compute inner hash
@@ -55,9 +61,8 @@ public static short computeHmacSha512(byte[] key, short key_offset, short key_le
}
Util.arrayFillNonAtomic(data, key_length, (short)(BLOCKSIZE-key_length), (byte)0x36);
Util.arrayCopyNonAtomic(message, message_offset, data, BLOCKSIZE, message_length);
- //Sha512.reset();
- //Sha512.doFinal(data, (short)0, (short)(BLOCKSIZE+message_length), data, BLOCKSIZE); // copy hash result to data buffer!
- Sha512.resetUpdateDoFinal(data, (short)0, (short)(BLOCKSIZE+message_length), data, BLOCKSIZE); // copy hash result to data buffer!
+ sha512.reset();
+ sha512.doFinal(data, (short)0, (short)(BLOCKSIZE+message_length), data, BLOCKSIZE); // copy hash result to data buffer!
// compute outer hash
for (short i=0; i>15)&1); posy--; posx--; addx=hashState[posx]; addy=h_short[posy]; hashState[posx] = (short)(addx+addy+akku); akku= (short)(( ((addx&addy)|((addx|addy) & ~hashState[posx])) >>15)&1); posy--; posx--; addx=hashState[posx]; addy=h_short[posy]; hashState[posx] = (short)(addx+addy+akku); akku= (short)(( ((addx&addy)|((addx|addy) & ~hashState[posx])) >>15)&1); posy--; posx--; addx=hashState[posx]; addy=h_short[posy]; hashState[posx] = (short)(addx+addy+akku) ;
- }
-
-
- short remainingBytes= (short)(inLength-(short)128);
- Util.arrayCopyNonAtomic(inBuff, inOffset, buffer, bufferOff, remainingBytes);
- bufferLeft-=remainingBytes;
- bufferOff+=remainingBytes;
-
-
-
-
- buffer[bufferOff]=(byte)0x80;
- bufferLeft--;
- bufferOff++;
- Util.arrayFillNonAtomic(buffer, bufferOff, bufferLeft, (byte)0x00);
-
-
- buffer[(short)(buffer.length-2)]=(byte)(((short)(8*inLength)>>8)&0xff);
- buffer[(short)(buffer.length-1)]=(byte)((8*inLength) &0xff);
-
-
- for (short i=0; i<32; i++){
- h_short[i]=hashState[i];
- }
- CompressionFunction(h_short, (short)0, buffer, (short)0);
-
- for (short i=0; i<32; i+=4){
- akku = 0; posy = (short)((i)+3); posx = (short)((i)+3); addx=hashState[posx]; addy=h_short[posy]; hashState[posx] = (short)(addx+addy+akku); akku= (short)(( ((addx&addy)|((addx|addy) & ~hashState[posx])) >>15)&1); posy--; posx--; addx=hashState[posx]; addy=h_short[posy]; hashState[posx] = (short)(addx+addy+akku); akku= (short)(( ((addx&addy)|((addx|addy) & ~hashState[posx])) >>15)&1); posy--; posx--; addx=hashState[posx]; addy=h_short[posy]; hashState[posx] = (short)(addx+addy+akku); akku= (short)(( ((addx&addy)|((addx|addy) & ~hashState[posx])) >>15)&1); posy--; posx--; addx=hashState[posx]; addy=h_short[posy]; hashState[posx] = (short)(addx+addy+akku) ;
- }
-
-
- for (short i=0; i<32; i++){
- outBuff[outOffset]=(byte)((hashState[i]>>8)&0xff);
- outOffset++;
- outBuff[outOffset]=(byte)(hashState[i]&0xff);
- outOffset++;
- }
-
- return (short)64;
- }
-
- public static void CompressionFunction(short[] state, short stateOff, byte[] msgBlock, short msgOff){
-
-
- short off1, off2, off3;
- short regA0, regA1, regA2, regA3;
- short regB0, regB1, regB2, regB3;
- short tmpA0, tmpA1, tmpA2, tmpA3;
-
-
-
- for (short dstOff=0; dstOff<64; dstOff++){ w_short[dstOff]= Util.getShort(msgBlock, (short)((msgOff)+2*dstOff)); } ;
-
- short hOff=0, wOff=0;
- for (short round=0; round<80; round++){
-
-
- off1=(short)(((short)(wOff+56))%64); off2=(short)(((short)(wOff+36))%64); off3=(short)(((short)(wOff+4))%64); tmpA0 = w_short[off1]; tmpA1 = w_short[(short)(off1+1)]; tmpA2 = w_short[(short)(off1+2)]; tmpA3 = w_short[(short)(off1+3)]; regA0 = (short) ( ( (tmpA3 >>>3) & (short)8191 | ((short)(tmpA2 <<(13))) ) ^ ( (tmpA1 >>>13) & (short)7 | ((short)(tmpA0 <<(3))) ) ^ ((tmpA0 >>>6) & (short)1023) ); regA1 = (short) ( ( (tmpA0 >>>3) & (short)8191 | ((short)(tmpA3 <<(13))) ) ^ ( (tmpA2 >>>13) & (short)7 | ((short)(tmpA1 <<(3))) ) ^ ( (tmpA1 >>>6) & (short)1023 | ((short)(tmpA0 <<(10))) ) ); regA2 = (short) ( ( (tmpA1 >>>3) & (short)8191 | ((short)(tmpA0 <<(13))) ) ^ ( (tmpA3 >>>13) & (short)7 | ((short)(tmpA2 <<(3))) ) ^ ( (tmpA2 >>>6) & (short)1023 | ((short)(tmpA1 <<(10))) ) ); regA3 = (short) ( ( (tmpA2 >>>3) & (short)8191 | ((short)(tmpA1 <<(13))) ) ^ ( (tmpA0 >>>13) & (short)7 | ((short)(tmpA3 <<(3))) ) ^ ( (tmpA3 >>>6) & (short)1023 | ((short)(tmpA2 <<(10))) ) ) ; regB0 = w_short[off2]; regB1 = w_short[(short)(off2+1)]; regB2 =w_short[(short)(off2+2)]; regB3 =w_short[(short)(off2+3)]; tmpA0 = regA3 ; regA3 = (short)((regA3 )+(regB3 )); tmpA2 = (short)(( ((tmpA0 &(regB3 ))|((tmpA0 |(regB3 )) & ~(regA3 ))) >>15)&1); tmpA0 =regA2 ; regA2 = (short)((regA2 )+(regB2 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB2 ))|((tmpA0 |(regB2 )) & ~(regA2 ))) >>15)&1); tmpA0 =regA1 ; regA1 = (short)((regA1 )+(regB1 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB1 ))|((tmpA0 |(regB1 )) & ~(regA1 ))) >>15)&1); regA0 = (short)((regA0 )+(regB0 )+tmpA2 ) ; tmpA0 = w_short[off3]; tmpA1 = w_short[(short)(off3+1)]; tmpA2 = w_short[(short)(off3+2)]; tmpA3 = w_short[(short)(off3+3)]; regB0 = (short) ( ( (tmpA0 >>>1) & (short)32767 | ((short)(tmpA3 <<(15))) ) ^ ( (tmpA0 >>>8) & (short)255 | ((short)(tmpA3 <<(8))) ) ^ ((tmpA0 >>>7) & (short)511) ); regB1 = (short) ( ( (tmpA1 >>>1) & (short)32767 | ((short)(tmpA0 <<(15))) ) ^ ( (tmpA1 >>>8) & (short)255 | ((short)(tmpA0 <<(8))) ) ^ ( (tmpA1 >>>7) & (short)511 | ((short)(tmpA0 <<(9))) ) ); regB2 = (short) ( ( (tmpA2 >>>1) & (short)32767 | ((short)(tmpA1 <<(15))) ) ^ ( (tmpA2 >>>8) & (short)255 | ((short)(tmpA1 <<(8))) ) ^ ( (tmpA2 >>>7) & (short)511 | ((short)(tmpA1 <<(9))) ) ); regB3 = (short) ( ( (tmpA3 >>>1) & (short)32767 | ((short)(tmpA2 <<(15))) ) ^ ( (tmpA3 >>>8) & (short)255 | ((short)(tmpA2 <<(8))) ) ^ ( (tmpA3 >>>7) & (short)511 | ((short)(tmpA2 <<(9))) ) ) ; tmpA0 = regA3 ; regA3 = (short)((regA3 )+(regB3 )); tmpA2 = (short)(( ((tmpA0 &(regB3 ))|((tmpA0 |(regB3 )) & ~(regA3 ))) >>15)&1); tmpA0 =regA2 ; regA2 = (short)((regA2 )+(regB2 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB2 ))|((tmpA0 |(regB2 )) & ~(regA2 ))) >>15)&1); tmpA0 =regA1 ; regA1 = (short)((regA1 )+(regB1 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB1 ))|((tmpA0 |(regB1 )) & ~(regA1 ))) >>15)&1); regA0 = (short)((regA0 )+(regB0 )+tmpA2 ) ; regB0 = w_short[wOff]; regB1 = w_short[(short)(wOff+1)]; regB2 =w_short[(short)(wOff+2)]; regB3 =w_short[(short)(wOff+3)]; tmpA0 = regA3 ; regA3 = (short)((regA3 )+(regB3 )); tmpA2 = (short)(( ((tmpA0 &(regB3 ))|((tmpA0 |(regB3 )) & ~(regA3 ))) >>15)&1); tmpA0 =regA2 ; regA2 = (short)((regA2 )+(regB2 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB2 ))|((tmpA0 |(regB2 )) & ~(regA2 ))) >>15)&1); tmpA0 =regA1 ; regA1 = (short)((regA1 )+(regB1 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB1 ))|((tmpA0 |(regB1 )) & ~(regA1 ))) >>15)&1); regA0 = (short)((regA0 )+(regB0 )+tmpA2 ) ; regB0 = w_short[wOff]; regB1 = w_short[(short)(wOff+1)]; regB2 = w_short[(short)(wOff+2)]; regB3 = w_short[(short)(wOff+3)]; w_short[wOff]= regA0 ; w_short[(short)(wOff+1)]= regA1 ; w_short[(short)(wOff+2)]= regA2 ; w_short[(short)(wOff+3)]= regA3 ; wOff=(short)(((short)(wOff+4))%64) ;
-
-
- off1= (short)(((short)(hOff+28))%32);
- off2= (short)(4*(round));
- tmpA0 =state[(short)((off1)+3)]; tmpA1 =K_SHORT[(short)((off2)+3)]; regA3 = (short)(tmpA0 +tmpA1 ); tmpA2 = (short)(( ((tmpA0 &tmpA1 )|((tmpA0 |tmpA1 ) & ~regA3 )) >>15)&1); tmpA0 =state[(short)((off1)+2)]; tmpA1 =K_SHORT[(short)((off2)+2)]; regA2 = (short)(tmpA0 +tmpA1 +tmpA2 ); tmpA2 = (short)(( ((tmpA0 &tmpA1 )|((tmpA0 |tmpA1 ) & ~regA2 )) >>15)&1); tmpA0 =state[(short)((off1)+1)]; tmpA1 =K_SHORT[(short)((off2)+1)]; regA1 = (short)(tmpA0 +tmpA1 +tmpA2 ); tmpA2 = (short)(( ((tmpA0 &tmpA1 )|((tmpA0 |tmpA1 ) & ~regA1 )) >>15)&1); regA0 = (short)(state[(off1)]+K_SHORT[(off2)]+tmpA2 ); ;
-
-
- tmpA0 = regA3 ; regA3 = (short)((regA3 )+(regB3 )); tmpA2 = (short)(( ((tmpA0 &(regB3 ))|((tmpA0 |(regB3 )) & ~(regA3 ))) >>15)&1); tmpA0 =regA2 ; regA2 = (short)((regA2 )+(regB2 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB2 ))|((tmpA0 |(regB2 )) & ~(regA2 ))) >>15)&1); tmpA0 =regA1 ; regA1 = (short)((regA1 )+(regB1 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB1 ))|((tmpA0 |(regB1 )) & ~(regA1 ))) >>15)&1); regA0 = (short)((regA0 )+(regB0 )+tmpA2 ) ;
-
-
- off1=(short)(((short)(hOff+16))%32);
- off2=(short)(((short)(hOff+20))%32);
- off3=(short)(((short)(hOff+24))%32);
- tmpA0 = state[off1]; regB0 = (short) ((tmpA0 & state[off2]) ^ ((~tmpA0 ) & state[off3])); tmpA0 = state[(short)(off1+1)]; regB1 = (short) ((tmpA0 & state[(short)(off2+1)]) ^ ((~tmpA0 ) & state[(short)(off3+1)])); tmpA0 = state[(short)(off1+2)]; regB2 = (short) ((tmpA0 & state[(short)(off2+2)]) ^ ((~tmpA0 ) & state[(short)(off3+2)])); tmpA0 = state[(short)(off1+3)]; regB3 = (short) ((tmpA0 & state[(short)(off2+3)]) ^ ((~tmpA0 ) & state[(short)(off3+3)])); ;
-
-
- tmpA0 = regA3 ; regA3 = (short)((regA3 )+(regB3 )); tmpA2 = (short)(( ((tmpA0 &(regB3 ))|((tmpA0 |(regB3 )) & ~(regA3 ))) >>15)&1); tmpA0 =regA2 ; regA2 = (short)((regA2 )+(regB2 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB2 ))|((tmpA0 |(regB2 )) & ~(regA2 ))) >>15)&1); tmpA0 =regA1 ; regA1 = (short)((regA1 )+(regB1 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB1 ))|((tmpA0 |(regB1 )) & ~(regA1 ))) >>15)&1); regA0 = (short)((regA0 )+(regB0 )+tmpA2 ) ;
-
-
- off1=(short)(((short)(hOff+16))%32);
- tmpA0 = state[off1]; tmpA1 = state[(short)(off1+1)]; tmpA2 = state[(short)(off1+2)]; tmpA3 = state[(short)(off1+3)]; regB0 = (short) ( ( (tmpA0 >>>14) & (short)3 | ((short)(tmpA3 <<(2))) ) ^ ( (tmpA3 >>>2) & (short)16383 | ((short)(tmpA2 <<(14))) ) ^ ( (tmpA2 >>>9) & (short)127 | ((short)(tmpA1 <<(7))) ) ); regB1 = (short) ( ( (tmpA1 >>>14) & (short)3 | ((short)(tmpA0 <<(2))) ) ^ ( (tmpA0 >>>2) & (short)16383 | ((short)(tmpA3 <<(14))) ) ^ ( (tmpA3 >>>9) & (short)127 | ((short)(tmpA2 <<(7))) ) ); regB2 = (short) ( ( (tmpA2 >>>14) & (short)3 | ((short)(tmpA1 <<(2))) ) ^ ( (tmpA1 >>>2) & (short)16383 | ((short)(tmpA0 <<(14))) ) ^ ( (tmpA0 >>>9) & (short)127 | ((short)(tmpA3 <<(7))) ) ); regB3 = (short) ( ( (tmpA3 >>>14) & (short)3 | ((short)(tmpA2 <<(2))) ) ^ ( (tmpA2 >>>2) & (short)16383 | ((short)(tmpA1 <<(14))) ) ^ ( (tmpA1 >>>9) & (short)127 | ((short)(tmpA0 <<(7))) ) ) ;
-
-
- tmpA0 = regA3 ; regA3 = (short)((regA3 )+(regB3 )); tmpA2 = (short)(( ((tmpA0 &(regB3 ))|((tmpA0 |(regB3 )) & ~(regA3 ))) >>15)&1); tmpA0 =regA2 ; regA2 = (short)((regA2 )+(regB2 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB2 ))|((tmpA0 |(regB2 )) & ~(regA2 ))) >>15)&1); tmpA0 =regA1 ; regA1 = (short)((regA1 )+(regB1 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB1 ))|((tmpA0 |(regB1 )) & ~(regA1 ))) >>15)&1); regA0 = (short)((regA0 )+(regB0 )+tmpA2 ) ;
-
-
- off1= (short)(((short)(hOff+12))%32);
- tmpA0 =(short)((off1)+3); tmpA1 =state[tmpA0 ]; state[tmpA0 ] = (short)(tmpA1 +regA3 ); tmpA2 = (short)(( ((tmpA1 ®A3 )|((tmpA1 |regA3 ) & ~state[tmpA0 ])) >>15)&1); tmpA0 =(short)((off1)+2); tmpA1 =state[tmpA0 ]; state[tmpA0 ] = (short)(tmpA1 +regA2 +tmpA2 ); tmpA2 = (short)(( ((tmpA1 ®A2 )|((tmpA1 |regA2 ) & ~state[tmpA0 ])) >>15)&1); tmpA0 =(short)((off1)+1); tmpA1 =state[tmpA0 ]; state[tmpA0 ] = (short)(tmpA1 +regA1 +tmpA2 ); tmpA2 = (short)(( ((tmpA1 ®A1 )|((tmpA1 |regA1 ) & ~state[tmpA0 ])) >>15)&1); tmpA0 =(short)(off1); tmpA1 =state[tmpA0 ]; state[tmpA0 ] = (short)(tmpA1 +regA0 +tmpA2 );
-
-
-
- off1= (short)(((short)(hOff+4))%32);
- off2= (short)(((short)(hOff+8))%32);
- tmpA0 =state[hOff]; tmpA1 =state[off1]; tmpA2 =state[off2]; regB0 = (short) ((tmpA0 & tmpA1 ) ^ (tmpA0 & tmpA2 ) ^ (tmpA1 & tmpA2 )); tmpA0 =state[(short)(hOff+1)]; tmpA1 =state[(short)(off1+1)]; tmpA2 =state[(short)(off2+1)]; regB1 = (short) ((tmpA0 & tmpA1 ) ^ (tmpA0 & tmpA2 ) ^ (tmpA1 & tmpA2 )); tmpA0 =state[(short)(hOff+2)]; tmpA1 =state[(short)(off1+2)]; tmpA2 =state[(short)(off2+2)]; regB2 = (short) ((tmpA0 & tmpA1 ) ^ (tmpA0 & tmpA2 ) ^ (tmpA1 & tmpA2 )); tmpA0 =state[(short)(hOff+3)]; tmpA1 =state[(short)(off1+3)]; tmpA2 =state[(short)(off2+3)]; regB3 = (short) ((tmpA0 & tmpA1 ) ^ (tmpA0 & tmpA2 ) ^ (tmpA1 & tmpA2 ));
-
-
- tmpA0 = regA3 ; regA3 = (short)((regA3 )+(regB3 )); tmpA2 = (short)(( ((tmpA0 &(regB3 ))|((tmpA0 |(regB3 )) & ~(regA3 ))) >>15)&1); tmpA0 =regA2 ; regA2 = (short)((regA2 )+(regB2 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB2 ))|((tmpA0 |(regB2 )) & ~(regA2 ))) >>15)&1); tmpA0 =regA1 ; regA1 = (short)((regA1 )+(regB1 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB1 ))|((tmpA0 |(regB1 )) & ~(regA1 ))) >>15)&1); regA0 = (short)((regA0 )+(regB0 )+tmpA2 ) ;
-
-
- tmpA0 = state[hOff]; tmpA1 = state[(short)(hOff+1)]; tmpA2 = state[(short)(hOff+2)]; tmpA3 = state[(short)(hOff+3)]; regB0 = (short) ( ( (tmpA3 >>>12) & (short)15 | ((short)(tmpA2 <<(4))) ) ^ ( (tmpA2 >>>2) & (short)16383 | ((short)(tmpA1 <<(14))) ) ^ ( (tmpA2 >>>7) & (short)511 | ((short)(tmpA1 <<(9))) ) ); regB1 = (short) ( ( (tmpA0 >>>12) & (short)15 | ((short)(tmpA3 <<(4))) ) ^ ( (tmpA3 >>>2) & (short)16383 | ((short)(tmpA2 <<(14))) ) ^ ( (tmpA3 >>>7) & (short)511 | ((short)(tmpA2 <<(9))) ) ); regB2 = (short) ( ( (tmpA1 >>>12) & (short)15 | ((short)(tmpA0 <<(4))) ) ^ ( (tmpA0 >>>2) & (short)16383 | ((short)(tmpA3 <<(14))) ) ^ ( (tmpA0 >>>7) & (short)511 | ((short)(tmpA3 <<(9))) ) ); regB3 = (short) ( ( (tmpA2 >>>12) & (short)15 | ((short)(tmpA1 <<(4))) ) ^ ( (tmpA1 >>>2) & (short)16383 | ((short)(tmpA0 <<(14))) ) ^ ( (tmpA1 >>>7) & (short)511 | ((short)(tmpA0 <<(9))) ) ) ;
-
-
- tmpA0 = regA3 ; regA3 = (short)((regA3 )+(regB3 )); tmpA2 = (short)(( ((tmpA0 &(regB3 ))|((tmpA0 |(regB3 )) & ~(regA3 ))) >>15)&1); tmpA0 =regA2 ; regA2 = (short)((regA2 )+(regB2 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB2 ))|((tmpA0 |(regB2 )) & ~(regA2 ))) >>15)&1); tmpA0 =regA1 ; regA1 = (short)((regA1 )+(regB1 )+tmpA2 ); tmpA2 = (short)(( ((tmpA0 &(regB1 ))|((tmpA0 |(regB1 )) & ~(regA1 ))) >>15)&1); regA0 = (short)((regA0 )+(regB0 )+tmpA2 ) ;
-
-
- state[(short)(((short)(hOff+28))%32)]= regA0;
- state[(short)(((short)(hOff+29))%32)]= regA1;
- state[(short)(((short)(hOff+30))%32)]= regA2;
- state[(short)(((short)(hOff+31))%32)]= regA3;
-
-
- hOff= (short)(((short)(32+hOff-4))%32);
-
- }
- }
-}
diff --git a/src/org/satochip/applet/Sha512.javap b/src/org/satochip/applet/Sha512.javap
deleted file mode 100644
index aab25f2..0000000
--- a/src/org/satochip/applet/Sha512.javap
+++ /dev/null
@@ -1,839 +0,0 @@
-package org.satochip.applet;
-
-import javacard.framework.JCSystem;
-import javacard.framework.Util;
-
-// build the java file using a C preprocessor such as mcpp (http://mcpp.sourceforge.net/)
-// build command: mcpp Sha512.javap Sha512.java -P
-
-#define add_carry(x, offsetx, y, offsety)\
- akku = 0;\
- posy = (short)((offsety)+3);\
- posx = (short)((offsetx)+3);\
- addx=x[posx]; addy=y[posy];\
- x[posx] = (short)(addx+addy+akku);\
- akku= (short)(( ((addx&addy)|((addx|addy) & ~x[posx])) >>15)&1);\
- posy--; posx--;\
- addx=x[posx]; addy=y[posy];\
- x[posx] = (short)(addx+addy+akku);\
- akku= (short)(( ((addx&addy)|((addx|addy) & ~x[posx])) >>15)&1);\
- posy--; posx--;\
- addx=x[posx]; addy=y[posy];\
- x[posx] = (short)(addx+addy+akku);\
- akku= (short)(( ((addx&addy)|((addx|addy) & ~x[posx])) >>15)&1);\
- posy--; posx--;\
- addx=x[posx]; addy=y[posy];\
- x[posx] = (short)(addx+addy+akku)
-
-#define Rotnb(src, srcOffset, dst, dstOffset, rightShifts, mask)\
- leftShifts = (short)(16-rightShifts);\
- dst[dstOffset]= (short) (((src[srcOffset]>>rightShifts)&mask) | (src[(short)(srcOffset+3)]<>rightShifts)&mask) | (src[srcOffset]<>rightShifts)&mask) | (src[(short)(srcOffset+1)]<>rightShifts)&mask) | (src[(short)(srcOffset+2)]<>rightShifts)&mask) | (src[(short)(srcOffset+3)]<>rightShifts)&mask) | (src[srcOffset]<>rightShifts)&mask) | (src[(short)(srcOffset+1)]<>rightShifts)&mask) | (src[(short)(srcOffset+2)]<>rightShifts)&mask) | (src[(short)(srcOffset+3)]<>rightShifts)&mask) | (src[srcOffset]<>rightShifts)&mask) | (src[(short)(srcOffset+1)]<>rightShifts)&mask) | (src[(short)(srcOffset+2)]<>rightShifts)&mask) | (src[(short)(srcOffset+3)]<>rightShifts)&mask) | (src[srcOffset]<>rightShifts)&mask) | (src[(short)(srcOffset+1)]<>rightShifts)&mask) | (src[(short)(srcOffset+2)]<>rightShifts)&mask);\
- dst[(short)(dstOffset+1)]= (short) (((src[(short)(srcOffset+1)]>>rightShifts)&mask) | (src[srcOffset]<>rightShifts)&mask) | (src[(short)(srcOffset+1)]<>rightShifts)&mask) | (src[(short)(srcOffset+2)]<>8)&0xff);
- dataSize[7]=(byte)((8*inLength) &0xff);
- add_carry_byte(dataSize, MSGSIZE, dataSize, CHUNKSIZE, (short)4);
-
- // perform function compression on complete 1024 blocks
- while (inLength>=bufferLeft){
-
- // fulfill buffer
- //System.arraycopy(inBuff, inOffset, buffer, bufferOff, bufferLeft);
- Util.arrayCopyNonAtomic(inBuff, inOffset, buffer, bufferOff, bufferLeft);
- inOffset+=bufferLeft;
- inLength-=bufferLeft;
- bufferLeft=128;
- bufferOff=0;
-
- // apply compression function
- for (short i=0; i<32; i++){
- h_short[i]=hashState[i];
- }
- CompressionFunction(h_short, (short)0, buffer, (short)0);
-
- //add result back in hashState
- for (short i=0; i<32; i+=4){
- add_carry(hashState, (short)i, h_short, (short)i);
- }
-
- }
- // at this point, bufferLeft>inLength
-
- // save remaining msg in buffer
- Util.arrayCopyNonAtomic(inBuff, inOffset, buffer, bufferOff, inLength);
- inOffset+=inLength;
- bufferLeft-=inLength;
- bufferOff+=inLength;
- }
- */
-
- /*
- public static short doFinal(byte[] inBuff, short inOffset, short inLength, byte[] outBuff, short outOffset){
-
- // for additions
- short akku,posy,posx,addx,addy;
-
- // perform update first
- update(inBuff, inOffset, inLength);
-
- // padd remaining bytes in the buffer
- buffer[bufferOff]=(byte)0x80;
- bufferLeft--;
- bufferOff++;
- Util.arrayFillNonAtomic(buffer, bufferOff, bufferLeft, (byte)0x00);
-
- if (bufferLeft<16){ // needs an additional block
- // apply compression function
- for (short i=0; i<32; i++){
- h_short[i]=hashState[i];
- }
- CompressionFunction(h_short, (short)0, buffer, (short)0);
- //add result back in hashState
- for (short i=0; i<32; i+=4){
- add_carry(hashState, (short)i, h_short, (short)i);
- }
- // reset buffer
- bufferOff=0;
- bufferLeft=128;
- Util.arrayFillNonAtomic(buffer, bufferOff, bufferLeft, (byte)0x00);
- }
- // message size (in bits)
- Util.arrayCopyNonAtomic(dataSize, MSGSIZE, buffer, (short)(buffer.length-4), (short)4);
-
- // apply compression function on last block
- for (short i=0; i<32; i++){
- h_short[i]=hashState[i];
- }
- CompressionFunction(h_short, (short)0, buffer, (short)0);
- //add result back in hashState
- for (short i=0; i<32; i+=4){
- add_carry(hashState, (short)i, h_short, (short)i);
- }
-
- // copy final state back and reset
- for (short i=0; i<32; i++){
- outBuff[outOffset]=(byte)((hashState[i]>>8)&0xff);
- outOffset++;
- outBuff[outOffset]=(byte)(hashState[i]&0xff);
- outOffset++;
- }
- reset();
-
- return (short)64;
- }
- */
-
- // simplified method to hash exactly 2 blocks, i.e. >128 bytes and <=240 bytes, as required for Bip32
- public static short resetUpdateDoFinal(byte[] inBuff, short inOffset, short inLength, byte[] outBuff, short outOffset){
-
- // variable declaration for inline additions
- short akku,posy,posx,addx,addy;
-
- /* Reset */
- bufferOff=0;
- bufferLeft=128;
-
- /* Update */
-
- // perform function compression on first (complete) 1024 blocks
- // fulfil buffer
- Util.arrayCopyNonAtomic(inBuff, inOffset, buffer, bufferOff, bufferLeft);
- inOffset+=bufferLeft;
- bufferLeft=128;
- bufferOff=0;
-
- // apply compression function
- for (short i=0; i<32; i++){
- hashState[i]= H_INIT_SHORT[i];
- h_short[i]=hashState[i];
- }
- CompressionFunction(h_short, (short)0, buffer, (short)0);
- //add result back in hashState
- for (short i=0; i<32; i+=4){
- add_carry(hashState, i, h_short, i);
- }
-
- // save remaining msg in buffer
- short remainingBytes= (short)(inLength-(short)128);
- Util.arrayCopyNonAtomic(inBuff, inOffset, buffer, bufferOff, remainingBytes);
- bufferLeft-=remainingBytes;
- bufferOff+=remainingBytes;
-
- /* DoFinal */
-
- // pad remaining bytes in the buffer
- buffer[bufferOff]=(byte)0x80;
- bufferLeft--;
- bufferOff++;
- Util.arrayFillNonAtomic(buffer, bufferOff, bufferLeft, (byte)0x00);
-
- // message size (in bits)
- buffer[(short)(buffer.length-2)]=(byte)(((short)(8*inLength)>>8)&0xff);
- buffer[(short)(buffer.length-1)]=(byte)((8*inLength) &0xff);
-
- // apply compression function on last block
- for (short i=0; i<32; i++){
- h_short[i]=hashState[i];
- }
- CompressionFunction(h_short, (short)0, buffer, (short)0);
- //add result back in hashState
- for (short i=0; i<32; i+=4){
- add_carry(hashState, i, h_short, i);
- }
-
- // copy final state back
- for (short i=0; i<32; i++){
- outBuff[outOffset]=(byte)((hashState[i]>>8)&0xff);
- outOffset++;
- outBuff[outOffset]=(byte)(hashState[i]&0xff);
- outOffset++;
- }
-
- return (short)64;
- }
-
- public static void CompressionFunction(short[] state, short stateOff, byte[] msgBlock, short msgOff){
-
- // temporary value for inline method
- short akku,posy,posx,addx,addy; // used in add_carry
- short off1, off2, off3;
- short leftShifts; // used in E0, E1, Sig0, Sig1
-
- // stateOff => 32 short state (512 bits)
- // msgBlock => 128 byte data (1024 bits)
- InitW(msgBlock, msgOff);
-
- short hOff=0, wOff=0;
- for (short round=0; round<80; round++){
-
- // update W and get wCurrent
- //wOff=updateW(w_short, wOff, tmp, REG1);
- updateW(w_short, wOff, tmp, REG1);
-
- // get K
- getK(round, tmp, REG2);
-
- // reg1= K+wCurrent
- add_carry(tmp, REG1, tmp, REG2);
-
- // reg1= K+wCurrent+h
- off1= (short)(((short)(hOff+28))%32);
- add_carry(tmp, REG1, state, off1);
-
- // reg2= Ch(e,f,g)
- off1=(short)(((short)(hOff+16))%32);
- off2=(short)(((short)(hOff+20))%32);
- off3=(short)(((short)(hOff+24))%32);
- Ch(state, off1, state, off2, state, off3, tmp, REG2);
-
- // reg1= K+wCurrent+h+Ch(e,f,g)
- add_carry(tmp, REG1, tmp, REG2);
-
- // reg2= E1(e)
- off1=(short)(((short)(hOff+16))%32);
- E1_opt(state, off1, tmp, REG2);
-
- // reg1= K+wCurrent+Ch(e,f,g)+E1
- add_carry(tmp, REG1, tmp, REG2);
-
- // d= d+reg1
- off1= (short)(((short)(hOff+12))%32);
- add_carry(state, off1, tmp, REG1);
-
- // reg2= Maj(a,b,c)
- //Maj(state, hOff, state, (short)(((short)(hOff+4))%32), state, (short)(((short)(hOff+8))%32), tmp, REG2);
- off1= (short)(((short)(hOff+4))%32);
- off2= (short)(((short)(hOff+8))%32);
- Maj(state, hOff, state, off1, state, off2, tmp, REG2);
-
- // reg1= reg1+Maj(a,b,c)
- add_carry(tmp, REG1, tmp, REG2);
-
- // reg2= E0(a)
- E0_opt(state, hOff, tmp, REG2);
-
- // reg1= reg1+E0(a)
- add_carry(tmp, REG1, tmp, REG2);
-
- //update state(h) with reg1
- state[(short)(((short)(hOff+28))%32)]= tmp[8];
- state[(short)(((short)(hOff+29))%32)]= tmp[9];
- state[(short)(((short)(hOff+30))%32)]= tmp[10];
- state[(short)(((short)(hOff+31))%32)]= tmp[11];
-
- // update offset
- hOff= (short)(((short)(32+hOff-4))%32);
-
- }// end for
- }
-
- /*
- public static void getK(short round, short[] dst, short dstOff){
- dst[dstOff]=K_SHORT[(short)(4*round)];
- dst[(short)(dstOff+1)]=K_SHORT[(short)(4*round+1)];
- dst[(short)(dstOff+2)]=K_SHORT[(short)(4*round+2)];
- dst[(short)(dstOff+3)]=K_SHORT[(short)(4*round+3)];
- }
- */
-
- /*
- public static boolean add_carry_byte(byte[] x, short offsetx, byte[] y, short offsety, short size){
- short digit_mask = 0xff;
- short digit_len = 8;
- short akku = 0;
- short j = (short)(offsetx+size-1);
- for(short i = (short)(offsety+size-1); i >= offsety; i--, j--) {
- akku = (short)(akku + (x[j] & digit_mask) + (y[i] & digit_mask));
-
- x[j] = (byte)(akku & digit_mask);
- akku = (short)((akku >>> digit_len) & digit_mask);
- }
- return akku != 0;
- }
- */
-
- /**
- * ROTATION on short[4]
- * */
- /*
- public static void Rotnb(short[] src, short srcOffset, short[] dst, short dstOffset, short rightShifts){
- //0>rightShifts)&mask) | (src[(short)(srcOffset+3)]<>rightShifts)&mask) | (src[srcOffset]<>rightShifts)&mask) | (src[(short)(srcOffset+1)]<>rightShifts)&mask) | (src[(short)(srcOffset+2)]<>rightShifts)&mask) | (src[(short)(srcOffset+3)]<>rightShifts)&mask) | (src[srcOffset]<>rightShifts)&mask) | (src[(short)(srcOffset+1)]<>rightShifts)&mask) | (src[(short)(srcOffset+2)]<>rightShifts)&mask) | (src[(short)(srcOffset+3)]<>rightShifts)&mask) | (src[srcOffset]<>rightShifts)&mask) | (src[(short)(srcOffset+1)]<>rightShifts)&mask) | (src[(short)(srcOffset+2)]<>rightShifts)&mask) | (src[(short)(srcOffset+3)]<>rightShifts)&mask) | (src[srcOffset]<>rightShifts)&mask) | (src[(short)(srcOffset+1)]<>rightShifts)&mask) | (src[(short)(srcOffset+2)]<>rightShifts)&mask);
- dst[(short)(dstOffset+1)]= (short) (((src[(short)(srcOffset+1)]>>rightShifts)&mask) | (src[srcOffset]<>rightShifts)&mask) | (src[(short)(srcOffset+1)]<>rightShifts)&mask) | (src[(short)(srcOffset+2)]<>15)&1);\
- posy--; posx--;\
- addx=x[posx]; addy=y[posy];\
- x[posx] = (short)(addx+addy+akku);\
- akku= (short)(( ((addx&addy)|((addx|addy) & ~x[posx])) >>15)&1);\
- posy--; posx--;\
- addx=x[posx]; addy=y[posy];\
- x[posx] = (short)(addx+addy+akku);\
- akku= (short)(( ((addx&addy)|((addx|addy) & ~x[posx])) >>15)&1);\
- posy--; posx--;\
- addx=x[posx]; addy=y[posy];\
- x[posx] = (short)(addx+addy+akku)
-
-// add shorts and shorts back to first shorts
-#define add_carry_fast(x, y, tmp)\
- tmp##0= x##3;\
- x##3 = (short)((x##3)+(y##3));\
- tmp##2= (short)(( ((tmp##0&(y##3))|((tmp##0|(y##3)) & ~(x##3))) >>15)&1);\
- tmp##0=x##2;\
- x##2 = (short)((x##2)+(y##2)+tmp##2);\
- tmp##2= (short)(( ((tmp##0&(y##2))|((tmp##0|(y##2)) & ~(x##2))) >>15)&1);\
- tmp##0=x##1;\
- x##1 = (short)((x##1)+(y##1)+tmp##2);\
- tmp##2= (short)(( ((tmp##0&(y##1))|((tmp##0|(y##1)) & ~(x##1))) >>15)&1);\
- x##0 = (short)((x##0)+(y##0)+tmp##2)
-
-// add short-array and short-array to shorts
-#define add_carry_fast2(x, offsetx, y, offsety, dst, tmp)\
- tmp##0=x[(short)((offsetx)+3)];\
- tmp##1=y[(short)((offsety)+3)];\
- dst##3= (short)(tmp##0+tmp##1);\
- tmp##2= (short)(( ((tmp##0&tmp##1)|((tmp##0|tmp##1) & ~dst##3)) >>15)&1);\
- tmp##0=x[(short)((offsetx)+2)];\
- tmp##1=y[(short)((offsety)+2)];\
- dst##2= (short)(tmp##0+tmp##1+tmp##2);\
- tmp##2= (short)(( ((tmp##0&tmp##1)|((tmp##0|tmp##1) & ~dst##2)) >>15)&1);\
- tmp##0=x[(short)((offsetx)+1)];\
- tmp##1=y[(short)((offsety)+1)];\
- dst##1= (short)(tmp##0+tmp##1+tmp##2);\
- tmp##2= (short)(( ((tmp##0&tmp##1)|((tmp##0|tmp##1) & ~dst##1)) >>15)&1);\
- dst##0= (short)(x[(offsetx)]+y[(offsety)]+tmp##2);\
-
-// add short-array and shorts back to short-array
-#define add_carry_fast3(x, offsetx, y, tmp)\
- tmp##0=(short)((offsetx)+3);\
- tmp##1=x[tmp##0];\
- x[tmp##0] = (short)(tmp##1+y##3);\
- tmp##2= (short)(( ((tmp##1&y##3)|((tmp##1|y##3) & ~x[tmp##0])) >>15)&1);\
- tmp##0=(short)((offsetx)+2);\
- tmp##1=x[tmp##0];\
- x[tmp##0] = (short)(tmp##1+y##2+tmp##2);\
- tmp##2= (short)(( ((tmp##1&y##2)|((tmp##1|y##2) & ~x[tmp##0])) >>15)&1);\
- tmp##0=(short)((offsetx)+1);\
- tmp##1=x[tmp##0];\
- x[tmp##0] = (short)(tmp##1+y##1+tmp##2);\
- tmp##2= (short)(( ((tmp##1&y##1)|((tmp##1|y##1) & ~x[tmp##0])) >>15)&1);\
- tmp##0=(short)(offsetx);\
- tmp##1=x[tmp##0];\
- x[tmp##0] = (short)(tmp##1+y##0+tmp##2);\
-
-#define Ch_fast(x, xOff, y, yOff, z, zOff, dst, tmp)\
- tmp##0= x[xOff];\
- dst##0= (short) ((tmp##0 & y[yOff]) ^ ((~tmp##0) & z[zOff]));\
- tmp##0= x[(short)(xOff+1)];\
- dst##1= (short) ((tmp##0 & y[(short)(yOff+1)]) ^ ((~tmp##0) & z[(short)(zOff+1)]));\
- tmp##0= x[(short)(xOff+2)];\
- dst##2= (short) ((tmp##0 & y[(short)(yOff+2)]) ^ ((~tmp##0) & z[(short)(zOff+2)]));\
- tmp##0= x[(short)(xOff+3)];\
- dst##3= (short) ((tmp##0 & y[(short)(yOff+3)]) ^ ((~tmp##0) & z[(short)(zOff+3)]));
-
-#define Maj_fast(x, xOff, y, yOff, z, zOff, dst, tmp)\
- tmp##0=x[xOff];\
- tmp##1=y[yOff];\
- tmp##2=z[zOff];\
- dst##0= (short) ((tmp##0 & tmp##1) ^ (tmp##0 & tmp##2) ^ (tmp##1 & tmp##2));\
- tmp##0=x[(short)(xOff+1)];\
- tmp##1=y[(short)(yOff+1)];\
- tmp##2=z[(short)(zOff+1)];\
- dst##1= (short) ((tmp##0 & tmp##1) ^ (tmp##0 & tmp##2) ^ (tmp##1 & tmp##2));\
- tmp##0=x[(short)(xOff+2)];\
- tmp##1=y[(short)(yOff+2)];\
- tmp##2=z[(short)(zOff+2)];\
- dst##2= (short) ((tmp##0 & tmp##1) ^ (tmp##0 & tmp##2) ^ (tmp##1 & tmp##2));\
- tmp##0=x[(short)(xOff+3)];\
- tmp##1=y[(short)(yOff+3)];\
- tmp##2=z[(short)(zOff+3)];\
- dst##3= (short) ((tmp##0 & tmp##1) ^ (tmp##0 & tmp##2) ^ (tmp##1 & tmp##2));\
-
-/*
- Based on https://github.com/LedgerHQ/ledger-javacard/blob/master/src-preprocessed/com/ledger/wallet/SHA512.javap
- Unrolled versions of
-
- #define r0(h,l,n) \
- (short) \
- ( (h>>>n) & ~(((short)0xFFFF<<(16-n)) ) | \
- ((short)(l<<(16-n))) )
-*/
- #define r0_6(h,l) \
- ( (h>>>6) & (short)1023 | \
- ((short)(l<<(10))) )
-
-#define r0_7(h,l) \
- ( (h>>>7) & (short)511 | \
- ((short)(l<<(9))) )
-
-#define r0_3(h,l) \
- ( (h>>>3) & (short)8191 | \
- ((short)(l<<(13))) )
-
-#define r0_13(h,l) \
- ( (h>>>13) & (short)7 | \
- ((short)(l<<(3))) )
-
-#define r0_1(h,l) \
- ( (h>>>1) & (short)32767 | \
- ((short)(l<<(15))) )
-
-#define r0_8(h,l) \
- ( (h>>>8) & (short)255 | \
- ((short)(l<<(8))) )
-
-#define r0_14(h,l) \
- ( (h>>>14) & (short)3 | \
- ((short)(l<<(2))) )
-
-#define r0_2(h,l) \
- ( (h>>>2) & (short)16383 | \
- ((short)(l<<(14))) )
-
-#define r0_9(h,l) \
- ( (h>>>9) & (short)127 | \
- ((short)(l<<(7))) )
-
-#define r0_12(h,l) \
- ( (h>>>12) & (short)15 | \
- ((short)(l<<(4))) )
-
-/*
- Based on https://github.com/LedgerHQ/ledger-javacard/blob/master/src-preprocessed/com/ledger/wallet/SHA512.javap
- Unrolled versions of
-
- #define s0(h,n) \
- (short) \
- ((h>>>n) & ~(((short)0xFFFF<<(16-n)) ))
-*/
-
-#define s0_6(h) \
- ((h>>>6) & (short)1023)
-
-#define s0_7(h) \
- ((h>>>7) & (short)511)
-
-#define E0_fast(x, xOff, dst, tmp)\
- tmp##0= x[xOff];\
- tmp##1= x[(short)(xOff+1)];\
- tmp##2= x[(short)(xOff+2)];\
- tmp##3= x[(short)(xOff+3)];\
- dst##0= (short) (r0_12(tmp##3,tmp##2) ^ r0_2(tmp##2,tmp##1) ^ r0_7(tmp##2,tmp##1));\
- dst##1= (short) (r0_12(tmp##0,tmp##3) ^ r0_2(tmp##3,tmp##2) ^ r0_7(tmp##3,tmp##2));\
- dst##2= (short) (r0_12(tmp##1,tmp##0) ^ r0_2(tmp##0,tmp##3) ^ r0_7(tmp##0,tmp##3));\
- dst##3= (short) (r0_12(tmp##2,tmp##1) ^ r0_2(tmp##1,tmp##0) ^ r0_7(tmp##1,tmp##0))
-
-#define E1_fast(x, xOff, dst, tmp)\
- tmp##0= x[xOff];\
- tmp##1= x[(short)(xOff+1)];\
- tmp##2= x[(short)(xOff+2)];\
- tmp##3= x[(short)(xOff+3)];\
- dst##0= (short) (r0_14(tmp##0,tmp##3) ^ r0_2(tmp##3,tmp##2) ^ r0_9(tmp##2,tmp##1));\
- dst##1= (short) (r0_14(tmp##1,tmp##0) ^ r0_2(tmp##0,tmp##3) ^ r0_9(tmp##3,tmp##2));\
- dst##2= (short) (r0_14(tmp##2,tmp##1) ^ r0_2(tmp##1,tmp##0) ^ r0_9(tmp##0,tmp##3));\
- dst##3= (short) (r0_14(tmp##3,tmp##2) ^ r0_2(tmp##2,tmp##1) ^ r0_9(tmp##1,tmp##0))
-
-#define Sig0_fast(x, xOff, dst, tmp)\
- tmp##0= x[xOff];\
- tmp##1= x[(short)(xOff+1)];\
- tmp##2= x[(short)(xOff+2)];\
- tmp##3= x[(short)(xOff+3)];\
- dst##0= (short) (r0_1(tmp##0,tmp##3) ^ r0_8(tmp##0,tmp##3) ^ s0_7(tmp##0));\
- dst##1= (short) (r0_1(tmp##1,tmp##0) ^ r0_8(tmp##1,tmp##0) ^ r0_7(tmp##1,tmp##0));\
- dst##2= (short) (r0_1(tmp##2,tmp##1) ^ r0_8(tmp##2,tmp##1) ^ r0_7(tmp##2,tmp##1));\
- dst##3= (short) (r0_1(tmp##3,tmp##2) ^ r0_8(tmp##3,tmp##2) ^ r0_7(tmp##3,tmp##2))
-
-#define Sig1_fast(x, xOff, dst, tmp)\
- tmp##0= x[xOff];\
- tmp##1= x[(short)(xOff+1)];\
- tmp##2= x[(short)(xOff+2)];\
- tmp##3= x[(short)(xOff+3)];\
- dst##0= (short) (r0_3(tmp##3,tmp##2) ^ r0_13(tmp##1,tmp##0) ^ s0_6(tmp##0));\
- dst##1= (short) (r0_3(tmp##0,tmp##3) ^ r0_13(tmp##2,tmp##1) ^ r0_6(tmp##1,tmp##0));\
- dst##2= (short) (r0_3(tmp##1,tmp##0) ^ r0_13(tmp##3,tmp##2) ^ r0_6(tmp##2,tmp##1));\
- dst##3= (short) (r0_3(tmp##2,tmp##1) ^ r0_13(tmp##0,tmp##3) ^ r0_6(tmp##3,tmp##2))
-
-#define getK_fast(round, dst)\
- dst##0=K_SHORT[(short)(4*(round))];\
- dst##1=K_SHORT[(short)(4*(round)+1)];\
- dst##2=K_SHORT[(short)(4*(round)+2)];\
- dst##3=K_SHORT[(short)(4*(round)+3)]
-
-#define InitW(msgBlock, msgOff)\
- for (short dstOff=0; dstOff<64; dstOff++){\
- w_short[dstOff]= Util.getShort(msgBlock, (short)((msgOff)+2*dstOff));\
- }
-
-#define updateW_fast(w, wOff, dstcpy, dstnew, tmp)\
- off1=(short)(((short)(wOff+56))%64);\
- off2=(short)(((short)(wOff+36))%64);\
- off3=(short)(((short)(wOff+4))%64);\
- MessageSchedule_fast(w, off1, w, off2, w, off3, w, wOff, dstcpy, dstnew, tmp);\
- dstcpy##0= w[wOff];\
- dstcpy##1= w[(short)(wOff+1)];\
- dstcpy##2= w[(short)(wOff+2)];\
- dstcpy##3= w[(short)(wOff+3)];\
- w[wOff]= dstnew##0;\
- w[(short)(wOff+1)]= dstnew##1;\
- w[(short)(wOff+2)]= dstnew##2;\
- w[(short)(wOff+3)]= dstnew##3;\
- wOff=(short)(((short)(wOff+4))%64)
-
-// dstcpy is used as temporary variable and dstnew stores updated messageschedule value
-// values in w, x, y,z are left unchanged here
-#define MessageSchedule_fast(w, wOff, x, xOff, y, yOff, z, zOff, dstcpy, dstnew, tmp)\
- Sig1_fast(w, wOff, dstnew, tmp);\
- dstcpy##0= x[xOff]; dstcpy##1= x[(short)(xOff+1)]; dstcpy##2=x[(short)(xOff+2)]; dstcpy##3=x[(short)(xOff+3)];\
- add_carry_fast(dstnew, dstcpy, tmp);\
- Sig0_fast(y, yOff, dstcpy, tmp);\
- add_carry_fast(dstnew, dstcpy, tmp);\
- dstcpy##0= z[zOff]; dstcpy##1= z[(short)(zOff+1)]; dstcpy##2=z[(short)(zOff+2)]; dstcpy##3=z[(short)(zOff+3)];\
- add_carry_fast(dstnew, dstcpy, tmp)
-
-public class Sha512 {
-
- public static final short[] H_INIT_SHORT={
- (short) 0x6a09, (short) 0xe667, (short) 0xf3bc, (short) 0xc908,
- (short) 0xbb67, (short) 0xae85, (short) 0x84ca, (short) 0xa73b,
- (short) 0x3c6e, (short) 0xf372, (short) 0xfe94, (short) 0xf82b,
- (short) 0xa54f, (short) 0xf53a, (short) 0x5f1d, (short) 0x36f1,
- (short) 0x510e, (short) 0x527f, (short) 0xade6, (short) 0x82d1,
- (short) 0x9b05, (short) 0x688c, (short) 0x2b3e, (short) 0x6c1f,
- (short) 0x1f83, (short) 0xd9ab, (short) 0xfb41, (short) 0xbd6b,
- (short) 0x5be0, (short) 0xcd19, (short) 0x137e, (short) 0x2179
- };
-
- public static final short[] K_SHORT={
- (short) 0x428a,(short) 0x2f98,(short) 0xd728,(short) 0xae22,
- (short) 0x7137,(short) 0x4491,(short) 0x23ef,(short) 0x65cd,
- (short) 0xb5c0,(short) 0xfbcf,(short) 0xec4d,(short) 0x3b2f,
- (short) 0xe9b5,(short) 0xdba5,(short) 0x8189,(short) 0xdbbc,
- (short) 0x3956,(short) 0xc25b,(short) 0xf348,(short) 0xb538,
- (short) 0x59f1,(short) 0x11f1,(short) 0xb605,(short) 0xd019,
- (short) 0x923f,(short) 0x82a4,(short) 0xaf19,(short) 0x4f9b,
- (short) 0xab1c,(short) 0x5ed5,(short) 0xda6d,(short) 0x8118,
- (short) 0xd807,(short) 0xaa98,(short) 0xa303,(short) 0x0242,
- (short) 0x1283,(short) 0x5b01,(short) 0x4570,(short) 0x6fbe,
- (short) 0x2431,(short) 0x85be,(short) 0x4ee4,(short) 0xb28c,
- (short) 0x550c,(short) 0x7dc3,(short) 0xd5ff,(short) 0xb4e2,
- (short) 0x72be,(short) 0x5d74,(short) 0xf27b,(short) 0x896f,
- (short) 0x80de,(short) 0xb1fe,(short) 0x3b16,(short) 0x96b1,
- (short) 0x9bdc,(short) 0x06a7,(short) 0x25c7,(short) 0x1235,
- (short) 0xc19b,(short) 0xf174,(short) 0xcf69,(short) 0x2694,
- (short) 0xe49b,(short) 0x69c1,(short) 0x9ef1,(short) 0x4ad2,
- (short) 0xefbe,(short) 0x4786,(short) 0x384f,(short) 0x25e3,
- (short) 0x0fc1,(short) 0x9dc6,(short) 0x8b8c,(short) 0xd5b5,
- (short) 0x240c,(short) 0xa1cc,(short) 0x77ac,(short) 0x9c65,
- (short) 0x2de9,(short) 0x2c6f,(short) 0x592b,(short) 0x0275,
- (short) 0x4a74,(short) 0x84aa,(short) 0x6ea6,(short) 0xe483,
- (short) 0x5cb0,(short) 0xa9dc,(short) 0xbd41,(short) 0xfbd4,
- (short) 0x76f9,(short) 0x88da,(short) 0x8311,(short) 0x53b5,
- (short) 0x983e,(short) 0x5152,(short) 0xee66,(short) 0xdfab,
- (short) 0xa831,(short) 0xc66d,(short) 0x2db4,(short) 0x3210,
- (short) 0xb003,(short) 0x27c8,(short) 0x98fb,(short) 0x213f,
- (short) 0xbf59,(short) 0x7fc7,(short) 0xbeef,(short) 0x0ee4,
- (short) 0xc6e0,(short) 0x0bf3,(short) 0x3da8,(short) 0x8fc2,
- (short) 0xd5a7,(short) 0x9147,(short) 0x930a,(short) 0xa725,
- (short) 0x06ca,(short) 0x6351,(short) 0xe003,(short) 0x826f,
- (short) 0x1429,(short) 0x2967,(short) 0x0a0e,(short) 0x6e70,
- (short) 0x27b7,(short) 0x0a85,(short) 0x46d2,(short) 0x2ffc,
- (short) 0x2e1b,(short) 0x2138,(short) 0x5c26,(short) 0xc926,
- (short) 0x4d2c,(short) 0x6dfc,(short) 0x5ac4,(short) 0x2aed,
- (short) 0x5338,(short) 0x0d13,(short) 0x9d95,(short) 0xb3df,
- (short) 0x650a,(short) 0x7354,(short) 0x8baf,(short) 0x63de,
- (short) 0x766a,(short) 0x0abb,(short) 0x3c77,(short) 0xb2a8,
- (short) 0x81c2,(short) 0xc92e,(short) 0x47ed,(short) 0xaee6,
- (short) 0x9272,(short) 0x2c85,(short) 0x1482,(short) 0x353b,
- (short) 0xa2bf,(short) 0xe8a1,(short) 0x4cf1,(short) 0x0364,
- (short) 0xa81a,(short) 0x664b,(short) 0xbc42,(short) 0x3001,
- (short) 0xc24b,(short) 0x8b70,(short) 0xd0f8,(short) 0x9791,
- (short) 0xc76c,(short) 0x51a3,(short) 0x0654,(short) 0xbe30,
- (short) 0xd192,(short) 0xe819,(short) 0xd6ef,(short) 0x5218,
- (short) 0xd699,(short) 0x0624,(short) 0x5565,(short) 0xa910,
- (short) 0xf40e,(short) 0x3585,(short) 0x5771,(short) 0x202a,
- (short) 0x106a,(short) 0xa070,(short) 0x32bb,(short) 0xd1b8,
- (short) 0x19a4,(short) 0xc116,(short) 0xb8d2,(short) 0xd0c8,
- (short) 0x1e37,(short) 0x6c08,(short) 0x5141,(short) 0xab53,
- (short) 0x2748,(short) 0x774c,(short) 0xdf8e,(short) 0xeb99,
- (short) 0x34b0,(short) 0xbcb5,(short) 0xe19b,(short) 0x48a8,
- (short) 0x391c,(short) 0x0cb3,(short) 0xc5c9,(short) 0x5a63,
- (short) 0x4ed8,(short) 0xaa4a,(short) 0xe341,(short) 0x8acb,
- (short) 0x5b9c,(short) 0xca4f,(short) 0x7763,(short) 0xe373,
- (short) 0x682e,(short) 0x6ff3,(short) 0xd6b2,(short) 0xb8a3,
- (short) 0x748f,(short) 0x82ee,(short) 0x5def,(short) 0xb2fc,
- (short) 0x78a5,(short) 0x636f,(short) 0x4317,(short) 0x2f60,
- (short) 0x84c8,(short) 0x7814,(short) 0xa1f0,(short) 0xab72,
- (short) 0x8cc7,(short) 0x0208,(short) 0x1a64,(short) 0x39ec,
- (short) 0x90be,(short) 0xfffa,(short) 0x2363,(short) 0x1e28,
- (short) 0xa450,(short) 0x6ceb,(short) 0xde82,(short) 0xbde9,
- (short) 0xbef9,(short) 0xa3f7,(short) 0xb2c6,(short) 0x7915,
- (short) 0xc671,(short) 0x78f2,(short) 0xe372,(short) 0x532b,
- (short) 0xca27,(short) 0x3ece,(short) 0xea26,(short) 0x619c,
- (short) 0xd186,(short) 0xb8c7,(short) 0x21c0,(short) 0xc207,
- (short) 0xeada,(short) 0x7dd6,(short) 0xcde0,(short) 0xeb1e,
- (short) 0xf57d,(short) 0x4f7f,(short) 0xee6e,(short) 0xd178,
- (short) 0x06f0,(short) 0x67aa,(short) 0x7217,(short) 0x6fba,
- (short) 0x0a63,(short) 0x7dc5,(short) 0xa2c8,(short) 0x98a6,
- (short) 0x113f,(short) 0x9804,(short) 0xbef9,(short) 0x0dae,
- (short) 0x1b71,(short) 0x0b35,(short) 0x131c,(short) 0x471b,
- (short) 0x28db,(short) 0x77f5,(short) 0x2304,(short) 0x7d84,
- (short) 0x32ca,(short) 0xab7b,(short) 0x40c7,(short) 0x2493,
- (short) 0x3c9e,(short) 0xbe0a,(short) 0x15c9,(short) 0xbebc,
- (short) 0x431d,(short) 0x67c4,(short) 0x9c10,(short) 0x0d4c,
- (short) 0x4cc5,(short) 0xd4be,(short) 0xcb3e,(short) 0x42b6,
- (short) 0x597f,(short) 0x299c,(short) 0xfc65,(short) 0x7e2a,
- (short) 0x5fcb,(short) 0x6fab,(short) 0x3ad6,(short) 0xfaec,
- (short) 0x6c44,(short) 0x198c,(short) 0x4a47,(short) 0x5817
- };
-
- public static short[] h_short;
- public static short[] w_short;
-
- public static short[] hashState;
- public static byte[] buffer;
- public static short bufferOff;
- public static short bufferLeft;
-
- // used in reset(), update() & doFinal() to store size of msg to hash
- // public static byte[] dataSize;
- // public static final short MSGSIZE=0;
- // public static final short CHUNKSIZE=4;
-
- public static void init(){
-
- w_short= JCSystem.makeTransientShortArray((short) (64), JCSystem.CLEAR_ON_DESELECT);
- h_short= JCSystem.makeTransientShortArray((short) (32), JCSystem.CLEAR_ON_DESELECT);
-
- hashState= JCSystem.makeTransientShortArray((short) (32), JCSystem.CLEAR_ON_DESELECT);
- buffer= JCSystem.makeTransientByteArray((short) (128), JCSystem.CLEAR_ON_DESELECT);
-
- // used in reset(), update() & doFinal() to store size of msg to hash
- //dataSize= JCSystem.makeTransientByteArray((short) (8), JCSystem.CLEAR_ON_DESELECT);
- }
-
- // simplified method to hash exactly 2 blocks, i.e. >128 bytes and <=240 bytes, as required for Bip32
- public static short resetUpdateDoFinal(byte[] inBuff, short inOffset, short inLength, byte[] outBuff, short outOffset){
-
- // variable declaration for inline additions
- short akku,posy,posx,addx,addy;
-
- /* Reset */
- bufferOff=0;
- bufferLeft=128;
-
- /* Update */
-
- // perform function compression on first (complete) 1024 blocks
- // fulfil buffer
- Util.arrayCopyNonAtomic(inBuff, inOffset, buffer, bufferOff, bufferLeft);
- inOffset+=bufferLeft;
- bufferLeft=128;
- bufferOff=0;
-
- // apply compression function
- for (short i=0; i<32; i++){
- hashState[i]= H_INIT_SHORT[i];
- h_short[i]=hashState[i];
- }
- CompressionFunction(h_short, (short)0, buffer, (short)0);
- //add result back in hashState
- for (short i=0; i<32; i+=4){
- add_carry(hashState, i, h_short, i);
- }
-
- // save remaining msg in buffer
- short remainingBytes= (short)(inLength-(short)128);
- Util.arrayCopyNonAtomic(inBuff, inOffset, buffer, bufferOff, remainingBytes);
- bufferLeft-=remainingBytes;
- bufferOff+=remainingBytes;
-
- /* DoFinal */
-
- // pad remaining bytes in the buffer
- buffer[bufferOff]=(byte)0x80;
- bufferLeft--;
- bufferOff++;
- Util.arrayFillNonAtomic(buffer, bufferOff, bufferLeft, (byte)0x00);
-
- // message size (in bits)
- buffer[(short)(buffer.length-2)]=(byte)(((short)(8*inLength)>>8)&0xff);
- buffer[(short)(buffer.length-1)]=(byte)((8*inLength) &0xff);
-
- // apply compression function on last block
- for (short i=0; i<32; i++){
- h_short[i]=hashState[i];
- }
- CompressionFunction(h_short, (short)0, buffer, (short)0);
- //add result back in hashState
- for (short i=0; i<32; i+=4){
- add_carry(hashState, i, h_short, i);
- }
-
- // copy final state back
- for (short i=0; i<32; i++){
- outBuff[outOffset]=(byte)((hashState[i]>>8)&0xff);
- outOffset++;
- outBuff[outOffset]=(byte)(hashState[i]&0xff);
- outOffset++;
- }
-
- return (short)64;
- }
-
- public static void CompressionFunction(short[] state, short stateOff, byte[] msgBlock, short msgOff){
-
- // temporary value for inline method
- short off1, off2, off3;
- short regA0, regA1, regA2, regA3;
- short regB0, regB1, regB2, regB3;
- short tmpA0, tmpA1, tmpA2, tmpA3;
-
- // stateOff => 32 short state (512 bits)
- // msgBlock => 128 byte data (1024 bits)
- InitW(msgBlock, msgOff);
-
- short hOff=0, wOff=0;
- for (short round=0; round<80; round++){
-
- // update W and get wCurrent in regB
- updateW_fast(w_short, wOff, regB, regA, tmpA);
-
- // regA= h+K
- off1= (short)(((short)(hOff+28))%32);
- off2= (short)(4*(round));
- add_carry_fast2(state, off1, K_SHORT, off2, regA, tmpA);
-
- // regA= h+K+wCurrent
- add_carry_fast(regA, regB, tmpA);
-
- // regB= Ch(e,f,g)
- off1=(short)(((short)(hOff+16))%32);
- off2=(short)(((short)(hOff+20))%32);
- off3=(short)(((short)(hOff+24))%32);
- Ch_fast(state, off1, state, off2, state, off3, regB, tmpA);
-
- // regA= h+K+wCurrent+Ch(e,f,g)
- add_carry_fast(regA, regB, tmpA);
-
- // regB= E1(e)
- off1=(short)(((short)(hOff+16))%32);
- E1_fast(state, off1, regB, tmpA);
-
- // regA= h+K+wCurrent+Ch(e,f,g)+E1
- add_carry_fast(regA, regB, tmpA);
-
- // d= d+regA
- off1= (short)(((short)(hOff+12))%32);
- add_carry_fast3(state, off1, regA, tmpA)
-
- // regB= Maj(a,b,c)
- //Maj(state, hOff, state, (short)(((short)(hOff+4))%32), state, (short)(((short)(hOff+8))%32), tmp, REG2);
- off1= (short)(((short)(hOff+4))%32);
- off2= (short)(((short)(hOff+8))%32);
- Maj_fast(state, hOff, state, off1, state, off2, regB, tmpA)
-
- // regA= regA+Maj(a,b,c)
- add_carry_fast(regA, regB, tmpA);
-
- // regB= E0(a)
- E0_fast(state, hOff, regB, tmpA);
-
- // regA= regA+E0(a)
- add_carry_fast(regA, regB, tmpA);
-
- //update state(h) with regA
- state[(short)(((short)(hOff+28))%32)]= regA0;
- state[(short)(((short)(hOff+29))%32)]= regA1;
- state[(short)(((short)(hOff+30))%32)]= regA2;
- state[(short)(((short)(hOff+31))%32)]= regA3;
-
- // update offset
- hOff= (short)(((short)(32+hOff-4))%32);
-
- }// end for
- }
-
-
- /*
- public static void reset(){
- bufferOff=0;
- bufferLeft=128;
- for (short i=0; i<32; i++){
- hashState[i]= H_INIT_SHORT[i];
- }
- for (short i=0; i<8; i++){
- dataSize[i]=(byte)0;
- }
- }
-
- public static void update(byte[] inBuff, short inOffset, short inLength){
-
- // for additions
- short akku,posy,posx,addx,addy;
-
- // update msg size in bits
- dataSize[6]=(byte)(((short)(8*inLength)>>8)&0xff);
- dataSize[7]=(byte)((8*inLength) &0xff);
- add_carry_byte(dataSize, MSGSIZE, dataSize, CHUNKSIZE, (short)4);
-
- // perform function compression on complete 1024 blocks
- while (inLength>=bufferLeft){
-
- // fulfill buffer
- //System.arraycopy(inBuff, inOffset, buffer, bufferOff, bufferLeft);
- Util.arrayCopyNonAtomic(inBuff, inOffset, buffer, bufferOff, bufferLeft);
- inOffset+=bufferLeft;
- inLength-=bufferLeft;
- bufferLeft=128;
- bufferOff=0;
-
- // apply compression function
- for (short i=0; i<32; i++){
- h_short[i]=hashState[i];
- }
- CompressionFunction(h_short, (short)0, buffer, (short)0);
-
- //add result back in hashState
- for (short i=0; i<32; i+=4){
- add_carry(hashState, (short)i, h_short, (short)i);
- }
-
- }
- // at this point, bufferLeft>inLength
-
- // save remaining msg in buffer
- Util.arrayCopyNonAtomic(inBuff, inOffset, buffer, bufferOff, inLength);
- inOffset+=inLength;
- bufferLeft-=inLength;
- bufferOff+=inLength;
- }
-
-
-
- public static short doFinal(byte[] inBuff, short inOffset, short inLength, byte[] outBuff, short outOffset){
-
- // for additions
- short akku,posy,posx,addx,addy;
-
- // perform update first
- update(inBuff, inOffset, inLength);
-
- // padd remaining bytes in the buffer
- buffer[bufferOff]=(byte)0x80;
- bufferLeft--;
- bufferOff++;
- Util.arrayFillNonAtomic(buffer, bufferOff, bufferLeft, (byte)0x00);
-
- if (bufferLeft<16){ // needs an additional block
- // apply compression function
- for (short i=0; i<32; i++){
- h_short[i]=hashState[i];
- }
- CompressionFunction(h_short, (short)0, buffer, (short)0);
- //add result back in hashState
- for (short i=0; i<32; i+=4){
- add_carry(hashState, (short)i, h_short, (short)i);
- }
- // reset buffer
- bufferOff=0;
- bufferLeft=128;
- Util.arrayFillNonAtomic(buffer, bufferOff, bufferLeft, (byte)0x00);
- }
- // message size (in bits)
- Util.arrayCopyNonAtomic(dataSize, MSGSIZE, buffer, (short)(buffer.length-4), (short)4);
-
- // apply compression function on last block
- for (short i=0; i<32; i++){
- h_short[i]=hashState[i];
- }
- CompressionFunction(h_short, (short)0, buffer, (short)0);
- //add result back in hashState
- for (short i=0; i<32; i+=4){
- add_carry(hashState, (short)i, h_short, (short)i);
- }
-
- // copy final state back and reset
- for (short i=0; i<32; i++){
- outBuff[outOffset]=(byte)((hashState[i]>>8)&0xff);
- outOffset++;
- outBuff[outOffset]=(byte)(hashState[i]&0xff);
- outOffset++;
- }
- reset();
-
- return (short)64;
- }
-
- public static boolean add_carry_byte(byte[] x, short offsetx, byte[] y, short offsety, short size){
- short digit_mask = 0xff;
- short digit_len = 8;
- short akku = 0;
- short j = (short)(offsetx+size-1);
- for(short i = (short)(offsety+size-1); i >= offsety; i--, j--) {
- akku = (short)(akku + (x[j] & digit_mask) + (y[i] & digit_mask));
-
- x[j] = (byte)(akku & digit_mask);
- akku = (short)((akku >>> digit_len) & digit_mask);
- }
- return akku != 0;
- }
- */
-
-}
-