From e04f4c7bc7232b049d68b30f5e22a2167776824c Mon Sep 17 00:00:00 2001 From: Michele Balistreri Date: Tue, 21 Nov 2017 16:21:56 +0300 Subject: [PATCH] implement AES CBC-MAC with a software fallback --- .../java/im/status/wallet/SecureChannel.java | 45 ++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/src/main/java/im/status/wallet/SecureChannel.java b/src/main/java/im/status/wallet/SecureChannel.java index eaf8545..00279d1 100644 --- a/src/main/java/im/status/wallet/SecureChannel.java +++ b/src/main/java/im/status/wallet/SecureChannel.java @@ -22,9 +22,13 @@ public class SecureChannel { public static final byte PAIR_P1_FIRST_STEP = 0x00; public static final byte PAIR_P1_LAST_STEP = 0x01; + public static final short MAX_MAC_APDU_SIZE = (short) 256; + private AESKey scEncKey; private AESKey scMacKey; private Cipher scCipher; + private Cipher scMacCipher; + private byte[] macCipherBuf; private Signature scMac; private KeyPair scKeypair; private byte[] secret; @@ -46,7 +50,12 @@ public class SecureChannel { public SecureChannel(byte pairingLimit, byte[] aPairingSecret, short off) { scCipher = Cipher.getInstance(Cipher.ALG_AES_CBC_ISO9797_M2,false); - scMac = Signature.getInstance(Signature.ALG_AES_MAC_128_NOPAD, false); + try { + scMac = Signature.getInstance(Signature.ALG_AES_MAC_128_NOPAD, false); + } catch (CryptoException e) { + scMacCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false); + macCipherBuf = JCSystem.makeTransientByteArray(MAX_MAC_APDU_SIZE, JCSystem.CLEAR_ON_DESELECT); + } scEncKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_256, false); scMacKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_256, false); @@ -56,7 +65,7 @@ public class SecureChannel { SECP256k1.setCurveParameters((ECKey) scKeypair.getPublic()); scKeypair.genKeyPair(); - secret = JCSystem.makeTransientByteArray((byte)(SC_SECRET_LENGTH * 2), JCSystem.CLEAR_ON_DESELECT); + secret = JCSystem.makeTransientByteArray((short)(SC_SECRET_LENGTH * 2), JCSystem.CLEAR_ON_DESELECT); pairingSecret = new byte[SC_SECRET_LENGTH]; pairingKeys = new byte[(short)(PAIRING_KEY_LENGTH * pairingLimit)]; @@ -261,11 +270,19 @@ public class SecureChannel { } public boolean verifyAESMAC(byte[] apduBuffer, short apduLen) { - scMac.init(scMacKey, Signature.MODE_VERIFY); - scMac.update(apduBuffer, (short) 0, ISO7816.OFFSET_CDATA); - scMac.update(secret, SC_BLOCK_SIZE, (short) (SC_BLOCK_SIZE - ISO7816.OFFSET_CDATA)); + if (scMac == null) { + scMacCipher.init(scMacKey, Cipher.MODE_ENCRYPT); + short encLen = scMacCipher.update(apduBuffer, (short) 0, ISO7816.OFFSET_CDATA, macCipherBuf, (short) 0); + encLen += scMacCipher.update(secret, SC_BLOCK_SIZE, (short) (SC_BLOCK_SIZE - ISO7816.OFFSET_CDATA), macCipherBuf, encLen); + encLen += scMacCipher.doFinal(apduBuffer, (short) (ISO7816.OFFSET_CDATA + SC_BLOCK_SIZE), (short) (apduLen - SC_BLOCK_SIZE), macCipherBuf, encLen); + return Util.arrayCompare(apduBuffer, ISO7816.OFFSET_CDATA, macCipherBuf, (short)(encLen - SC_BLOCK_SIZE), SC_BLOCK_SIZE) == 0; + } else { + scMac.init(scMacKey, Signature.MODE_VERIFY); + scMac.update(apduBuffer, (short) 0, ISO7816.OFFSET_CDATA); + scMac.update(secret, SC_BLOCK_SIZE, (short) (SC_BLOCK_SIZE - ISO7816.OFFSET_CDATA)); - return scMac.verify(apduBuffer, (short) (ISO7816.OFFSET_CDATA + SC_BLOCK_SIZE), (short) (apduLen - SC_BLOCK_SIZE), apduBuffer, ISO7816.OFFSET_CDATA, SC_BLOCK_SIZE); + return scMac.verify(apduBuffer, (short) (ISO7816.OFFSET_CDATA + SC_BLOCK_SIZE), (short) (apduLen - SC_BLOCK_SIZE), apduBuffer, ISO7816.OFFSET_CDATA, SC_BLOCK_SIZE); + } } /** @@ -296,10 +313,18 @@ public class SecureChannel { } public void computeAESMAC(short len, byte[] apduBuffer) { - scMac.init(scMacKey, Signature.MODE_SIGN); - scMac.update(apduBuffer, (short) 0, (short) 1); - scMac.update(secret, SC_BLOCK_SIZE, (short)(SC_BLOCK_SIZE - 1)); - scMac.sign(apduBuffer, (short)(ISO7816.OFFSET_CDATA + SC_BLOCK_SIZE), len, apduBuffer, ISO7816.OFFSET_CDATA); + if (scMac == null) { + scMacCipher.init(scMacKey, Cipher.MODE_ENCRYPT); + short encLen = scMacCipher.update(apduBuffer, (short) 0, (short) 1, macCipherBuf, (short) 0); + encLen += scMacCipher.update(secret, SC_BLOCK_SIZE, (short) (SC_BLOCK_SIZE - 1), macCipherBuf, encLen); + encLen += scMacCipher.doFinal(apduBuffer, (short) (ISO7816.OFFSET_CDATA + SC_BLOCK_SIZE), len, macCipherBuf, encLen); + Util.arrayCopyNonAtomic(macCipherBuf, (short)(encLen - SC_BLOCK_SIZE), apduBuffer, ISO7816.OFFSET_CDATA, SC_BLOCK_SIZE); + } else { + scMac.init(scMacKey, Signature.MODE_SIGN); + scMac.update(apduBuffer, (short) 0, (short) 1); + scMac.update(secret, SC_BLOCK_SIZE, (short) (SC_BLOCK_SIZE - 1)); + scMac.sign(apduBuffer, (short) (ISO7816.OFFSET_CDATA + SC_BLOCK_SIZE), len, apduBuffer, ISO7816.OFFSET_CDATA); + } } /**