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; - } - */ - -} -