document SecureChannel

This commit is contained in:
Michele Balistreri 2017-10-28 18:46:56 +03:00
parent 8729768478
commit 74594092c8
1 changed files with 40 additions and 15 deletions

View File

@ -3,10 +3,12 @@ package im.status.wallet;
import javacard.framework.APDU;
import javacard.framework.ISO7816;
import javacard.framework.JCSystem;
import javacard.framework.Util;
import javacard.security.*;
import javacardx.crypto.Cipher;
/**
* Implements all methods related to the secure channel as specified in the SECURE_CHANNEL.md document.
*/
public class SecureChannel {
public static final short SC_KEY_LENGTH = 256;
public static final short SC_SECRET_LENGTH = 32;
@ -21,8 +23,13 @@ public class SecureChannel {
private KeyPair scKeypair;
private byte[] secret;
/**
* Instatiates a Secure Channel. All memory allocations needed for the secure channel are peformed here. The keypair
* used for the EC-DH algorithm is also generated here.
*/
public SecureChannel() {
scCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
scCipher = Cipher.getInstance(Cipher.ALG_AES_CBC_ISO9797_M2,false);
scKey = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_256, false);
scKeypair = new KeyPair(KeyPair.ALG_EC_FP, SC_KEY_LENGTH);
@ -36,7 +43,11 @@ public class SecureChannel {
secret = JCSystem.makeTransientByteArray(SC_SECRET_LENGTH, JCSystem.CLEAR_ON_DESELECT);
}
/**
* Processes the OPEN SECURE CHANNEL command.
*
* @param apdu the JCRE-owned APDU object.
*/
public void openSecureChannel(APDU apdu) {
apdu.setIncomingAndReceive();
byte[] apduBuffer = apdu.getBuffer();
@ -48,41 +59,55 @@ public class SecureChannel {
apdu.setOutgoingAndSend((short) 0, SC_SECRET_LENGTH);
}
/**
* Decrypts the given APDU buffer. The plaintext is written in-place starting at the ISO7816.OFFSET_CDATA offset. The
* IV and padding are stripped. The LC byte is overwritten with the plaintext length.
*
* @param apduBuffer the APDU buffer
* @return the length of the decrypted
*/
public short decryptAPDU(byte[] apduBuffer) {
short apduLen = (short)((short) apduBuffer[ISO7816.OFFSET_LC] & 0xff);
scCipher.init(scKey, Cipher.MODE_DECRYPT, apduBuffer, ISO7816.OFFSET_CDATA, SC_BLOCK_SIZE);
short len = scCipher.doFinal(apduBuffer, (short)(ISO7816.OFFSET_CDATA + SC_BLOCK_SIZE), (short) (apduLen - SC_BLOCK_SIZE), apduBuffer, ISO7816.OFFSET_CDATA);
while(apduBuffer[(short)(ISO7816.OFFSET_CDATA+len-1)] != (byte) 0x80) {
len--;
}
len--;
apduBuffer[ISO7816.OFFSET_LC] = (byte) len;
return len;
}
/**
* Encrypts the APDU buffer. The plaintext must be placed starting at the SecureChannel.SC_OUT_OFFSET offset, to leave
* place for the SecureChannel-specific data at the beginning of the APDU.
*
* @param apduBuffer the APDU buffer
* @param len the length of the plaintext
* @return the length of the encrypted APDU
*/
public short encryptAPDU(byte[] apduBuffer, short len) {
apduBuffer[(short)(SC_OUT_OFFSET + len)] = (byte) 0x80;
len++;
short padding = (short) ((SC_BLOCK_SIZE - (short) (len % SC_BLOCK_SIZE)) % SC_BLOCK_SIZE);
Util.arrayFillNonAtomic(apduBuffer, (short)(SC_OUT_OFFSET + len), padding, (byte) 0x00);
len += padding;
Crypto.random.generateData(apduBuffer, ISO7816.OFFSET_CDATA, SC_BLOCK_SIZE);
scCipher.init(scKey, Cipher.MODE_ENCRYPT, apduBuffer, ISO7816.OFFSET_CDATA, SC_BLOCK_SIZE);
len = scCipher.doFinal(apduBuffer, SC_OUT_OFFSET, len, apduBuffer, (short)(ISO7816.OFFSET_CDATA + SC_BLOCK_SIZE));
return (short)(len + SC_BLOCK_SIZE);
}
/**
* Copies the public key used for EC-DH in the given buffer.
*
* @param buf the buffer
* @param off the offset in the buffer
* @return the length of the public key
*/
public short copyPublicKey(byte[] buf, byte off) {
ECPublicKey pk = (ECPublicKey) scKeypair.getPublic();
return pk.getW(buf, off);
}
/**
* Returns whether a secure channel is currently established or not.
* @return whether a secure channel is currently established or not.
*/
public boolean isOpen() {
return scKey.isInitialized();
}