diff options
| -rw-r--r-- | smccTest/src/main/java/at/gv/egiz/smcc/activation/Activation.java | 63 | ||||
| -rw-r--r-- | smccTest/src/main/java/at/gv/egiz/smcc/activation/SecureChannel.java | 102 | 
2 files changed, 130 insertions, 35 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 6a40faa3..d659cc7c 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 @@ -166,10 +166,16 @@ public class Activation {          (byte) 0xd0, (byte) 0x40, (byte) 0x00, (byte) 0x00, (byte) 0x17,          (byte) 0x00, (byte) 0x12, (byte) 0x01}; -    private final static byte[] ZEROS = { +    public final static byte[] ZEROS = {          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00      }; +		public final static byte[] ONES = { +        (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, +				(byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11 +    }; + +      /** Bit mask for counting the ones. */      private final static byte[] BIT_MASK = {          0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, (byte) 0x80 @@ -305,6 +311,25 @@ public class Activation {              throw new SignatureCardException("failed to read EF.PuK", ex);          } + +				System.out.println("DUMMY APDU SELECT EF_C_X509.CH.DS"); +        cmdAPDU = new CommandAPDU(0x00, 0xA4, 0x02, 0x00, new byte[]{(byte) 0xc0, (byte) 0x00}, 256); +        System.out.println(" cmd apdu " + toString(cmdAPDU.getBytes())); +        resp = channel.transmit(cmdAPDU); +        System.out.println(" -> " + toString(resp.getBytes()) + "\n"); + +				System.out.println("DUMMY APDU 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"); + +//				System.out.println("DELETE EF_C_X509.CH.DS *****************************"); +//        cmdAPDU = new CommandAPDU(0x00, 0xE4, 0x02, 0x00, new byte[]{(byte) 0xC0, (byte) 0x00}); +//        System.out.println(" cmd apdu " + toString(cmdAPDU.getBytes())); +//        resp = channel.transmit(cmdAPDU); +//        System.out.println(" -> " + toString(resp.getBytes()) + "\n"); +          /*          [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: @@ -319,8 +344,6 @@ public class Activation {           <ResponseAPDU SW="9000" rc="0" sequence="7">A88200A8B616831480040000002300789901D04000001700120102007F49820044864084BA7BF0AF355A67E0C9064EE53A63859903C775199221494A430FFAE20F3F2DC283FEF3C8EEF21FBF75448DC7DB9649BAC504DE0C6416C91D62882438128CDFC100C001809E82004087506037D74C9DCE7454A2F561A19FF24ED03D097A0CD8D45F3CB2DCF51684195632F39D72381F64BA2DCB65524C54E94265CB9E5F43EBCC02D23C1D9A02D26E</ResponseAPDU>          */ - -        // TODO      } @@ -701,6 +724,7 @@ public class Activation {        test.setUp();        test.activate();  //      test.testMACProtection(); +//      test.testENCProtection();      } catch (Exception e) {          e.printStackTrace();      } @@ -761,7 +785,7 @@ hashres      : 4D BF FC AD 67 94 55 F9 7F DD 47 30 C7 74 B1 7D CF B8 B3 74 93 87          } -				byte[] case2apdu = channel.protectNoCommandData(new byte[] { (byte)0x00, (byte)0xb0, (byte)0x00, (byte)0x00, (byte)0xdf }, true); +				byte[] case2apdu = channel.protectNoCommandData(new byte[] { (byte)0x00, (byte)0xb0, (byte)0x00, (byte)0x00, (byte)0xdf });  				System.out.println("apdu orig:   " + toString(apdu_));  				System.out.println("apdu test:   " + toString(case2apdu)); @@ -773,12 +797,41 @@ hashres      : 4D BF FC AD 67 94 55 F9 7F DD 47 30 C7 74 B1 7D CF B8 B3 74 93 87  				byte[] case3apdu = channel.protectCommandData(new byte[] { (byte)0x00, (byte)0x10, (byte)0x20, (byte)0x30, (byte)0x04, (byte)0x41, (byte)0x042, (byte)0x43, (byte)0x44 }, false);  				System.out.println("apdu test:   " + toString(case3apdu)); -				case3apdu = channel.protectCommandData(new byte[] { (byte)0x00, (byte)0x10, (byte)0x20, (byte)0x30, (byte)0x04, (byte)0x41, (byte)0x042, (byte)0x43, (byte)0x44, (byte)0x80 }, true); +				case3apdu = channel.protectCommandData(new byte[] { (byte)0x00, (byte)0x10, (byte)0x20, (byte)0x30, (byte)0x04, (byte)0x41, (byte)0x042, (byte)0x43, (byte)0x44, (byte)0x80 }, false);  				System.out.println("apdu test:   " + toString(case3apdu));      } + +		/** +     * sniffed values (cf. activate-800400...790503.log lines 125-136, hashres = kenc | kencssc +     * and apdu_ from activate activate-800400...790503-apdu.log lines 96(corresponding challenge) +     */ + +		static final byte[] kenc = new byte[] { (byte)0x15, (byte)0xC7, (byte)0x63, (byte)0x2B, (byte)0xB7, (byte)0xBB, (byte)0x00, (byte)0x53, (byte)0xFA, (byte)0x3F, (byte)0xAC, (byte)0x2B, (byte)0x9B, (byte)0x59, (byte)0xCF, (byte)0xC3, (byte)0x04, (byte)0x50, (byte)0x51, (byte)0xE8, (byte)0x62, (byte)0xE8, (byte)0xD3, (byte)0xEE }; +    static final byte[] kencssc = new byte[] { (byte)0x62, (byte)0x82, (byte)0xA5, (byte)0xBA, (byte)0xB2, (byte)0xDD, (byte)0x25, (byte)0x50 }; +		static final byte[] kmac = new byte[] { (byte)0xD4, (byte)0x0B, (byte)0x7F, (byte)0x7E, (byte)0x9B, (byte)0x45, (byte)0x8C, (byte)0x39, (byte)0x80, (byte)0x8E, (byte)0x5B, (byte)0x2B, (byte)0x63, (byte)0x4B, (byte)0x0F, (byte)0xC4, (byte)0x0D, (byte)0xEE, (byte)0xB7, (byte)0x6D, (byte)0xC9, (byte)0xC1, (byte)0xFD, (byte)0xE9 }; +    static final byte[] kmacssc = new byte[] { (byte)0x3E, (byte)0x09, (byte)0x6C, (byte)0x86, (byte)0xB4, (byte)0xBB, (byte)0x9F, (byte)0x30 }; +    static final byte[] apduEnc_ = new byte[] { (byte) 0x0C, (byte)0xE4, (byte)0x02, (byte)0x00, (byte)0x15, (byte)0x87, (byte)0x09, (byte)0x01, (byte)0xB9, (byte)0x5A, (byte)0xCA, (byte)0xA5, (byte)0x69, (byte)0x55, (byte)0x46, (byte)0x56, (byte)0x8E, (byte)0x08, (byte)0x40, (byte)0x7D, (byte)0xEA, (byte)0xC4, (byte)0x30, (byte)0xE6, (byte)0xCF, (byte)0x94, (byte)0x00 }; + +		public void testENCProtection() throws GeneralSecurityException { + +			SecureChannel sc = new SecureChannel(channel,  +							new SecretKeySpec(kenc, "3DES"), new SecretKeySpec(kmac, "3DES"), +							8, kencssc, kmacssc); + +			byte[] apdu = new byte[] { (byte) 0x00, (byte) 0xe4, (byte) 0x02, (byte) 0x00, (byte) 0x02, (byte) 0xc0, (byte) 0x00 }; +		  System.out.println("apdu test:    " + toString(apdu)); +			byte[] apduTest = sc.protectCommandData(apdu, true); +			System.out.println("encrypt:      " + toString(apduTest)); + +			if (!Arrays.equals(apduEnc_, apduTest)) { +				System.out.println("************************************************** ERRROR "); +			} + +		} +  		public static final byte[] SM_RESP_APDU = new byte[] {  			(byte)0x81, (byte)0x81, (byte)0xac, (byte)0xa8, (byte)0x82, (byte)0x00, (byte)0xa8, (byte)0xb6, (byte)0x16, (byte)0x83, (byte)0x14, (byte)0x80, (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x23, (byte)0x00, (byte)0x79, (byte)0x05, (byte)0x03, (byte)0xd0, (byte)0x40, (byte)0x00, (byte)0x00, (byte)0x17, (byte)0x00, (byte)0x12, (byte)0x01, (byte)0x02, (byte)0x00, (byte)0x7f,  			(byte)0x49, (byte)0x82, (byte)0x00, (byte)0x44, (byte)0x86, (byte)0x40, (byte)0xd4, (byte)0x7c, (byte)0x12, (byte)0x55, (byte)0xe4, (byte)0x7b, (byte)0x0c, (byte)0x7d, (byte)0x4e, (byte)0xbb, (byte)0x17, (byte)0xe4, (byte)0x83, (byte)0xe5, (byte)0x3d, (byte)0x56, (byte)0xdf, (byte)0x45, (byte)0x7e, (byte)0x99, (byte)0xcb, (byte)0xcc, (byte)0x93, (byte)0xd2, (byte)0xc2, (byte)0x5e, 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 f8f679e2..d297bbd5 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 @@ -4,15 +4,18 @@   */  package at.gv.egiz.smcc.activation; -import at.gv.egiz.smcc.DNIeCryptoUtil;  import at.gv.egiz.smcc.util.TLVSequence;  import java.nio.ByteBuffer;  import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException;  import java.security.InvalidKeyException; -import java.security.MessageDigest;  import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException;  import java.util.Arrays; +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec;  import javax.crypto.spec.SecretKeySpec;  import javax.smartcardio.Card;  import javax.smartcardio.CardChannel; @@ -93,7 +96,7 @@ public class SecureChannel extends CardChannel {  				throw new IllegalArgumentException("invalid Command APDU " + toString(apdu));  			} else if (apdu.length < 6) {  				CommandAPDU capdu_ = new CommandAPDU( -								protectNoCommandData(apdu, apdu.length == 5)); +								protectNoCommandData(apdu));  				log.info("cmd apdu*: {}", toString(capdu_.getBytes()));  				ResponseAPDU resp_ = channel.transmit(capdu_);  				log.info(" -> resp*: {}", toString(resp_.getBytes())); @@ -101,7 +104,7 @@ public class SecureChannel extends CardChannel {  			} else {  				CommandAPDU capdu_ = new CommandAPDU( -								protectCommandData(apdu, apdu.length > 5+apdu[4])); +								protectCommandData(apdu, true));  				log.info("cmd apdu*: {}", toString(capdu_.getBytes()));  				ResponseAPDU resp_ = channel.transmit(capdu_);  				log.info(" -> resp*: {}", toString(resp_.getBytes())); @@ -126,7 +129,6 @@ public class SecureChannel extends CardChannel {  	/**  	 * Case 1b/2 of command-response pair defined in ISO 7816-3 -	 * no command data, response data  	 *  	 * CLA|INS|P1|P2    -> CLA'|INS|P1|P2|Lc'|TLmac|00  	 * CLA|INS|P1|P2|Le -> CLA'|INS|P1|P2|Lc'|TLle|TLmac|00 @@ -135,9 +137,10 @@ public class SecureChannel extends CardChannel {  	 * @return  	 * @throws GeneralSecurityException mac-calculation error  	 */ -	byte[] protectNoCommandData(byte[] apdu, boolean responseData) throws GeneralSecurityException { +	byte[] protectNoCommandData(byte[] apdu) throws GeneralSecurityException { -		int leLength = (responseData) ? 1 : 0; +		// whether Le Byte is present (response expected) +		int leLength = (apdu.length == 5) ? 1 : 0;  		byte[] apdu_ = new byte[16 + 3*leLength];  		// authenticate header: CLA** b3=1 @@ -150,7 +153,7 @@ public class SecureChannel extends CardChannel {  		apdu_[4] = (byte) (3*leLength + 2 + blocksize); //0x0a or 0x0d;  		// T*L Le -		if (responseData) { +		if (leLength > 0) {  			apdu_[5] = (byte) 0x97;  			apdu_[6] = (byte) 0x01;  			apdu_[7] = apdu[4]; @@ -175,7 +178,7 @@ public class SecureChannel extends CardChannel {  		System.arraycopy(paddedHeader, 0, mac_in, blocksize, blocksize);  		// TL Le -		if (responseData) { +		if (leLength > 0) {  			byte[] paddedTLLe = RetailCBCMac.pad(Arrays.copyOfRange(apdu_, 5, 8), blocksize);  			System.arraycopy(paddedTLLe, 0, mac_in, 2*blocksize, blocksize);  		} @@ -252,7 +255,6 @@ public class SecureChannel extends CardChannel {  	/**  	 * Case 3b/4 of command-response pair defined in ISO 7816-3 -	 * command data, no response data  	 *  	 * CLA|INS|P1|P2|Lc|Data -> CLA'|INS|P1|P2|Lc'|TLplain|TLmac|00  	 * CLA|INS|P1|P2|Lc|Data|Le -> CLA'|INS|P1|P2|Lc'|TLplain|TLle|TLmac|00 @@ -261,12 +263,23 @@ public class SecureChannel extends CardChannel {  	 * @return  	 * @throws GeneralSecurityException mac-calculation error  	 */ -	byte[] protectCommandData(byte[] apdu, boolean responseData) throws GeneralSecurityException { +	byte[] protectCommandData(byte[] apdu, boolean encrypt) throws GeneralSecurityException { -		int leLength = (responseData) ? 1 : 0; +		int contentLength = apdu[4]; +		byte[] cryptogram = null; -		// header | Lc' | TLplain | [TLLe] | TLmac | 00 -		byte[] apdu_= new byte[4 + 1 + 2+apdu[4] + 3*leLength + 2+blocksize + 1]; +		// whether Le Byte is present (response expected) +		int leLength = (apdu.length > 5+contentLength) ? 1 : 0; + +		if (encrypt) { +			cryptogram = encrypt(Arrays.copyOfRange(apdu, 5, 5+apdu[4])); +			contentLength = cryptogram.length + 1; // + padding-content indicator byte +			log.info("cryptogram (" + cryptogram.length + "byte): " +							+ toString(cryptogram)); +		} + +		// header | Lc' | TLplain(TL-P-cryptogram) | [TLLe] | TLmac | 00 +		byte[] apdu_= new byte[4 + 1 + 2+contentLength + 3*leLength + 2+blocksize + 1];  		// authenticate header: CLA** b3=1  		apdu_[0] = (byte) (apdu[0] | (byte) 0x0c); //CLA**: b8-6=000 b4-3=11 @@ -275,29 +288,38 @@ public class SecureChannel extends CardChannel {  		apdu_[3] = apdu[3];  		// Lc': TLplain [TLLe] TLmac -		apdu_[4] = (byte) (2+apdu[4] + 3*leLength +  2+blocksize); - -		// T*L plain -		apdu_[5] = (byte) 0x81; -		apdu_[6] = apdu[4]; -		System.arraycopy(apdu, 5, apdu_, 7, apdu[4]); +		apdu_[4] = (byte) (2+contentLength + 3*leLength +  2+blocksize); + +		if (encrypt) { +			// T*L paddingIndicatorByte crpytogram +			apdu_[5] = (byte) 0x87; +			apdu_[6] = (byte) contentLength; +			apdu_[7] = (byte) 0x01; +			System.arraycopy(cryptogram, 0, apdu_, 8, cryptogram.length); +			 +		} else { +			// T*L plain +			apdu_[5] = (byte) 0x81; +			apdu_[6] = apdu[4]; +			System.arraycopy(apdu, 5, apdu_, 7, apdu[4]); +		}  		// T*L Le -		if (responseData) { -			apdu_[7+apdu[4]] = (byte) 0x97; -			apdu_[8+apdu[4]] = (byte) 0x01; -			apdu_[9+apdu[4]] = apdu[apdu.length-1]; +		if (leLength > 0) { +			apdu_[7+contentLength] = (byte) 0x97; +			apdu_[8+contentLength] = (byte) 0x01; +			apdu_[9+contentLength] = apdu[apdu.length-1];  		}  		// TL cc -		apdu_[7 + apdu[4] + 3*leLength] = (byte) 0x8e; -		apdu_[8 + apdu[4] + 3*leLength] = (byte) blocksize; //0x08; +		apdu_[7 + contentLength + 3*leLength] = (byte) 0x8e; +		apdu_[8 + contentLength + 3*leLength] = (byte) blocksize; //0x08;  		apdu_[apdu_.length-1] = (byte) 0x00;  		// TLplain [TLLe] Padding  		byte[] paddedPlainLe = RetailCBCMac.pad( -						Arrays.copyOfRange(apdu_, 5, 5+2+apdu[4] + 3*leLength), blocksize); +						Arrays.copyOfRange(apdu_, 5, 5+2+contentLength + 3*leLength), blocksize);  		log.trace("padded plain command data: " + toString(paddedPlainLe));  		// 3 blocks: SSC, header|padding, TLplain[TLLe]|padding @@ -319,15 +341,35 @@ public class SecureChannel extends CardChannel {  		log.debug("cryptographic checksum ({}): {}", toString(mac_in), toString(mac));  		// insert mac in 8E object -		System.arraycopy(mac, 0, apdu_, 9 + apdu[4] + 3*leLength, blocksize); +		System.arraycopy(mac, 0, apdu_, 9 + contentLength + 3*leLength, blocksize);  		return apdu_;  	} +	byte[] encrypt(byte[] plain) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { + +		incrementKENCSSC(); + +		Cipher tDES = Cipher.getInstance("3DES/CBC/NoPadding"); +		tDES.init(Cipher.ENCRYPT_MODE, kenc, new IvParameterSpec(kencssc)); //Activation.ZEROS)); + +		byte[] paddedPlain = RetailCBCMac.pad(plain, blocksize); +		 +		log.info("cryptogram input (" + paddedPlain.length + "byte): " +						+ toString(paddedPlain)); + +		return tDES.doFinal(paddedPlain); +	}  	void incrementSSC() {  		//TODO  		kmacssc[7] += 1; -		System.out.println(" [SC] incrementing kmac_ssc: " + toString(kmacssc)); +		log.info("incrementing kmac_ssc: " + toString(kmacssc)); +	} + +	void incrementKENCSSC() { +		//TODO +		kencssc[7] += 1; +		log.debug("incrementing kenc_ssc: " + toString(kencssc));  	}  	public static String toString(byte[] b) { | 
