diff options
| author | clemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2011-01-21 16:38:26 +0000 | 
|---|---|---|
| committer | clemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2011-01-21 16:38:26 +0000 | 
| commit | 7c4d1a5aff3a5ab82464affec8e0e7dcfbd2bfb3 (patch) | |
| tree | 5c51df8e737cc6b432b6c0faf57c9de733c9dcca | |
| parent | f9b44e767a43184e037fa7a16a6f5053187d41ff (diff) | |
| download | mocca-7c4d1a5aff3a5ab82464affec8e0e7dcfbd2bfb3.tar.gz mocca-7c4d1a5aff3a5ab82464affec8e0e7dcfbd2bfb3.tar.bz2 mocca-7c4d1a5aff3a5ab82464affec8e0e7dcfbd2bfb3.zip | |
git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@894 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4
3 files changed, 287 insertions, 53 deletions
| diff --git a/smccTest/src/main/java/at/gv/egiz/smcc/activation/Activation.java b/smccTest/src/main/java/at/gv/egiz/smcc/activation/Activation.java index 8d102c80..516e9487 100644 --- a/smccTest/src/main/java/at/gv/egiz/smcc/activation/Activation.java +++ b/smccTest/src/main/java/at/gv/egiz/smcc/activation/Activation.java @@ -7,8 +7,25 @@ package at.gv.egiz.smcc.activation;  import at.gv.egiz.smcc.SignatureCardException;  import at.gv.egiz.smcc.util.TLVSequence; +import iaik.asn1.ASN1; +import iaik.asn1.ASN1Object; +import iaik.asn1.CodingException; +import iaik.asn1.DerCoder; +import iaik.security.ecc.ECCException; +import iaik.security.ecc.ecdsa.ECDSAParameter; +import iaik.security.ecc.ecdsa.ECPublicKey; +import iaik.security.ecc.math.ecgroup.AffineCoordinate; +import iaik.security.ecc.math.ecgroup.CoordinateTypes; +import iaik.security.ecc.math.ecgroup.ECGroupFactory; +import iaik.security.ecc.math.ecgroup.ECPoint; +import iaik.security.ecc.math.ecgroup.EllipticCurve; +import iaik.security.ecc.math.field.FieldElement; +import iaik.security.ecc.parameter.ECCParameterFactory; +import iaik.security.ecc.spec.ECCParameterSpec; +import iaik.security.ecc.util.PointFormatter;  import iaik.security.provider.IAIK;  import java.io.UnsupportedEncodingException; +import java.math.BigInteger;  import java.nio.charset.Charset;  import java.security.GeneralSecurityException;  import java.security.InvalidAlgorithmParameterException; @@ -16,7 +33,7 @@ import java.security.InvalidKeyException;  import java.security.MessageDigest;  import java.security.NoSuchAlgorithmException;  import java.security.NoSuchProviderException; -import java.security.SignatureException; +import java.security.PublicKey;  import java.util.Arrays;  import java.util.List;  import java.util.Random; @@ -253,7 +270,52 @@ public class Activation {          resp = channel.transmit(cmdAPDU);          System.out.println(" -> " + toString(resp.getBytes()) + "\n"); -        openSecureChannel(k_qsig, cin); +//        openSecureChannel(k_qsig, cin); + +        System.out.println("READ BINARY"); +        cmdAPDU = new CommandAPDU(0x00, 0xb0, 0x00, 0x00, 256); +        System.out.println(" cmd apdu " + toString(cmdAPDU.getBytes())); +        resp = channel.transmit(cmdAPDU); +        System.out.println(" -> " + toString(resp.getBytes()) + "\n"); + +        try{ +            ASN1Object puk = DerCoder.decode(resp.getData()); +            System.out.println("EF.PuK:\n" + ASN1.print(puk)); + +            byte[] oid = (byte[]) puk.getComponentAt(1).getComponentAt(1).getValue(); +            if (oid == null || oid.length == 0) { +                System.out.println("assume P-256"); +                oid = "1.2.840.10045.3.1.7".getBytes("ASCII"); +            } + +            System.out.println("OID: " + new String(oid)); +            byte[] Q = (byte[]) puk.getComponentAt(1).getComponentAt(0).getValue(); +//            byte[] Qx = Arrays.copyOfRange(Q, 0, Q.length/2); +//            byte[] Qy = Arrays.copyOfRange(Q, Q.length/2, Q.length); +// +//            System.out.println("Qx: " + toString(Qx)); +//            System.out.println("Qy: " + toString(Qy)); + +//            ECPublicKey ecPuK = decodeECPublicKey(Q, new String(oid)); +//            System.out.println("PuK: " + ecPuK); + +        } catch (CodingException ex) { +            throw new SignatureCardException("failed to read EF.PuK", ex); +        } +        /* +        [a8:82:00:a8:b6:16:83:14:80:04:00:00:00:23:00:79:05:03:d0:40:00:00:17:00:12:01:02:00: +         7f:49: +         82:00: public exponent? +         44: +         86:40: +            d4:7c:12:55:e4:7b:0c:7d:4e:bb:17:e4:83:e5:3d:56:df:45:7e:99:cb:cc:93:d2:c2:5e:4d:91:27:6e:8b:e7: +            6d:23:53:f6:ab:2e:a6:dd:b7:1c:68:fb:59:cd:d0:45:2b:10:0e:27:00:6e:aa:1c:49:90:67:a9:9f:59:d1:97: +         c1:00:c0:01:80:9e:82:00:40:de:22:37:4c:41:e0:f7:94:9a:5a:e4:76:b8:9b:00:b8:23:7c:e9:4a +92:fd:b0:fb:25:4a:a7:0e:4d:5f:6f:3d:3a:54:28:f8:90:a1:7d:60:28:f8:72:b7:0f:9f:a6:a8:53:15:f2:9f +88:37:d4:6b:77:f7:69:c1:b9:e7:2a:43:90:00] + +         <ResponseAPDU SW="9000" rc="0" sequence="7">A88200A8B616831480040000002300789901D04000001700120102007F49820044864084BA7BF0AF355A67E0C9064EE53A63859903C775199221494A430FFAE20F3F2DC283FEF3C8EEF21FBF75448DC7DB9649BAC504DE0C6416C91D62882438128CDFC100C001809E82004087506037D74C9DCE7454A2F561A19FF24ED03D097A0CD8D45F3CB2DCF51684195632F39D72381F64BA2DCB65524C54E94265CB9E5F43EBCC02D23C1D9A02D26E</ResponseAPDU> +        */      } @@ -514,79 +576,116 @@ public class Activation {          }          System.out.println("successfully verified RND.ICC/IFD"); -         -// -//	var kicc = plain.bytes(32, 64);	// 32 -> 64 -//	keyinp = kicc.xor(kifd); -// +        // +        //	var kicc = plain.bytes(32, 64);	// 32 -> 64 +        byte[] kd_icc = Arrays.copyOfRange(plain, 32, 96); -        // TDES session key negotiation according to E-Sign K [STARCOS,6.11]? +        channel = secureChannel(kd_icc, kd_ifd); -        byte[] kd_icc = Arrays.copyOfRange(plain, 32, 96); +    } + +    SecureChannel secureChannel(byte[] kd_icc, byte[] kd_ifd) throws NoSuchAlgorithmException { + +        //	keyinp = kicc.xor(kifd); +        // +        // TDES session key negotiation according to E-Sign K [STARCOS,6.11]?          System.out.println("derive key input...");          byte[] kinp = new byte[kd_ifd.length];          for (int i = 0; i < kd_ifd.length; i++) { -          kinp[i] = (byte) (kd_icc[i] ^ kd_ifd[i]); +            kinp[i] = (byte) (kd_icc[i] ^ kd_ifd[i]);          } -          System.out.println("session key negotiation key (key seed): " + toString(kinp)); - -//	var hashin = keyinp.concat(new ByteString("00000001", HEX)); -//	var hashres = crypto.digest(Crypto.SHA_256, hashin); -//	var kencval = hashres.bytes(0, 24); -//	var kencssc = hashres.bytes(24, 8); -// -//	GPSystem.trace("Kenc         : " + kencval); -//	GPSystem.trace("Kenc SSC     : " + kencssc); -//	var kenc = new Key(); -//	kenc.setComponent(Key.DES, kencval); -// - +        //	var hashin = keyinp.concat(new ByteString("00000001", HEX)); +        //	var hashres = crypto.digest(Crypto.SHA_256, hashin); +        //	var kencval = hashres.bytes(0, 24); +        //	var kencssc = hashres.bytes(24, 8); +        // +        //	GPSystem.trace("Kenc         : " + kencval); +        //	GPSystem.trace("Kenc SSC     : " + kencssc); +        //	var kenc = new Key(); +        //	kenc.setComponent(Key.DES, kencval); +        //          MessageDigest sha256 = MessageDigest.getInstance("SHA-256");          sha256.update(kinp); -        sha256.update(new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01}); +        sha256.update(new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01});          byte[] enc_ = sha256.digest(); -          SecretKeySpec kenc = new SecretKeySpec(Arrays.copyOfRange(enc_, 0, 24), "3DES");          byte[] kencssc = Arrays.copyOfRange(enc_, 24, 32); -          System.out.println("session key kenc: " + toString(kenc.getEncoded()));          System.out.println("send sequence counter SSC_enc: " + toString(kencssc)); - -//	var hashin = keyinp.concat(new ByteString("00000002", HEX)); -//	var hashres = crypto.digest(Crypto.SHA_256, hashin); -//	var kmacval = hashres.bytes(0, 24); -//	var kmacssc = hashres.bytes(24, 8); -// -//	GPSystem.trace("Kmac         : " + kmacval); -//	GPSystem.trace("Kmac SSC     : " + kmacssc); -//	var kmac = new Key(); -//	kmac.setComponent(Key.DES, kmacval); - +        //	var hashin = keyinp.concat(new ByteString("00000002", HEX)); +        //	var hashres = crypto.digest(Crypto.SHA_256, hashin); +        //	var kmacval = hashres.bytes(0, 24); +        //	var kmacssc = hashres.bytes(24, 8); +        // +        //	GPSystem.trace("Kmac         : " + kmacval); +        //	GPSystem.trace("Kmac SSC     : " + kmacssc); +        //	var kmac = new Key(); +        //	kmac.setComponent(Key.DES, kmacval);          sha256.update(kinp); -        sha256.update(new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02}); +        sha256.update(new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x02});          enc_ = sha256.digest(); -          SecretKeySpec kmac = new SecretKeySpec(Arrays.copyOfRange(enc_, 0, 24), "3DES");          byte[] kmacssc = Arrays.copyOfRange(enc_, 24, 32); -          System.out.println("session key kmac: " + toString(kmac.getEncoded()));          System.out.println("send sequence counter SSC_mac: " + toString(kmacssc)); +        // +        //	var sc = new IsoSecureChannel(crypto); +        //	sc.setEncKey(kenc); +        //	sc.setMacKey(kmac); +        // +        //	sc.setMACSendSequenceCounter(kmacssc); +        //	sc.setEncryptionSendSequenceCounter(kencssc); +        //	return sc; +        //} + +        return new SecureChannel(channel, kenc, kmac, kencssc, kmacssc); +    } -// -//	var sc = new IsoSecureChannel(crypto); -//	sc.setEncKey(kenc); -//	sc.setMacKey(kmac); -// -//	sc.setMACSendSequenceCounter(kmacssc); -//	sc.setEncryptionSendSequenceCounter(kencssc); -//	return sc; -//} +     /** +   * Decodes the given encoded EC PublicKey according to the Octet-String-to-Point conversion +   * of ANSI X9.62 (1998), section 4.3.7. +   * <p> +   * This method is called on the client side to decode the public server key +   * contained in an ECDH ServerKeyExchange message received from the server. +   * +   * @param ecPoint the (client) public key ECPoint, encoded according to +   *                ANSI X9.62 (1998), section 4.3.6 +   * @param oid the oid of the curve +   * +   * @return the decoded public EC key +   * +   * @exception Exception if an error occurs when decoding the key +   */ +  public static ECPublicKey decodeECPublicKey(byte[] ecPoint, String oid) throws ECCException { -        channel = new SecureChannel(channel, kenc, kmac, kencssc, kmacssc); +    ECCParameterFactory pFac = ECCParameterFactory.getInstance(); +    ECCParameterSpec spec = pFac.getParameterByOID(oid); -    } +    // Now, we need an instance of elliptic curve factory +    ECGroupFactory gfac = ECGroupFactory.getInstance(); + +    BigInteger r = spec.getR(); + +    FieldElement aElement = spec.getA(); +    FieldElement bElement = spec.getB(); + +    // Now we get a curve of the form y^2 = x^3 + ax + b having order r from the +    // ECGroupFactory. We assume that the curve is non-singular. +    EllipticCurve ec = gfac.getCurve(aElement, bElement, r, CoordinateTypes.AFFINE_COORDINATES); + + +    AffineCoordinate coord = PointFormatter.getInstance().getPointCodec().decodePoint(ecPoint, ec); + +    // With these coordinates, we can construct a point on the curve. +    ECPoint point = ec.newPoint(coord); + +    ECDSAParameter params = new ECDSAParameter(spec); + +    return new ECPublicKey(params, point); + +  }      public static void main(String[] args) { diff --git a/smccTest/src/main/java/at/gv/egiz/smcc/activation/RetailCBCMac.java b/smccTest/src/main/java/at/gv/egiz/smcc/activation/RetailCBCMac.java index 79f7be62..f8cedc0e 100644 --- a/smccTest/src/main/java/at/gv/egiz/smcc/activation/RetailCBCMac.java +++ b/smccTest/src/main/java/at/gv/egiz/smcc/activation/RetailCBCMac.java @@ -123,7 +123,7 @@ public class RetailCBCMac {                         int off,                         int len,                         SecretKey key,  -                       String cipherAlg,  +                       String cipherAlg,                         int blockSize)       throws NoSuchAlgorithmException,              NoSuchProviderException,  diff --git a/smccTest/src/main/java/at/gv/egiz/smcc/activation/SecureChannel.java b/smccTest/src/main/java/at/gv/egiz/smcc/activation/SecureChannel.java index 303b1b68..9bbd39fb 100644 --- a/smccTest/src/main/java/at/gv/egiz/smcc/activation/SecureChannel.java +++ b/smccTest/src/main/java/at/gv/egiz/smcc/activation/SecureChannel.java @@ -6,6 +6,13 @@  package at.gv.egiz.smcc.activation;  import java.nio.ByteBuffer; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.util.Arrays; +import java.util.logging.Level; +import java.util.logging.Logger;  import javax.crypto.spec.SecretKeySpec;  import javax.smartcardio.Card;  import javax.smartcardio.CardChannel; @@ -49,7 +56,17 @@ public class SecureChannel extends CardChannel {      @Override      public ResponseAPDU transmit(CommandAPDU capdu) throws CardException { -        return basicChannel.transmit(capdu); +        try { +            kmacssc[7] += 1; +            System.out.println("incrementing kmac_ssc: " + toString(kmacssc)); +            System.out.println("kmac: " + toString(kmac.getEncoded())); +            CommandAPDU capdu_ = new CommandAPDU(protectAPDU(capdu.getBytes())); +            System.out.println(" cmd apdu* " + toString(capdu_.getBytes())); +            return basicChannel.transmit(capdu_); +        } catch (Exception ex) { +            System.out.println("failed to transmit protected APDU: " + ex.getMessage()); +            throw new CardException(ex); +        }      }      @Override @@ -62,4 +79,122 @@ public class SecureChannel extends CardChannel {          throw new UnsupportedOperationException("Not supported yet.");      } +    /** +     * +     * @param apdu +     * @return +     * @throws IllegalArgumentException +     */ +    protected byte[] protectAPDU(byte[] apdu) throws IllegalArgumentException, InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, GeneralSecurityException { + +        byte[] apdu_ = null; +        byte[] mac_in = null; +        int i_mac = 0; + +        if (apdu.length < 4) { +            throw new IllegalArgumentException("invalid Command APDU " + toString(apdu)); +        } else if (apdu.length == 4) { +            // no command data, no response data, status not protected +            // CLA|INS|P1|P2            -> CLA'|INS|P1|P2|Lc'|TLmac +            apdu_ = new byte[15]; + +            // authenticate header: CLA* b3=1 +            apdu_[0] = (byte) (apdu[0] | (byte) 0x0c); // CLA*: b8-6=000 b4-3=11 +            apdu_[1] = apdu[1]; +            apdu_[2] = apdu[2]; +            apdu_[3] = apdu[3]; +             +            // Lc': TLmac (blocksize=8) +            apdu_[4] = (byte) 0x0a; +            // cryptographic checksum +            apdu_[5] = (byte) 0x8e; +            apdu_[6] = (byte) 0x08; +            i_mac = 7; + +            // 2 data objects: SSC, header +            mac_in = new byte[2*8]; + +            //TODO increment SSC +            System.arraycopy(kmacssc, 0, mac_in, 0, 8); +             +            // CLA** INS P1 P2 padding +            byte[] header_ = RetailCBCMac.pad(Arrays.copyOf(apdu_, 4), 8); +            System.arraycopy(header_, 0, mac_in, 8, 8); + +            System.out.println("data covered by cryptographic checksum: " + toString(mac_in)); +             +        } else if (apdu.length == 5) { +            // CLA|INS|P1|P2|Le         -> CLA'|INS|P1|P2|Lc'|TLle|TLmac|00 +            // no command data, response data +            apdu_ = new byte[19]; + +            // authenticate header: CLA* b3=1 +            apdu_[0] = (byte) (apdu[0] | (byte) 0x0c); // CLA*: b8-6=000 b4-3=11 +            apdu_[1] = apdu[1]; +            apdu_[2] = apdu[2]; +            apdu_[3] = apdu[3]; + +            // Lc': TLle TLmac +            apdu_[4] = (byte) 0x0d; + +            // Ne +            apdu_[5] = (byte) 0x97; +            apdu_[6] = (byte) 0x01; +            apdu_[7] = apdu[4]; + +            // cryptographic checksum +            apdu_[8] = (byte) 0x8e; +            apdu_[9] = (byte) 0x08; +            i_mac = 10; +            apdu_[18] = 0x00; + +            // 3 data objects: SSC, header, Le +            mac_in = new byte[3*8]; + +            //TODO increment SSC +            System.arraycopy(kmacssc, 0, mac_in, 0, 8); + +            // CLA** INS P1 P2 padding +            byte[] header_ = RetailCBCMac.pad(Arrays.copyOf(apdu_, 4), 8); +            System.arraycopy(header_, 0, mac_in, 8, 8); + +            System.arraycopy(RetailCBCMac.pad(Arrays.copyOfRange(apdu_, 5, 8), 8), 0, mac_in, 16, 8); +            System.out.println("data covered by cryptographic checksum: " + toString(mac_in)); + + +        } else if (apdu.length == 5 + apdu[4]){ +            // CLA|INS|P1|P2|Lc|Data    -> CLA'|INS|P1|P2|Lc'|TLplain|TLmac +            // 81 (plain value) 8e (cryptographic checksum) + +        } else { +            // CLA|INS|P1|P2|Lc|Data|Le -> CLA'|INS|P1|P2|Lc'|TLplain|TLle|TLmac|00 +            // 81 (plain value) 97 (Ne) 8e (cryptographic checksum) +             +            // TODO extended APDUs + +        } + + +        byte[] mac = RetailCBCMac.retailMac(mac_in, "DES", "DESede", kmac, 8, 8); +        System.out.println("mac: " + toString(mac)); +        System.arraycopy(mac, 0, apdu_, i_mac, 8); +        return apdu_; + +    } + +    public static String toString(byte[] b) { +        StringBuilder sb = new StringBuilder(); +        sb.append('['); +        if (b != null && b.length > 0) { +            sb.append(Integer.toHexString((b[0] & 240) >> 4)); +            sb.append(Integer.toHexString(b[0] & 15)); +            for (int i = 1; i < b.length; i++) { +                sb.append((i % 32 == 0) ? '\n' : ':'); +                sb.append(Integer.toHexString((b[i] & 240) >> 4)); +                sb.append(Integer.toHexString(b[i] & 15)); +            } +        } +        sb.append(']'); +        return sb.toString(); +    }  } | 
