Improve memory handling with SecureMessaging

This commit is contained in:
Arnaud Fontaine 2017-07-07 19:34:46 +02:00
parent f693a7290e
commit ec84edb737
4 changed files with 124 additions and 109 deletions

View File

@ -31,7 +31,7 @@ public final class CmacKey {
protected final byte[] k1;
protected final byte[] k2;
protected CmacKey(final byte aesKeyLength) {
protected CmacKey(final short aesKeyLength) {
key = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT,
(short)(aesKeyLength * 8),
false);
@ -51,6 +51,10 @@ public final class CmacKey {
Util.arrayFillNonAtomic(k2, (short)0, (short)k2.length, (byte)0);
}
protected final short getSize() {
return key.getSize();
}
protected final void setKey(final byte[] buf, final short bufOff) {
key.setKey(buf, bufOff);

View File

@ -51,8 +51,13 @@ public final class CmacSignature {
}
protected final void clear() {
if(key != null) {
if(key.isInitialized()) {
key.clearKey();
}
key = null;
}
}
private final byte blockLen() {
return bytes[BYTE_OFFSET_BLOCK_LEN];

View File

@ -27,6 +27,14 @@ import javacardx.crypto.*;
public final class Common {
protected static final short aesKeyLength(final ECParams params) {
if(params.nb_bits < (short)512) {
return (short)16;
} else {
return (short)32;
}
}
protected static final short writeLength(final byte[] buf, short off, final short len) {
if(len > 0xff) {
buf[off] = (byte)0x82;

View File

@ -29,7 +29,6 @@ public final class SecureMessaging {
public static final short MAC_LENGTH = (short)(Constants.AES_BLOCK_SIZE / (short)2);
protected static final byte[] PADDING_BLOCK = {
(byte)0x80, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
@ -37,62 +36,101 @@ public final class SecureMessaging {
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00
};
private final byte[] iv;
private final byte[] mac_chaining;
private static final byte[] CRT_PREFIX = {
(byte)0xA6, (byte)0x0D,
(byte)0x90, (byte)0x02, (byte)0x11, (byte)0x00,
(byte)0x95, (byte)0x01, (byte)0x3C,
(byte)0x80, (byte)0x01, (byte)0x88,
(byte)0x81, (byte)0x01
};
private final Cipher cipher;
private final CmacSignature macer;
private AESKey senc;
private CmacKey smac;
private CmacKey srmac;
private final MessageDigest digest;
private final KeyAgreement key_agreement;
protected final PGPKey static_key;
private final Cipher cipher;
private AESKey senc;
private final byte[] iv;
private final CmacSignature macer;
private final byte[] mac_chaining;
private CmacKey sreceiptmac;
private CmacKey smac;
private CmacKey srmac;
protected SecureMessaging(final Transients transients) {
digest = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
key_agreement = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH_PLAIN, false);
static_key = new PGPKey(true);
cipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
macer = new CmacSignature();
senc = null;
iv = JCSystem.makeTransientByteArray(Constants.AES_BLOCK_SIZE,
JCSystem.CLEAR_ON_DESELECT);
macer = new CmacSignature();
mac_chaining = JCSystem.makeTransientByteArray(Constants.AES_BLOCK_SIZE,
JCSystem.CLEAR_ON_DESELECT);
senc = null;
sreceiptmac = null;
smac = null;
srmac = null;
static_key = new PGPKey(true);
reset(transients);
}
protected final void clearSession(final Transients transients) {
if(senc != null) {
if((senc != null) && senc.isInitialized()) {
senc.clearKey();
senc = null;
}
if(smac != null) {
smac.clearKey();
smac = null;
}
if(srmac != null) {
srmac.clearKey();
srmac = null;
}
macer.clear();
transients.setSecureMessagingEncryptionCounter((short)0);
Util.arrayFillNonAtomic(iv, (short)0, (short)iv.length, (byte)0);
macer.clear();
Util.arrayFillNonAtomic(mac_chaining, (short)0, (short)mac_chaining.length, (byte)0);
if((sreceiptmac != null) && senc.isInitialized()) {
sreceiptmac.clearKey();
}
if((smac != null) && smac.isInitialized()) {
smac.clearKey();
}
if((srmac != null) && srmac.isInitialized()) {
srmac.clearKey();
}
transients.setSecureMessagingEncryptionCounter((short)0);
}
protected final void reset(final Transients transients) {
clearSession(transients);
sreceiptmac = null;
senc = null;
smac = null;
srmac = null;
static_key.reset();
}
private final void initSession(final short keyLength,
final byte[] buf, final short off) {
if((sreceiptmac == null) ||
(sreceiptmac.getSize() != (short)(keyLength * 8))) {
senc = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT,
(short)(keyLength * 8),
false);
sreceiptmac = new CmacKey(keyLength);
smac = new CmacKey(keyLength);
srmac = new CmacKey(keyLength);
}
sreceiptmac.setKey(buf, off);
senc.setKey(buf, (short)(off + keyLength));
smac.setKey(buf, (short)(off + (short)(2 * keyLength)));
srmac.setKey(buf, (short)(off + (short)(3 * keyLength)));
}
protected final boolean isInitialized() {
return static_key.isInitialized();
}
@ -104,38 +142,27 @@ public final class SecureMessaging {
&& (srmac != null) && srmac.isInitialized();
}
private static final byte aesKeyLength(final ECParams params) {
if(params.nb_bits < (short)512) {
return (byte)16;
} else {
return (byte)32;
}
}
private final short scp11b(final ECParams params,
private final short scp11b(final ECCurves curves,
final byte[] buf, final short len) {
final byte[] crt = new byte[]{ (byte)0xA6, (byte)0x0D,
(byte)0x90, (byte)0x02, (byte)0x11, (byte)0x00,
(byte)0x95, (byte)0x01, (byte)0x3C,
(byte)0x80, (byte)0x01, (byte)0x88,
(byte)0x81, (byte)0x01 };
final ECParams params = static_key.ecParams(curves);
if(len <= (short)((short)crt.length + 4)) {
if(len <= (short)((short)CRT_PREFIX.length + 4)) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return 0;
}
if(Util.arrayCompare(crt, (short)0,
if(Util.arrayCompare(CRT_PREFIX, (short)0,
buf, (short)0,
(short)crt.length) != (byte)0) {
(short)CRT_PREFIX.length) != (byte)0) {
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
return 0;
}
short off = (short)crt.length;
short off = (short)CRT_PREFIX.length;
if(buf[off] != aesKeyLength(params)) {
if(buf[off] != Common.aesKeyLength(params)) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
return 0;
}
@ -147,7 +174,7 @@ public final class SecureMessaging {
}
off += 2;
final short keylen = Common.readLength(buf, off, len);
short keylen = Common.readLength(buf, off, len);
off = Common.skipLength(buf, off, len);
@ -161,17 +188,17 @@ public final class SecureMessaging {
return 0;
}
final ECPrivateKey eskcard = (ECPrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE,
ECPrivateKey eskcard = (ECPrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE,
params.nb_bits,
false);
final ECPublicKey epkcard = (ECPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC,
ECPublicKey epkcard = (ECPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC,
params.nb_bits,
false);
params.setParams(eskcard);
params.setParams(epkcard);
final KeyPair ekcard = new KeyPair(epkcard, eskcard);
KeyPair ekcard = new KeyPair(epkcard, eskcard);
ekcard.genKeyPair();
@ -181,17 +208,16 @@ public final class SecureMessaging {
return 0;
}
final KeyAgreement ka = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH_PLAIN, false);
ka.init(eskcard);
key_agreement.init(eskcard);
short msglen = 0;
msglen += ka.generateSecret(buf, off, keylen, buf, len);
msglen += key_agreement.generateSecret(buf, off, keylen, buf, len);
eskcard.clearKey();
eskcard = null;
static_key.initKeyAgreement(ka);
msglen += ka.generateSecret(buf, off, keylen, buf, (short)(len + msglen));
static_key.initKeyAgreement(key_agreement);
msglen += key_agreement.generateSecret(buf, off, keylen, buf, (short)(len + msglen));
Util.setShort(buf, (short)(len + msglen), (short)0);
msglen += 2;
@ -200,52 +226,26 @@ public final class SecureMessaging {
off = (short)(len + msglen);
msglen += 2;
buf[(short)(len + msglen)] = crt[(short)8];
buf[(short)(len + msglen)] = CRT_PREFIX[(short)8];
++msglen;
buf[(short)(len + msglen)] = crt[(short)11];
buf[(short)(len + msglen)] = CRT_PREFIX[(short)11];
++msglen;
buf[(short)(len + msglen)] = buf[crt.length];
buf[(short)(len + msglen)] = buf[CRT_PREFIX.length];
++msglen;
short keydata_len = 0;
keylen = 0;
final MessageDigest digest = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
while(keydata_len < (short)(4 * buf[crt.length])) {
while(keylen < (short)(4 * buf[CRT_PREFIX.length])) {
Util.setShort(buf, off, counter);
++counter;
keydata_len += digest.doFinal(buf, len, msglen,
buf, (short)(len + msglen + keydata_len));
keylen += digest.doFinal(buf, len, msglen,
buf, (short)(len + msglen + keylen));
}
final CmacKey sreceiptmac = new CmacKey(aesKeyLength(params));
sreceiptmac.setKey(buf, (short)(len + msglen));
initSession(Common.aesKeyLength(params), buf, (short)(len + msglen));
if(senc != null) {
senc.clearKey();
senc = null;
}
senc = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT,
(short)(aesKeyLength(params) * 8),
false);
senc.setKey(buf, (short)(len + msglen + aesKeyLength(params)));
if(smac != null) {
smac.clearKey();
smac = null;
}
smac = new CmacKey(aesKeyLength(params));
smac.setKey(buf, (short)(len + msglen + 2 * aesKeyLength(params)));
if(srmac != null) {
srmac.clearKey();
srmac = null;
}
srmac = new CmacKey(aesKeyLength(params));
srmac.setKey(buf, (short)(len + msglen + 3 * aesKeyLength(params)));
Util.arrayFillNonAtomic(buf, len, (short)(msglen + keydata_len), (byte)0);
Util.arrayFillNonAtomic(buf, len, (short)(msglen + keylen), (byte)0);
off = len;
Util.setShort(buf, off, (short)0x5F49);
@ -255,6 +255,9 @@ public final class SecureMessaging {
msglen = off;
epkcard.clearKey();
epkcard = null;
ekcard = null;
buf[off++] = (byte)0x86;
buf[off++] = (byte)Constants.AES_BLOCK_SIZE;
@ -262,7 +265,6 @@ public final class SecureMessaging {
macer.init(sreceiptmac);
macer.sign(buf, (short)0, msglen,
buf, off, Constants.AES_BLOCK_SIZE);
sreceiptmac.clearKey();
macer.clear();
Util.arrayCopy(buf, off, mac_chaining, (short)0, Constants.AES_BLOCK_SIZE);
@ -284,11 +286,7 @@ public final class SecureMessaging {
clearSession(transients);
if(isInitialized() && static_key.isEc()) {
final ECParams params = static_key.ecParams(ec);
if(params != null) {
return scp11b(params, buf, len);
}
return scp11b(ec, buf, len);
}
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);