/// <summary> /// <para> Based on section B.1.2.2 of the v2.3 GlobalPlatform Card Specification. </para> /// </summary> /// <param name="data"></param> /// <param name="key"></param> /// <param name="icv"></param> /// <returns></returns> public static byte[] Algorithm3(byte[] data, byte[] key, byte[] icv) { if (data.Length % 8 != 0) { throw new ArgumentException("Data must be padded to 8-byte blocks.", nameof(data)); } Ensure.HasCount(key, nameof(key), 16); Ensure.HasCount(icv, nameof(icv), 8); int numBlocks = data.Length / 8; byte[] iv; if (numBlocks > 1) { byte[] firstBlocks = data.Take((numBlocks - 1) * 8).ToArray(); byte[] encFirstBlocks = DES.Encrypt(firstBlocks, key.Take(8).ToArray(), icv, CipherMode.CBC); iv = encFirstBlocks.TakeLast(8).ToArray(); } else { iv = icv; } byte[] lastBlock = data.TakeLast(8).ToArray(); byte[] encLastBlock = TripleDES.Encrypt(lastBlock, key, iv, CipherMode.CBC); byte[] mac = encLastBlock.TakeLast(8).ToArray(); return(mac); }
public void PutKey() { const byte keyVersion = 0x7F; const byte keyIdentifier = 0x01; byte[] encryptionkey = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }; var apdu = PutKeyCommand.Build .WithKeyVersion(keyVersion) .WithKeyIdentifier(keyIdentifier) .UsingEncryptionKey(encryptionkey) .PutFirstKey(KeyTypeCoding.DES, KeyData) .PutSecondKey(KeyTypeCoding.DES, KeyData) .PutThirdKey(KeyTypeCoding.DES, KeyData) .AsApdu(); apdu.Assert(ApduClass.GlobalPlatform, ApduInstruction.PutKey, keyVersion, keyIdentifier, 0x00); apdu.Lc.ShouldAllBeEquivalentTo(1 + 3 * 22); apdu.CommandData.First().Should().Be(keyVersion); apdu.CommandData.Skip(1).Split(22).ForEach(block => { block.First().Should().Be(0x80); block.Skip(1).First().Should().Be(0x10); block.Skip(2).Take(16).ShouldAllBeEquivalentTo(TripleDES.Encrypt(KeyData, encryptionkey, CipherMode.ECB)); block.Skip(18).First().Should().Be(0x03); block.Skip(19).ShouldAllBeEquivalentTo(KeyCheckValue.Generate(KeyTypeCoding.DES, KeyData)); }); }
public void TripleDes() { byte[] plaintext = { 0x98, 0x26, 0x62, 0x60, 0x55, 0x53, 0x24, 0x4D }; byte[] key = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 }; byte[] ciphertext = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; TripleDES.Encrypt(plaintext, key).Should().BeEquivalentTo(ciphertext); }
/// <summary> /// Generates a key check value for the specified key. /// <para> Based on section B.6 of the v2.3 GlobalPlatform Card Specification. </para> /// </summary> /// <param name="keyType"></param> /// <param name="key"></param> /// <returns></returns> public static byte[] Generate(KeyTypeCoding keyType, byte[] key) { IEnumerable <byte> data; switch (keyType) { case KeyTypeCoding.DES: data = Enumerable.Repeat <byte>(0x00, 8); break; case KeyTypeCoding.AES: data = Enumerable.Repeat <byte>(0x01, 16); break; default: throw new NotSupportedException("Unsupported key type."); } return(TripleDES.Encrypt(data.ToArray(), key, CipherMode.ECB).Take(3).ToArray()); }
/// <summary> /// <para> Based on section B.1.2.1 of the v2.3 GlobalPlatform Card Specification. </para> /// </summary> /// <param name="data"></param> /// <param name="key"></param> /// <returns></returns> public static byte[] Algorithm1(byte[] data, byte[] key) { byte[] ciphertext = TripleDES.Encrypt(data, key); return(ciphertext.Skip(ciphertext.Length - 8).Take(8).ToArray()); }
private byte[] GenerateSessionKey(SessionKeyType sessionKeyType, byte[] staticKey) => TripleDES.Encrypt(this.GenerateDerivationData(sessionKeyType), staticKey);
public CommandApdu SecureApdu(CommandApdu apdu) { if (apdu.ExtendedMode) { throw new InvalidOperationException("Extended commands APDUs are not supported."); } ApduClass.ByteCoding classByteCoding; if (apdu.CLA.IsBitSet(7)) { classByteCoding = ApduClass.ByteCoding.First; } else if (apdu.CLA.IsBitSet(6)) { classByteCoding = ApduClass.ByteCoding.InterIndustry; } else { return(apdu); } if (this.SecurityLevel.HasFlag(SecurityLevel.CMac) || apdu.INS == ApduInstruction.ExternalAuthenticate) { switch (classByteCoding) { case ApduClass.ByteCoding.First: apdu.CLA = apdu.CLA |= 0b00000100; break; case ApduClass.ByteCoding.InterIndustry: apdu.CLA = apdu.CLA |= 0b00100000; break; default: throw new InvalidOperationException("APDU does not use either First or Interindustry Class Byte coding."); } var mac = this.GenerateCmac(apdu); var data = new List <byte>(); data.AddRange(apdu.CommandData); data.AddRange(mac); apdu.CommandData = data.ToArray(); } if (this.SecurityLevel.HasFlag(SecurityLevel.CDecryption) && apdu.INS != ApduInstruction.ExternalAuthenticate) { var commandData = apdu.CommandData.Take(apdu.CommandData.Count() - 8).ToList(); var mac = apdu.CommandData.TakeLast(8); byte[] padded = commandData.Pad().ToArray(); byte[] encrypted = TripleDES.Encrypt(padded, this.EncryptionKey); var data = new List <byte>(); data.AddRange(encrypted); data.AddRange(mac); apdu.CommandData = data.ToArray(); } return(apdu); }