Calculating Key Check Values in C#

When symmetric keys are physically exchanged between two parties, generally the keys are broken up into parts for secure transfer across open communications paths (email, IM, face-to-face, etc.). As a result the parts are sent with Key Check Values included, as a simple checksum.

It’s not difficult to calculate a KCV value, it’s simply just the encryption of a block of zeros and the KCV is just the first 6 bytes of that encrypted value in hex. Here are some examples written in C# for AES and DES:

AES

AES has a fixed initialisation vector, but the data to encrypt is dependant on the length of the key:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private static string GetKcvAes(string key)
{
var iv = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
var data = new byte[key.Length];

for (var i = 0; i < key.Length; i++)
{
data[i] = 0x00;
}

var csp = new AesCryptoServiceProvider();

using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, csp.CreateEncryptor(StringToByteArray(key), iv), CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
return ByteArrayToString(memoryStream.ToArray()).Remove(6);
}
}
}

DES

DES is a little simpler, but fundamentally the same process as AES:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private static string GetKcvDes(string key)
{
var iv = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
var data = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

DES des = new DESCryptoServiceProvider();

using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, des.CreateEncryptor(StringToByteArray(key), iv), CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
return ByteArrayToString(memoryStream.ToArray()).Remove(6);
}
}
}

Triple DES

And 3DES is the same as DES, just with a different CSP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private static string GetKcv3Des(string key)
{
var iv = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
var data = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

TripleDES des = new TripleDESCryptoServiceProvider();

using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, des.CreateEncryptor(StringToByteArray(key), iv), CryptoStreamMode.Write))
{
cryptoStream.Write(data, 0, data.Length);
cryptoStream.FlushFinalBlock();
return ByteArrayToString(memoryStream.ToArray()).Remove(6);
}
}
}

And I’ll just include those ByteArrayToString() and StringToByteArray functions for completeness:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static string ByteArrayToString(byte[] ba)
{
var hex = new StringBuilder(ba.Length * 2);
foreach (var b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString().ToUpper();
}

public static byte[] StringToByteArray(String hex)
{
var numberChars = hex.Length;
var bytes = new byte[numberChars / 2];
for (var i = 0; i < numberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}