private static byte[] Mac_des_3des(GPKey key, byte[] text, int offset, int length, byte[] iv) { if (length == -1) { length = text.Length - offset; } try { //Cipher cipher1 = Cipher.getInstance(DES_CBC_CIPHER); //cipher1.init(Cipher.ENCRYPT_MODE, key.getKey(Type.DES), new IvParameterSpec(iv)); //Cipher cipher2 = Cipher.getInstance(DES3_CBC_CIPHER); //cipher2.init(Cipher.ENCRYPT_MODE, key.getKey(Type.DES3), new IvParameterSpec(iv)); byte[] result = Arrays.Clone(iv); byte[] temp; if (length > 8) { temp = GPCrypto.DoEncrypt_DES_CBC(key.GetKey(KeyType.DES).GetEncoded(), text, offset, length - 8, iv); Array.Copy(temp, temp.Length - 8, result, 0, 8); } temp = GPCrypto.DoEncrypt_DES3_CBC(key.GetKey(KeyType.DES3).GetEncoded(), text, (offset + length) - 8, 8, result); Array.Copy(temp, temp.Length - 8, result, 0, 8); return(result); } catch (Exception e) { //e.printStackTrace(); throw new Exception("MAC computation failed.", e); } }
public static GPKeySet Diversify(GPKeySet keys, byte[] diversification_data, Diversification mode, int scp) { try { GPKeySet result = new GPKeySet(); //Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding"); foreach (KeySessionType v in KeyTypeList.Values) { if (v == KeySessionType.RMAC) { continue; } byte[] kv = null; // shift around and fill initialize update data as required. if (mode == Diversification.VISA2) { kv = FillVisa(diversification_data, v); } else if (mode == Diversification.EMV) { kv = FillEmv(diversification_data, v); } // Encrypt with current master key //cipher.init(Cipher.ENCRYPT_MODE, keys.getKey(v).getKey(Type.DES3)); //byte[] keybytes = cipher.doFinal(kv); byte[] keybytes = GPCrypto.DoEncrypt_DES3_ECB(keys.GetKey(v).GetKey(KeyType.DES3).GetEncoded(), kv); // Replace the key, possibly changing type. G&D SCE 6.0 uses EMV 3DES and resulting keys // must be interpreted as AES-128 GPKey nk = new GPKey(keybytes, scp == 3 ? KeyType.AES : KeyType.DES3); result.SetKey(v, nk); } return(result); } //catch (BadPaddingException e) //{ // throw new Exception("Diversification failed.", e); //} //catch (InvalidKeyException e) //{ // throw new Exception("Diversification failed.", e); //} //catch (IllegalBlockSizeException e) //{ // throw new Exception("Diversification failed.", e); //} //catch (NoSuchAlgorithmException e) //{ // throw new Exception("Diversification failed.", e); //} //catch (NoSuchPaddingException e) //{ // throw new Exception("Diversification failed.", e); //} catch (Exception e) { throw new Exception("Diversification failed.", e); } }
private GPKeySet DeriveSessionKeysSCP01(GPKeySet staticKeys, byte[] host_challenge, byte[] card_challenge) { GPKeySet sessionKeys = new GPKeySet(); byte[] derivationData = new byte[16]; Array.Copy(card_challenge, 4, derivationData, 0, 4); Array.Copy(host_challenge, 0, derivationData, 4, 4); Array.Copy(card_challenge, 0, derivationData, 8, 4); Array.Copy(host_challenge, 4, derivationData, 12, 4); try { //Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding"); foreach (KeySessionType v in KeyTypeList.Values) { if (v == KeySessionType.RMAC) // skip RMAC key { continue; } //cipher.init(Cipher.ENCRYPT_MODE, staticKeys.getKeyFor(v)); //GPKey nk = new GPKey(cipher.doFinal(derivationData), Type.DES3); byte[] result = GPCrypto.DoEncrypt_DES3_ECB(staticKeys.GetKeyFor(v).GetEncoded(), derivationData); GPKey nk = new GPKey(result, KeyType.DES3); sessionKeys.SetKey(v, nk); } // KEK is the same sessionKeys.SetKey(KeySessionType.KEK, staticKeys.GetKey(KeySessionType.KEK)); return(sessionKeys); } //catch (NoSuchAlgorithmException e) //{ // throw new IllegalStateException("Session keys calculation failed.", e); //} //catch (NoSuchPaddingException e) //{ // throw new IllegalStateException("Session keys calculation failed.", e); //} //catch (InvalidKeyException e) //{ // throw new RuntimeException("Session keys calculation failed.", e); //} //catch (IllegalBlockSizeException e) //{ // throw new RuntimeException("Session keys calculation failed.", e); //} //catch (BadPaddingException e) //{ // throw new RuntimeException("Session keys calculation failed.", e); //} catch (Exception e) { throw new Exception("Session keys calculation failed.", e); } }
private static byte[] Scp03_key_check_value(GPKey key) { try { byte[] cv = GPCrypto.DoEncrypt_AES_CBC(key.GetKey().GetEncoded(), GPCrypto.one_bytes_16); //Cipher c = Cipher.getInstance(AES_CBC_CIPHER); //c.init(Cipher.ENCRYPT_MODE, key.getKey(), iv_null_aes); //byte[] cv = c.doFinal(one_bytes_16); return(Arrays.CopyOfRange(cv, 0, 3)); } catch (Exception e) { throw new Exception("Could not calculate key check value: ", e); } }
private static byte[] Scp03_encrypt_key(GPKey kek, GPKey key) { try { // Pad with random int n = key.GetLength() % 16 + 1; byte[] plaintext = new byte[n * 16]; SecureRandom sr = new SecureRandom(); sr.NextBytes(plaintext); Array.Copy(key.GetValue(), 0, plaintext, 0, key.GetValue().Length); // encrypt byte[] cgram = GPCrypto.DoEncrypt_AES_CBC(kek.GetValue(), plaintext); //Cipher c = Cipher.getInstance(AES_CBC_CIPHER); //c.init(Cipher.ENCRYPT_MODE, kek.GetEncoded(), null_bytes_16); //byte[] cgram = c.doFinal(plaintext); return(cgram); } catch (Exception e) { throw new Exception("Could not calculate key check value: ", e); } }
private static byte[] Mac_3des(ISecretKey key, byte[] text, int offset, int length, byte[] iv) { if (length == -1) { length = text.Length - offset; } try { //Cipher cipher = Cipher.getInstance(DES3_CBC_CIPHER); //cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); //byte[] res = cipher.doFinal(text, offset, length); byte[] res = GPCrypto.DoEncrypt_DES3_CBC(key.GetEncoded(), text, offset, length, iv); byte[] result = new byte[8]; Array.Copy(res, res.Length - 8, result, 0, 8); return(result); } catch (Exception e) { throw new Exception("MAC computation failed.", e); } }
private GPKeySet DeriveSessionKeysSCP02(GPKeySet staticKeys, byte[] sequence, bool implicitChannel) { GPKeySet sessionKeys = new GPKeySet(); try { //Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding"); byte[] derivationData = new byte[16]; Array.Copy(sequence, 0, derivationData, 2, 2); byte[] constantMAC = new byte[] { (byte)0x01, (byte)0x01 }; Array.Copy(constantMAC, 0, derivationData, 0, 2); //cipher.init(Cipher.ENCRYPT_MODE, staticKeys.getKeyFor(KeySessionType.MAC), GPCrypto.iv_null_des); //GPKey nk = new GPKey(cipher.doFinal(derivationData), Type.DES3); byte[] result = GPCrypto.DoEncrypt_DES3_CBC(staticKeys.GetKeyFor(KeySessionType.MAC).GetEncoded(), derivationData); GPKey nk = new GPKey(result, KeyType.DES3); sessionKeys.SetKey(KeySessionType.MAC, nk); // TODO: is this correct? - increment by one for all other than C-MAC if (implicitChannel) { Buffer_increment(derivationData, 2, 2); } byte[] constantRMAC = new byte[] { (byte)0x01, (byte)0x02 }; Array.Copy(constantRMAC, 0, derivationData, 0, 2); //cipher.init(Cipher.ENCRYPT_MODE, staticKeys.getKeyFor(KeySessionType.MAC), GPCrypto.iv_null_des); //nk = new GPKey(cipher.doFinal(derivationData), Type.DES3); byte[] result2 = GPCrypto.DoEncrypt_DES3_CBC(staticKeys.GetKeyFor(KeySessionType.MAC).GetEncoded(), derivationData); nk = new GPKey(result2, KeyType.DES3); sessionKeys.SetKey(KeySessionType.RMAC, nk); byte[] constantENC = new byte[] { (byte)0x01, (byte)0x82 }; Array.Copy(constantENC, 0, derivationData, 0, 2); //cipher.init(Cipher.ENCRYPT_MODE, staticKeys.getKeyFor(KeySessionType.ENC), GPCrypto.iv_null_des); //nk = new GPKey(cipher.doFinal(derivationData), Type.DES3); byte[] result3 = GPCrypto.DoEncrypt_DES3_CBC(staticKeys.GetKeyFor(KeySessionType.ENC).GetEncoded(), derivationData); nk = new GPKey(result3, KeyType.DES3); sessionKeys.SetKey(KeySessionType.ENC, nk); byte[] constantDEK = new byte[] { (byte)0x01, (byte)0x81 }; Array.Copy(constantDEK, 0, derivationData, 0, 2); //cipher.init(Cipher.ENCRYPT_MODE, staticKeys.getKeyFor(KeySessionType.KEK), GPCrypto.iv_null_des); //nk = new GPKey(cipher.doFinal(derivationData), Type.DES3); byte[] result4 = GPCrypto.DoEncrypt_DES3_CBC(staticKeys.GetKeyFor(KeySessionType.KEK).GetEncoded(), derivationData); nk = new GPKey(result4, KeyType.DES3); sessionKeys.SetKey(KeySessionType.KEK, nk); return(sessionKeys); } //catch (NoSuchAlgorithmException e) //{ // throw new IllegalStateException("Session keys calculation failed.", e); //} //catch (NoSuchPaddingException e) //{ // throw new IllegalStateException("Session keys calculation failed.", e); //} //catch (InvalidKeyException e) //{ // throw new RuntimeException("Session keys calculation failed.", e); //} //catch (IllegalBlockSizeException e) //{ // throw new RuntimeException("Session keys calculation failed.", e); //} //catch (BadPaddingException e) //{ // throw new RuntimeException("Session keys calculation failed.", e); //} //catch (InvalidAlgorithmParameterException e) //{ // throw new RuntimeException("Session keys calculation failed.", e); //} catch (Exception e) { throw new Exception("Session keys calculation failed.", e); } }
public override byte[] Wrap(GPCommand command) { byte[] cmd_mac = null; try { if (!mac && !enc) { return(command.Serialize()); } int cla = command.CLA; int lc = command.CommandData.Length; byte[] data = command.CommandData; // Encrypt if needed if (enc) { cla = 0x84; // Counter shall always be incremented Buffer_increment(encryption_counter); if (command.CommandData.Length > 0) { byte[] d = Pad80(command.CommandData, 16); // Encrypt with S-ENC, after increasing the counter byte[] iv = GPCrypto.DoEncrypt_AES_CBC(sessionKeys.GetKeyFor(KeySessionType.ENC).GetEncoded(), encryption_counter); data = GPCrypto.DoEncrypt_AES_CBC(sessionKeys.GetKeyFor(KeySessionType.ENC).GetEncoded(), d, iv); //Cipher c = Cipher.getInstance(GPCrypto.AES_CBC_CIPHER); //c.init(Cipher.ENCRYPT_MODE, sessionKeys.getKeyFor(KeySessionType.ENC), GPCrypto.null_bytes_16); //byte[] iv = c.doFinal(encryption_counter); // Now encrypt the data with S-ENC. //c.init(Cipher.ENCRYPT_MODE, sessionKeys.getKeyFor(KeySessionType.ENC), new IvParameterSpec(iv)); //data = c.doFinal(d); lc = data.Length; } } // Calculate C-MAC if (mac) { cla = 0x84; lc = lc + 8; ByteArrayOutputStream bo = new ByteArrayOutputStream(); bo.Write(chaining_value); bo.Write(cla); bo.Write(command.INS); bo.Write(command.P1); bo.Write(command.P2); bo.Write(lc); bo.Write(data); byte[] cmac_input = bo.ToByteArray(); byte[] cmac = Scp03_mac(sessionKeys.GetKey(KeySessionType.MAC), cmac_input, 128); // Set new chaining value Array.Copy(cmac, 0, chaining_value, 0, chaining_value.Length); // 8 bytes for actual mac cmd_mac = Arrays.CopyOf(cmac, 8); } // Construct new command ByteArrayOutputStream na = new ByteArrayOutputStream(); na.Write(cla); // possibly fiddled na.Write(command.INS); na.Write(command.P1); na.Write(command.P2); na.Write(lc); na.Write(data); if (mac) { na.Write(cmd_mac); } return(na.ToByteArray()); } catch (Exception e) { throw new Exception("APDU wrapping failed", e); } }
public override byte[] Wrap(GPCommand command) { try { if (!mac && !enc) { return(command.Serialize()); } if (rmac) { rMac.Reset(); rMac.Write(ClearBits((byte)command.CLA, (byte)0x07)); rMac.Write(command.INS); rMac.Write(command.P1); rMac.Write(command.P2); if (command.CommandData.Length >= 0) { rMac.Write(command.CommandData.Length); rMac.Write(command.CommandData); } } byte origCLA = command.CLA; byte newCLA = origCLA; byte origINS = command.INS; byte origP1 = command.P1; byte origP2 = command.P2; byte[] origData = command.CommandData; byte origLc = (byte)command.CommandData.Length; byte newLc = origLc; byte[] newData = null; byte le = command.Le.Value; ByteArrayOutputStream t = new ByteArrayOutputStream(); if (origLc > GetBlockSize()) { throw new Exception("APDU too long for wrapping."); } if (mac) { if (icv == null) { icv = new byte[8]; } else if (icvEnc) { //IBufferedCipher c = null; if (scp == 1) { icv = GPCrypto.DoEncrypt_DES3_ECB(sessionKeys.GetKeyFor(KeySessionType.MAC).GetEncoded(), icv); //c = Cipher.getInstance(GPCrypto.DES3_ECB_CIPHER); //c.init(Cipher.ENCRYPT_MODE, sessionKeys.getKeyFor(KeyType.MAC)); } else { icv = GPCrypto.DoEncrypt_DES_ECB(sessionKeys.GetKey(KeySessionType.MAC).GetKey(KeyType.DES).GetEncoded(), icv); //c = Cipher.getInstance(GPCrypto.DES_ECB_CIPHER); //c.init(Cipher.ENCRYPT_MODE, sessionKeys.getKey(KeyType.MAC).getKey(Type.DES)); } // encrypts the future ICV ? //icv = c.doFinal(icv); } if (preAPDU) { newCLA = SetBits((byte)newCLA, (byte)0x04); newLc = (byte)(newLc + 8); } t.Write(newCLA); t.Write(origINS); t.Write(origP1); t.Write(origP2); t.Write(newLc); t.Write(origData); if (scp == 1) { icv = Mac_3des(sessionKeys.GetKey(KeySessionType.MAC), t.ToByteArray(), icv); } else if (scp == 2) { icv = Mac_des_3des(sessionKeys.GetKey(KeySessionType.MAC), t.ToByteArray(), icv); } if (postAPDU) { newCLA = SetBits((byte)newCLA, (byte)0x04); newLc = (byte)(newLc + 8); } t.Reset(); newData = origData; } if (enc && (origLc > 0)) { if (scp == 1) { t.Write(origLc); t.Write(origData); if ((t.Size() % 8) != 0) { byte[] x = Pad80(t.ToByteArray(), 8); t.Reset(); t.Write(x); } } else { t.Write(Pad80(origData, 8)); } newLc += (byte)(t.Size() - origData.Length); //Cipher c = Cipher.getInstance(GPCrypto.DES3_CBC_CIPHER); //c.init(Cipher.ENCRYPT_MODE, sessionKeys.getKeyFor(KeyType.ENC), GPCrypto.iv_null_des); //newData = c.doFinal(t.toByteArray()); newData = GPCrypto.DoEncrypt_DES3_CBC(sessionKeys.GetKeyFor(KeySessionType.ENC).GetEncoded(), t.ToByteArray()); t.Reset(); } t.Write(newCLA); t.Write(origINS); t.Write(origP1); t.Write(origP2); if (newLc > 0) { t.Write(newLc); t.Write(newData); } if (mac) { t.Write(icv); } if (le > 0) { t.Write(le); } return(t.ToByteArray()); } catch (Exception e) { throw new Exception("APDU wrapping failed", e); } }