Reputation: 1033
In "GlobalPlatform Technology Secure Channel Protocol 03" document it defines a 'Data Derivation Scheme' as follows :
The following data derivation scheme is used to generate keys, pseudo-random card challenges or
cryptograms:
Data derivation shall use KDF in counter mode as specified in NIST SP 800-108 ([NIST 800-108]). The PRF
used in the KDF shall be CMAC as specified in [NIST 800-38B], used with full 16-byte output length.
The “fixed input data” plus iteration counter shall be the concatenation of the following items in the given
sequence (note that [NIST 800-108] allows the reordering of input data fields as long as the order, coding and
length of each field is unambiguously defined):
• A 12-byte “label” consisting of 11 bytes with value '00' followed by a 1-byte derivation constant as
defined below.
• A 1-byte “separation indicator” with value '00'.
• A 2-byte integer “L” specifying the length in bits of the derived data (value '0040', '0080', '00C0', or
'0100').
• A 1-byte counter “i” as specified in the KDF (which may take the values '01' or '02'; value '02' is used
when “L” takes the values '00C0' and '0100', i.e. when the PRF of the KDF is to be called twice to
generate enough derived data).
• The “context” parameter of the KDF. Its content is further specified in the sections below applying the
data derivation scheme.
Definition of the derivation constant:
I want to implement this in C# by using Bouncy Castle library.
This is my code (it's not generating correct keys, because I can't verify card cryptogram)
public static byte[] scp03_kdf(byte[] key, byte constant, byte[] msg, int blocklen_bits)
{
// 11 bytes
byte[] label = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
List<byte> byteArrayOutputStream = new List<byte>();
byteArrayOutputStream.AddRange(label); // Label
byteArrayOutputStream.Add(constant); // Constant
byteArrayOutputStream.Add(0x00); // Seperator
//L
byteArrayOutputStream.Add((byte)((blocklen_bits >> 8) & 0xFF)); // block size in two bytes
byteArrayOutputStream.Add((byte)(blocklen_bits & 0xFF));
byte[] blocka = byteArrayOutputStream.ToArray();
byte[] blockb = msg;
return scp03_kdf(key, blocka, blockb, blocklen_bits / 8);
}
private static byte[] scp03_kdf(byte[] key, byte[] a, byte[] b, int bytes)
{
ICipherParameters parameters = new KeyParameter(key);
AesEngine aes = new AesEngine();
CMac cmac = new CMac(aes);
KdfCounterBytesGenerator kdf = new KdfCounterBytesGenerator(cmac);
kdf.Init(new KdfCounterParameters(key, a, b, 8)); // counter size is in bits
byte[] cgram = new byte[bytes];
kdf.GenerateBytes(cgram, 0, cgram.Length);
return cgram;
}
When I try to generate session key MAC I'm calling scp03_kdf function with blocklen_bits = key.length*8
When I try to generate card cryptogram I'm calling scp03_kdf function with blocklen_bits = 64.
I found these codes from GlobalPlatformPro project which is written in Java and I converted them to C#.
What is the problem?
Upvotes: 1
Views: 252