diff --git a/src/fr/anssi/smartpgp/CmacKey.java b/src/fr/anssi/smartpgp/CmacKey.java index bd060e4..7c3fb7c 100644 --- a/src/fr/anssi/smartpgp/CmacKey.java +++ b/src/fr/anssi/smartpgp/CmacKey.java @@ -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); diff --git a/src/fr/anssi/smartpgp/CmacSignature.java b/src/fr/anssi/smartpgp/CmacSignature.java index 8460b39..9e8e5f8 100644 --- a/src/fr/anssi/smartpgp/CmacSignature.java +++ b/src/fr/anssi/smartpgp/CmacSignature.java @@ -51,7 +51,12 @@ public final class CmacSignature { } protected final void clear() { - key = null; + if(key != null) { + if(key.isInitialized()) { + key.clearKey(); + } + key = null; + } } private final byte blockLen() { diff --git a/src/fr/anssi/smartpgp/Common.java b/src/fr/anssi/smartpgp/Common.java index b78db07..5a822d5 100644 --- a/src/fr/anssi/smartpgp/Common.java +++ b/src/fr/anssi/smartpgp/Common.java @@ -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; diff --git a/src/fr/anssi/smartpgp/SecureMessaging.java b/src/fr/anssi/smartpgp/SecureMessaging.java index 3f90ae2..bb84188 100644 --- a/src/fr/anssi/smartpgp/SecureMessaging.java +++ b/src/fr/anssi/smartpgp/SecureMessaging.java @@ -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) { - cipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false); - - macer = new CmacSignature(); - - iv = JCSystem.makeTransientByteArray(Constants.AES_BLOCK_SIZE, - JCSystem.CLEAR_ON_DESELECT); - - mac_chaining = JCSystem.makeTransientByteArray(Constants.AES_BLOCK_SIZE, - JCSystem.CLEAR_ON_DESELECT); - - senc = null; - smac = null; - srmac = null; + 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); + 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); + sreceiptmac = null; + smac = null; + srmac = null; + 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, - params.nb_bits, - false); - final ECPublicKey epkcard = (ECPublicKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PUBLIC, - params.nb_bits, - false); + ECPrivateKey eskcard = (ECPrivateKey)KeyBuilder.buildKey(KeyBuilder.TYPE_EC_FP_PRIVATE, + params.nb_bits, + false); + 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);