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:
privatestaticstringGetKcvAes(string key) { var iv = newbyte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; var data = newbyte[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
privatestaticstringGetKcvDes(string key) { var iv = newbyte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; var data = newbyte[] { 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
privatestaticstringGetKcv3Des(string key) { var iv = newbyte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; var data = newbyte[] { 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
publicstaticstringByteArrayToString(byte[] ba) { var hex = new StringBuilder(ba.Length * 2); foreach (var b in ba) hex.AppendFormat("{0:x2}", b); return hex.ToString().ToUpper(); }
publicstaticbyte[] StringToByteArray(String hex) { var numberChars = hex.Length; var bytes = newbyte[numberChars / 2]; for (var i = 0; i < numberChars; i += 2) bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); return bytes; }