/// <summary> /// Applies full triple DES MAC as defined in [ISO 9797-1] as MAC Algorithm 1 with output transformation 1, /// without truncation, and withtriple DES taking the place of the block cipher. /// See Global Platform 2.1.1 Card Spec Section B.1.2.1 /// </summary> /// <param name="key">3DES key</param> /// <param name="iv">Initial Vector</param> /// <param name="data">Data to MAC</param> /// <returns>Full triple DES MAC</returns> public static byte[] FullTripleDESMAC(Key key, byte[] iv, byte[] data) { byte[] enc = TripleDESCBC(new Key(key.BuildTripleDesKey()), iv, data, MODE_ENCRYPT); byte[] result = new byte[8]; Array.Copy(enc, enc.Length - 8, result, 0, 8); return result; }
/// <summary> /// Applies Retail MAC as defined in [ISO 9797-1] as MAC Algorithm 1 with output /// transformation 3, without truncation, and withDES taking the place of the block cipher. /// </summary> /// <param name="key">Key</param> /// <param name="iv">Initial Vector</param> /// <param name="data">Data to MAC</param> /// <returns>Retial MAC</returns> public static byte[] SingleDESFullTripleDESMAC(Key key, byte[] iv, byte[] data) { byte[] intermeidateResult; byte[] result = new byte[8]; if (data.Length > 8) { intermeidateResult = DESCBC(new Key(key.BuildDesKey()), iv, SubArray(data, 0, data.Length - 8), MODE_ENCRYPT); Array.Copy(intermeidateResult, intermeidateResult.Length - 8, result, 0, 8); intermeidateResult = TripleDESCBC(new Key(key.BuildTripleDesKey()), result, SubArray(data, data.Length - 8, 8), MODE_ENCRYPT); } else { intermeidateResult = TripleDESCBC(new Key(key.BuildTripleDesKey()), iv, SubArray(data, data.Length - 8, 8), MODE_ENCRYPT); } Array.Copy(intermeidateResult, intermeidateResult.Length - 8, result, 0, 8); return result; }
/// <summary> /// /// </summary> /// <param name="keys"></param> /// <param name="replaceExisting"></param> /// <param name="keyFormat"></param> /// <returns></returns> public CommandAPDU CreatePutKeyCommand(List<Key> keys, bool replaceExisting, bool addKCV, int keyFormat) { int p1; int p2; if (keyFormat == KEY_FORMAT_2) throw new Exception("Format 2 is reserved for futrue use."); if (keyFormat != KEY_FORMAT_1) throw new Exception("Unknown format"); int prevId = -1; for (int i = 0; i < keys.Count; i++) { Key key = keys[i]; if (i > 1) if (key.KeyId != prevId + 1) throw new Exception("Key Identifiers must sequentially increment. See See Global Platform 2.1.1 Card Spec section 9.8.2.3.1"); prevId = key.KeyId; } if (replaceExisting) p1 = keys[0].KeyVersion; else { p1 = 0; } p2 = keys[0].KeyId; // Multiple keys if (keys.Count > 1) p2 |= 0x80; Key kek = null; if (mSCPIdentifier == SCP_01) kek = new Key(mStaticKeys.KekKey.BuildTripleDesKey()); else if(mSCPIdentifier == SCP_02) { kek = new Key(mSessionKeys.KekKey.BuildTripleDesKey()); } MemoryStream allKeyData = new MemoryStream(); allKeyData.WriteByte((byte)keys[0].KeyVersion); for (int i = 0; i < keys.Count; i++) { Key key = keys[i]; byte[] keyDataBytes = EncodeKeyData(key, kek, addKCV, keyFormat); allKeyData.Write(keyDataBytes, 0, keyDataBytes.Length); } CommandAPDU putKeyCommand = new CommandAPDU(CLA_GP, INS_PUT_KEY, p1, p2, allKeyData.ToArray(), 0x00); putKeyCommand = mSecureChannel.wrap(putKeyCommand); return putKeyCommand; }
/// <summary> /// Encrypts or decrypts <see cref="data"/> with DES/CBC/NoPadding /// </summary> /// <param name="key">Key</param> /// <param name="iv">Initial Vector</param> /// <param name="data">Data to encrypt or decrypt</param> /// <param name="mode">Operation mode: either <see cref="MODE_ENCRYPT"/> or <see cref="MODE_DECRYPT"/> </param> /// <returns></returns> public static byte[] DESCBC(Key key, byte[] iv, byte[] data, int operationMode) { byte[] result = null; DESCryptoServiceProvider tdes = new DESCryptoServiceProvider(); if (operationMode == MODE_DECRYPT) { tdes.Mode = CipherMode.CBC; tdes.Padding = PaddingMode.None; ICryptoTransform decryptor = tdes.CreateDecryptor(key.Value, iv); result = decryptor.TransformFinalBlock(data, 0, data.Length); } else if (operationMode == MODE_ENCRYPT) { tdes.Mode = CipherMode.CBC; tdes.Padding = PaddingMode.None; ICryptoTransform encryptor = tdes.CreateEncryptor(key.Value, iv); result = encryptor.TransformFinalBlock(data, 0, data.Length); } return result; }
private byte[] EncodeKeyData(Key key, Key kek, bool addKCV, int keyFormat) { MemoryStream keyData = new MemoryStream(); if (keyFormat == KEY_FORMAT_1) { // Key encryption algorithm keyData.WriteByte(CryptoUtil.ALG_DES); // Encrypted key data length keyData.WriteByte(0x10); byte[] encryptedKey = CryptoUtil.TripleDESECB(kek, key.Value, CryptoUtil.MODE_ENCRYPT); keyData.Write(encryptedKey, 0, encryptedKey.Length); if (addKCV) { // KCV length keyData.WriteByte(0x03); // Calculate KCV byte[] kcv = CryptoUtil.TripleDESECB(new Key(key.BuildTripleDesKey()), CryptoUtil.BINARY_ZEROS_8_BYTE_BLOCK, CryptoUtil.MODE_ENCRYPT); keyData.Write(kcv, 0, 3); } else { keyData.WriteByte(0x00); } } return keyData.ToArray(); }