我试图在C#PACE PIN通用映射中实现. 在协议的最后,我们需要这样做来计算令牌:
• Derive session keys Kenc and Kmac from Hmap
• 计算令牌:TPICC = MAC(Kmac,PKPCD,map),TPCD = MAC(Kmac,PKPBC,map)
我已经完成了第一点,获得了密钥Kenc = SHA1(Kshared|| 000000001)和密钥Kmac = SHA1(Kshared|| 00000002). 现在我必须完成第二点,它包括计算将发送到芯片的令牌:
- 计算令牌:TPICC = MAC(Kmac,PKPCD,map),TPCD = MAC(Kmac,PKPBC,map)
我在这里找到了一个方法:AES CMAC Calculation C# 但是当我试图计算已知结果的MAC时,我没有找到相同的值,这些值甚至不是相同的大小."
Here is a log from PlatinumReader, a software that has implemented what I want to implement in my application:
PKPCD,map:
04 b6 cb e1 30 44 9b 32 a6 bf e7 86 f2 56 41 a7
c9 c4 a4 99 a6 1b d4 98 69 67 2d f0 3f ba 82 07
26 14 ce d3 2b f2 1d 06 d6 f6 d0 69 6c 80 0e 8c
e4 57 79 94 1a 32 38 b9 28 f0 52 48 af 21 10 ce de
100
04 b5 05 d4 67 8c 5d 7d 1a a8 7b cc c3 d4 24 82
e3 6d df 84 19 5c f9 b0 f4 bb e0 de 69 de d3 04
2c 52 ea b6 b2 64 03 88 4a ff fa 46 01 82 fc bc
f5 bb 2a aa 64 97 ec e3 59 92 a9 45 1c ef 91 e3 02
密钥:K_MAC—派生MAC密钥(K_MAC [PACE])
b5 fe b9 48 8f 17 be 03 e5 4c 7d 80 90 7e 8a 1f
关键字:T_PCD—PCD计算的身份验证令牌(T_PCD [PACE]):结果
3e 93 48 fc ca 2c 5d dc
在我这边,我只需要TPCD,然后我将其作为请求发送给芯片,芯片通常应该用它的令牌响应,令牌应该对应于我可以手动计算的TPICC.这结束了www.example.com这个
APDU: Request sending my token (tcpd) to the chip
00 86 00 00 0c 7c 0a 85 08 3e 93 48 fc ca 2c 5d dc 00
Response : getting the chip token (tpicc) : 8b 9e 28 f9 81 be 50 86
7c 0a 86 08 8b 9e 28 f9 81 be 50 86 90 00
下面是我的代码:
byte[] AESCMAC(byte[] key, byte[] data)
{
// SubKey generation
// step 1, AES-128 with key K is applied to an all-zero input block.
byte[] L = AESEncrypt(key, new byte[8], new byte[16]);
// step 2, K1 is derived through the following operation:
byte[] FirstSubkey = Rol(L); //If the most significant bit of L is equal to 0, K1 is the left-shift of L by 1 bit.
if ((L[0] & 0x80) == 0x80)
FirstSubkey[15] ^= 0x87; // Otherwise, K1 is the exclusive-OR of const_Rb and the left-shift of L by 1 bit.
// step 3, K2 is derived through the following operation:
byte[] SecondSubkey = Rol(FirstSubkey); // If the most significant bit of K1 is equal to 0, K2 is the left-shift of K1 by 1 bit.
if ((FirstSubkey[0] & 0x80) == 0x80)
SecondSubkey[15] ^= 0x87; // Otherwise, K2 is the exclusive-OR of const_Rb and the left-shift of K1 by 1 bit.
// MAC computing
if (((data.Length != 0) && (data.Length % 16 == 0)) == true)
{
// If the size of the input message block is equal to a positive multiple of the block size (namely, 128 bits),
// the last block shall be exclusive-OR'ed with K1 before processing
for (int j = 0; j < FirstSubkey.Length; j++)
data[data.Length - 16 + j] ^= FirstSubkey[j];
}
else
{
// Otherwise, the last block shall be padded with 10^i
byte[] padding = new byte[16 - data.Length % 16];
padding[0] = 0x80;
data = data.Concat<byte>(padding.AsEnumerable()).ToArray();
// and exclusive-OR'ed with K2
for (int j = 0; j < SecondSubkey.Length; j++)
data[data.Length - 16 + j] ^= SecondSubkey[j];
}
// The result of the previous process will be the input of the last encryption.
byte[] encResult = AESEncrypt(key, new byte[8], data);
byte[] HashValue = new byte[16];
Array.Copy(encResult, encResult.Length - HashValue.Length, HashValue, 0, HashValue.Length);
return HashValue;
}
byte[] Rol(byte[] b)
{
byte[] r = new byte[b.Length];
byte carry = 0;
for (int i = b.Length - 1; i >= 0; i--)
{
ushort u = (ushort)(b[i] << 1);
r[i] = (byte)((u & 0xff) + carry);
carry = (byte)((u & 0xff00) >> 8);
}
return r;
}
byte[] AESEncrypt(byte[] key, byte[] iv, byte[] data)
{
using (MemoryStream ms = new MemoryStream())
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.None;
using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(key, iv), CryptoStreamMode.Write))
{
cs.Write(data, 0, data.Length);
cs.FlushFinalBlock();
return ms.ToArray();
}
}
}
我在这里调用函数:
byte[] tipcc = AESCMAC(StringToByteArray("b5feb9488f17be03e54c7d80907e8a1f"), StringToByteArray("b6cbe130449b32a6bfe786f25641a7c9c4a499a61bd49869672df03fba820726"));
addLogMsg("MAC : " + byteToHexStr(tipcc));
转换方法为:
public static byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
以及:
public string byteToHexStr(byte[] bytes)
{
string returnStr = "";
if (bytes != null)
{
for (int i = 0; i < bytes.Length; i++)
{
returnStr += bytes[i].ToString("X2");
}
}
return returnStr;
}