using System.Security.Cryptography;
public static void Main()
string apduSM = chipherAPDU("00a4040c07a0000002471001", "3d7155f3791c313c2924f51ae60f1ac9" , "b5feb9488f17be03e54c7d80907e8a1f");
Console.WriteLine("ADPU SM : " + apduSM);
public static string chipherAPDU(string apdu, string keyEnc, string keyMac)
byte[] apduBytes = StringToByteArray(apdu);
byte[] KeyENC = StringToByteArray(keyEnc);
byte[] KeyMAC = StringToByteArray(keyMac);
byte[] secureMessagingSSC = StringToByteArray("00000000000000000000000000000001");
SecureMessaging sm = new SecureMessaging(KeyMAC, KeyENC);
chipherApdu = byteToHexStr ( sm.encrypt(apduBytes, secureMessagingSSC) );
public static string byteToHexStr(byte[] bytes)
for (int i = 0; i < bytes.Length; i++)
returnStr += bytes[i].ToString("X2");
public static byte[] StringToByteArray(string hex)
return Enumerable.Range(0, hex.Length)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
internal class SecureMessaging
private readonly byte[] NULL = new byte[] { 0x00 };
private const byte PAD = 0x80;
private readonly byte[] secureMessagingSSC;
private readonly byte[] keyMAC;
private readonly byte[] keyENC;
public SecureMessaging(byte[] keyMAC, byte[] keyENC)
secureMessagingSSC = new byte[16];
public byte[] encrypt(byte[] apdu)
incrementSSC(secureMessagingSSC);
byte[] commandAPDU = encrypt(apdu, secureMessagingSSC);
incrementSSC(secureMessagingSSC);
public byte[] encrypt(byte[] apdu, byte[] secureMessagingSSC)
MemoryStream outputStream = new MemoryStream();
CardCommandAPDU cAPDU = new CardCommandAPDU(apdu);
if (cAPDU.isSecureMessaging())
throw new ArgumentException("Malformed APDU.");
byte[] data = cAPDU.data;
byte[] header = cAPDU.header;
using (Aes aes = Aes.Create())
aes.IV = getCipherIV(secureMessagingSSC);
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.None;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] encryptedData = encryptor.TransformFinalBlock(data, 0, data.Length);
outputStream.Write(new byte[] { 0x01 }, 0, 1);
outputStream.Write(encryptedData, 0, encryptedData.Length);
return outputStream.ToArray();
public byte[] decrypt(byte[] response)
if (response.Length < 12)
throw new ArgumentException("Malformed Secure Messaging APDU.");
return decrypt(response, secureMessagingSSC);
private byte[] decrypt(byte[] response, byte[] secureMessagingSSC)
MemoryStream outputStream = new MemoryStream();
byte[] statusBytes = new byte[2];
byte[] dataObject = null;
byte[] macObject = new byte[8];
return outputStream.ToArray();
public static void incrementSSC(byte[] ssc)
for (int i = ssc.Length - 1; i >= 0; i--)
private byte[] pad(byte[] data, int blockSize)
byte[] result = new byte[data.Length + (blockSize - data.Length % blockSize)];
Array.Copy(data, 0, result, 0, data.Length);
result[data.Length] = PAD;
private byte[] getCipherIV(byte[] smssc)
using (Aes aes = Aes.Create())
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.None;
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, null);
return encryptor.TransformFinalBlock(smssc, 0, smssc.Length);
public class CardCommandAPDU
public byte[] header = new byte[4];
public CardCommandAPDU(byte[] commandAPDU)
Array.Copy(commandAPDU, 0, header, 0, 4);
setBody(copy(commandAPDU, 4, commandAPDU.Length - 4));
public void setBody(byte[] body)
using (MemoryStream stream = new MemoryStream(body))
int length = (int)stream.Length;
le = stream.ReadByte() & 0xFF;
int tmp = stream.ReadByte();
le = (stream.ReadByte() & 0xFF) << 8 | stream.ReadByte() & 0xFF;
lc = (stream.ReadByte() & 0xFF) << 8 | stream.ReadByte() & 0xFF;
stream.Read(data, 0, lc);
le = stream.ReadByte() & 0xFF;
else if (stream.Length == 2)
le = (stream.ReadByte() & 0xFF) << 8 | stream.ReadByte() & 0xFF;
else if (stream.Length == 3)
if (stream.ReadByte() == 0)
le = (stream.ReadByte() & 0xFF) << 8 | stream.ReadByte() & 0xFF;
throw new ArgumentException("APDU malformée.");
else if (stream.Length > 3)
throw new ArgumentException("APDU malformée.");
stream.Read(data, 0, lc);
setLE((byte)stream.ReadByte());
else if (stream.Length == 3)
setLE((short)((stream.ReadByte() & 0xFF) << 8 | stream.ReadByte() & 0xFF));
else if (stream.Length == 2 || stream.Length > 3)
throw new ArgumentException("APDU malformée.");
throw new ArgumentException("APDU malformée.");
throw new ArgumentException("APDU malformée.");
Console.WriteLine("Exception", e);
public void setLE(short le)
public void setLE(int le)
if (le < 0 || le > 65536)
throw new ArgumentException("La longueur doit être comprise entre '1' et '65535'.");
public static byte[] copy(byte[] input, int offset, int length)
byte[] tmp = new byte[length];
Array.Copy(input, offset, tmp, 0, length);
public bool isSecureMessaging()
return (header[0] & 0x0F) == 0x0C;