Improve memory handling with SecureMessaging
This commit is contained in:
parent
f693a7290e
commit
ec84edb737
@ -31,7 +31,7 @@ public final class CmacKey {
|
|||||||
protected final byte[] k1;
|
protected final byte[] k1;
|
||||||
protected final byte[] k2;
|
protected final byte[] k2;
|
||||||
|
|
||||||
protected CmacKey(final byte aesKeyLength) {
|
protected CmacKey(final short aesKeyLength) {
|
||||||
key = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT,
|
key = (AESKey)KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT,
|
||||||
(short)(aesKeyLength * 8),
|
(short)(aesKeyLength * 8),
|
||||||
false);
|
false);
|
||||||
@ -51,6 +51,10 @@ public final class CmacKey {
|
|||||||
Util.arrayFillNonAtomic(k2, (short)0, (short)k2.length, (byte)0);
|
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) {
|
protected final void setKey(final byte[] buf, final short bufOff) {
|
||||||
key.setKey(buf, bufOff);
|
key.setKey(buf, bufOff);
|
||||||
|
|
||||||
|
@ -51,8 +51,13 @@ public final class CmacSignature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected final void clear() {
|
protected final void clear() {
|
||||||
|
if(key != null) {
|
||||||
|
if(key.isInitialized()) {
|
||||||
|
key.clearKey();
|
||||||
|
}
|
||||||
key = null;
|
key = null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final byte blockLen() {
|
private final byte blockLen() {
|
||||||
return bytes[BYTE_OFFSET_BLOCK_LEN];
|
return bytes[BYTE_OFFSET_BLOCK_LEN];
|
||||||
|
@ -27,6 +27,14 @@ import javacardx.crypto.*;
|
|||||||
|
|
||||||
public final class Common {
|
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) {
|
protected static final short writeLength(final byte[] buf, short off, final short len) {
|
||||||
if(len > 0xff) {
|
if(len > 0xff) {
|
||||||
buf[off] = (byte)0x82;
|
buf[off] = (byte)0x82;
|
||||||
|
@ -29,7 +29,6 @@ public final class SecureMessaging {
|
|||||||
|
|
||||||
public static final short MAC_LENGTH = (short)(Constants.AES_BLOCK_SIZE / (short)2);
|
public static final short MAC_LENGTH = (short)(Constants.AES_BLOCK_SIZE / (short)2);
|
||||||
|
|
||||||
|
|
||||||
protected static final byte[] PADDING_BLOCK = {
|
protected static final byte[] PADDING_BLOCK = {
|
||||||
(byte)0x80, (byte)0x00, (byte)0x00, (byte)0x00,
|
(byte)0x80, (byte)0x00, (byte)0x00, (byte)0x00,
|
||||||
(byte)0x00, (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
|
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
private final byte[] iv;
|
private static final byte[] CRT_PREFIX = {
|
||||||
private final byte[] mac_chaining;
|
(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 MessageDigest digest;
|
||||||
|
private final KeyAgreement key_agreement;
|
||||||
private final CmacSignature macer;
|
|
||||||
private AESKey senc;
|
|
||||||
private CmacKey smac;
|
|
||||||
private CmacKey srmac;
|
|
||||||
|
|
||||||
protected final PGPKey static_key;
|
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) {
|
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);
|
cipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
|
||||||
|
senc = null;
|
||||||
macer = new CmacSignature();
|
|
||||||
|
|
||||||
iv = JCSystem.makeTransientByteArray(Constants.AES_BLOCK_SIZE,
|
iv = JCSystem.makeTransientByteArray(Constants.AES_BLOCK_SIZE,
|
||||||
JCSystem.CLEAR_ON_DESELECT);
|
JCSystem.CLEAR_ON_DESELECT);
|
||||||
|
|
||||||
|
macer = new CmacSignature();
|
||||||
mac_chaining = JCSystem.makeTransientByteArray(Constants.AES_BLOCK_SIZE,
|
mac_chaining = JCSystem.makeTransientByteArray(Constants.AES_BLOCK_SIZE,
|
||||||
JCSystem.CLEAR_ON_DESELECT);
|
JCSystem.CLEAR_ON_DESELECT);
|
||||||
|
sreceiptmac = null;
|
||||||
senc = null;
|
|
||||||
smac = null;
|
smac = null;
|
||||||
srmac = null;
|
srmac = null;
|
||||||
|
|
||||||
static_key = new PGPKey(true);
|
|
||||||
|
|
||||||
reset(transients);
|
reset(transients);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected final void clearSession(final Transients transients) {
|
protected final void clearSession(final Transients transients) {
|
||||||
if(senc != null) {
|
if((senc != null) && senc.isInitialized()) {
|
||||||
senc.clearKey();
|
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);
|
Util.arrayFillNonAtomic(iv, (short)0, (short)iv.length, (byte)0);
|
||||||
|
|
||||||
|
macer.clear();
|
||||||
Util.arrayFillNonAtomic(mac_chaining, (short)0, (short)mac_chaining.length, (byte)0);
|
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) {
|
protected final void reset(final Transients transients) {
|
||||||
clearSession(transients);
|
clearSession(transients);
|
||||||
|
sreceiptmac = null;
|
||||||
|
senc = null;
|
||||||
|
smac = null;
|
||||||
|
srmac = null;
|
||||||
static_key.reset();
|
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() {
|
protected final boolean isInitialized() {
|
||||||
return static_key.isInitialized();
|
return static_key.isInitialized();
|
||||||
}
|
}
|
||||||
@ -104,38 +142,27 @@ public final class SecureMessaging {
|
|||||||
&& (srmac != null) && srmac.isInitialized();
|
&& (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[] buf, final short len) {
|
||||||
|
|
||||||
final byte[] crt = new byte[]{ (byte)0xA6, (byte)0x0D,
|
final ECParams params = static_key.ecParams(curves);
|
||||||
(byte)0x90, (byte)0x02, (byte)0x11, (byte)0x00,
|
|
||||||
(byte)0x95, (byte)0x01, (byte)0x3C,
|
|
||||||
(byte)0x80, (byte)0x01, (byte)0x88,
|
|
||||||
(byte)0x81, (byte)0x01 };
|
|
||||||
|
|
||||||
if(len <= (short)((short)crt.length + 4)) {
|
if(len <= (short)((short)CRT_PREFIX.length + 4)) {
|
||||||
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
|
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Util.arrayCompare(crt, (short)0,
|
if(Util.arrayCompare(CRT_PREFIX, (short)0,
|
||||||
buf, (short)0,
|
buf, (short)0,
|
||||||
(short)crt.length) != (byte)0) {
|
(short)CRT_PREFIX.length) != (byte)0) {
|
||||||
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
|
ISOException.throwIt(ISO7816.SW_WRONG_DATA);
|
||||||
return 0;
|
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);
|
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -147,7 +174,7 @@ public final class SecureMessaging {
|
|||||||
}
|
}
|
||||||
off += 2;
|
off += 2;
|
||||||
|
|
||||||
final short keylen = Common.readLength(buf, off, len);
|
short keylen = Common.readLength(buf, off, len);
|
||||||
|
|
||||||
off = Common.skipLength(buf, off, len);
|
off = Common.skipLength(buf, off, len);
|
||||||
|
|
||||||
@ -161,17 +188,17 @@ public final class SecureMessaging {
|
|||||||
return 0;
|
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,
|
params.nb_bits,
|
||||||
false);
|
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,
|
params.nb_bits,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
params.setParams(eskcard);
|
params.setParams(eskcard);
|
||||||
params.setParams(epkcard);
|
params.setParams(epkcard);
|
||||||
|
|
||||||
final KeyPair ekcard = new KeyPair(epkcard, eskcard);
|
KeyPair ekcard = new KeyPair(epkcard, eskcard);
|
||||||
|
|
||||||
ekcard.genKeyPair();
|
ekcard.genKeyPair();
|
||||||
|
|
||||||
@ -181,17 +208,16 @@ public final class SecureMessaging {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
final KeyAgreement ka = KeyAgreement.getInstance(KeyAgreement.ALG_EC_SVDP_DH_PLAIN, false);
|
key_agreement.init(eskcard);
|
||||||
|
|
||||||
ka.init(eskcard);
|
|
||||||
|
|
||||||
short msglen = 0;
|
short msglen = 0;
|
||||||
|
|
||||||
msglen += ka.generateSecret(buf, off, keylen, buf, len);
|
msglen += key_agreement.generateSecret(buf, off, keylen, buf, len);
|
||||||
eskcard.clearKey();
|
eskcard.clearKey();
|
||||||
|
eskcard = null;
|
||||||
|
|
||||||
static_key.initKeyAgreement(ka);
|
static_key.initKeyAgreement(key_agreement);
|
||||||
msglen += ka.generateSecret(buf, off, keylen, buf, (short)(len + msglen));
|
msglen += key_agreement.generateSecret(buf, off, keylen, buf, (short)(len + msglen));
|
||||||
|
|
||||||
Util.setShort(buf, (short)(len + msglen), (short)0);
|
Util.setShort(buf, (short)(len + msglen), (short)0);
|
||||||
msglen += 2;
|
msglen += 2;
|
||||||
@ -200,52 +226,26 @@ public final class SecureMessaging {
|
|||||||
off = (short)(len + msglen);
|
off = (short)(len + msglen);
|
||||||
msglen += 2;
|
msglen += 2;
|
||||||
|
|
||||||
buf[(short)(len + msglen)] = crt[(short)8];
|
buf[(short)(len + msglen)] = CRT_PREFIX[(short)8];
|
||||||
++msglen;
|
++msglen;
|
||||||
buf[(short)(len + msglen)] = crt[(short)11];
|
buf[(short)(len + msglen)] = CRT_PREFIX[(short)11];
|
||||||
++msglen;
|
++msglen;
|
||||||
buf[(short)(len + msglen)] = buf[crt.length];
|
buf[(short)(len + msglen)] = buf[CRT_PREFIX.length];
|
||||||
++msglen;
|
++msglen;
|
||||||
|
|
||||||
short keydata_len = 0;
|
keylen = 0;
|
||||||
|
|
||||||
final MessageDigest digest = MessageDigest.getInstance(MessageDigest.ALG_SHA_256, false);
|
while(keylen < (short)(4 * buf[CRT_PREFIX.length])) {
|
||||||
|
|
||||||
while(keydata_len < (short)(4 * buf[crt.length])) {
|
|
||||||
Util.setShort(buf, off, counter);
|
Util.setShort(buf, off, counter);
|
||||||
++counter;
|
++counter;
|
||||||
|
|
||||||
keydata_len += digest.doFinal(buf, len, msglen,
|
keylen += digest.doFinal(buf, len, msglen,
|
||||||
buf, (short)(len + msglen + keydata_len));
|
buf, (short)(len + msglen + keylen));
|
||||||
}
|
}
|
||||||
|
|
||||||
final CmacKey sreceiptmac = new CmacKey(aesKeyLength(params));
|
initSession(Common.aesKeyLength(params), buf, (short)(len + msglen));
|
||||||
sreceiptmac.setKey(buf, (short)(len + msglen));
|
|
||||||
|
|
||||||
if(senc != null) {
|
Util.arrayFillNonAtomic(buf, len, (short)(msglen + keylen), (byte)0);
|
||||||
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);
|
|
||||||
|
|
||||||
off = len;
|
off = len;
|
||||||
Util.setShort(buf, off, (short)0x5F49);
|
Util.setShort(buf, off, (short)0x5F49);
|
||||||
@ -255,6 +255,9 @@ public final class SecureMessaging {
|
|||||||
msglen = off;
|
msglen = off;
|
||||||
|
|
||||||
epkcard.clearKey();
|
epkcard.clearKey();
|
||||||
|
epkcard = null;
|
||||||
|
|
||||||
|
ekcard = null;
|
||||||
|
|
||||||
buf[off++] = (byte)0x86;
|
buf[off++] = (byte)0x86;
|
||||||
buf[off++] = (byte)Constants.AES_BLOCK_SIZE;
|
buf[off++] = (byte)Constants.AES_BLOCK_SIZE;
|
||||||
@ -262,7 +265,6 @@ public final class SecureMessaging {
|
|||||||
macer.init(sreceiptmac);
|
macer.init(sreceiptmac);
|
||||||
macer.sign(buf, (short)0, msglen,
|
macer.sign(buf, (short)0, msglen,
|
||||||
buf, off, Constants.AES_BLOCK_SIZE);
|
buf, off, Constants.AES_BLOCK_SIZE);
|
||||||
sreceiptmac.clearKey();
|
|
||||||
macer.clear();
|
macer.clear();
|
||||||
|
|
||||||
Util.arrayCopy(buf, off, mac_chaining, (short)0, Constants.AES_BLOCK_SIZE);
|
Util.arrayCopy(buf, off, mac_chaining, (short)0, Constants.AES_BLOCK_SIZE);
|
||||||
@ -284,11 +286,7 @@ public final class SecureMessaging {
|
|||||||
clearSession(transients);
|
clearSession(transients);
|
||||||
|
|
||||||
if(isInitialized() && static_key.isEc()) {
|
if(isInitialized() && static_key.isEc()) {
|
||||||
final ECParams params = static_key.ecParams(ec);
|
return scp11b(ec, buf, len);
|
||||||
|
|
||||||
if(params != null) {
|
|
||||||
return scp11b(params, buf, len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
|
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
|
||||||
|
Loading…
Reference in New Issue
Block a user