Skip to content

Commit 566c080

Browse files
committed
Use local key value diversification with AN10922
1 parent ea74872 commit 566c080

File tree

2 files changed

+107
-8
lines changed

2 files changed

+107
-8
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
using System.Security.Cryptography;
2+
3+
namespace Leosac.KeyManager.Library.Crypto
4+
{
5+
public static class AN10922KeyDiversification
6+
{
7+
public static string Diversify(string key, string diversifier)
8+
{
9+
diversifier = "01" + diversifier;
10+
return Convert.ToHexString(AESCMAC(Convert.FromHexString(key), Convert.FromHexString(diversifier), 32));
11+
}
12+
13+
private static byte[] AESEncrypt(byte[] key, byte[] iv, byte[] data)
14+
{
15+
using (MemoryStream ms = new MemoryStream())
16+
{
17+
using (var aes = Aes.Create())
18+
{
19+
aes.Mode = CipherMode.CBC;
20+
aes.Padding = PaddingMode.None;
21+
22+
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(key, iv), CryptoStreamMode.Write))
23+
{
24+
cs.Write(data, 0, data.Length);
25+
cs.FlushFinalBlock();
26+
27+
return ms.ToArray();
28+
}
29+
}
30+
}
31+
}
32+
33+
private static byte[] Rol(byte[] b)
34+
{
35+
byte[] r = new byte[b.Length];
36+
byte carry = 0;
37+
38+
for (int i = b.Length - 1; i >= 0; i--)
39+
{
40+
ushort u = (ushort)(b[i] << 1);
41+
r[i] = (byte)((u & 0xff) + carry);
42+
carry = (byte)((u & 0xff00) >> 8);
43+
}
44+
45+
return r;
46+
}
47+
48+
public static byte[] AESCMAC(byte[] key, byte[] data, int padsize = 16, byte[]? iv = null)
49+
{
50+
if (iv == null)
51+
{
52+
iv = new byte[16];
53+
}
54+
// SubKey generation
55+
// step 1, AES-128 with key K is applied to an all-zero input block.
56+
var L = AESEncrypt(key, iv, new byte[16]);
57+
58+
// step 2, K1 is derived through the following operation:
59+
var FirstSubkey = Rol(L); //If the most significant bit of L is equal to 0, K1 is the left-shift of L by 1 bit.
60+
if ((L[0] & 0x80) == 0x80)
61+
FirstSubkey[15] ^= 0x87; // Otherwise, K1 is the exclusive-OR of const_Rb and the left-shift of L by 1 bit.
62+
63+
// step 3, K2 is derived through the following operation:
64+
var SecondSubkey = Rol(FirstSubkey); // If the most significant bit of K1 is equal to 0, K2 is the left-shift of K1 by 1 bit.
65+
if ((FirstSubkey[0] & 0x80) == 0x80)
66+
SecondSubkey[15] ^= 0x87; // Otherwise, K2 is the exclusive-OR of const_Rb and the left-shift of K1 by 1 bit.
67+
68+
// MAC computing
69+
if (((data.Length != 0) && (data.Length % padsize == 0)) == true)
70+
{
71+
// If the size of the input message block is equal to a positive multiple of the block size (namely, 128 bits),
72+
// the last block shall be exclusive-OR'ed with K1 before processing
73+
for (int j = 0; j < FirstSubkey.Length; j++)
74+
data[data.Length - FirstSubkey.Length + j] ^= FirstSubkey[j];
75+
}
76+
else
77+
{
78+
// Otherwise, the last block shall be padded with 10^i
79+
var padding = new byte[padsize - data.Length % padsize];
80+
padding[0] = 0x80;
81+
82+
data = data.Concat(padding.AsEnumerable()).ToArray();
83+
84+
// and exclusive-OR'ed with K2
85+
for (int j = 0; j < SecondSubkey.Length; j++)
86+
data[data.Length - SecondSubkey.Length + j] ^= SecondSubkey[j];
87+
}
88+
89+
// The result of the previous process will be the input of the last encryption.
90+
var encResult = AESEncrypt(key, new byte[16], data);
91+
92+
var HashValue = new byte[16];
93+
Array.Copy(encResult, encResult.Length - HashValue.Length, HashValue, 0, HashValue.Length);
94+
95+
return HashValue;
96+
}
97+
}
98+
}

KeyManager.Library/KeyStore/KeyStore.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
using Leosac.KeyManager.Library.DivInput;
1+
using Leosac.KeyManager.Library.Crypto;
2+
using Leosac.KeyManager.Library.DivInput;
23
using Newtonsoft.Json;
34
using System.Text;
4-
using static System.Formats.Asn1.AsnWriter;
55
using System.Threading;
6+
using static System.Formats.Asn1.AsnWriter;
67

78
namespace Leosac.KeyManager.Library.KeyStore
89
{
@@ -688,14 +689,14 @@ protected void OnUserMessageNotified(string message)
688689

689690
public async Task<string?> GetKeyValue(KeyEntryId keyIdentifier, KeyEntryClass keClass, string? keyContainerSelector, string? divInput)
690691
{
691-
if (!string.IsNullOrEmpty(divInput))
692+
var key = await GetKey(keyIdentifier, keClass, keyContainerSelector);
693+
var kv = key?.GetAggregatedValueAsString();
694+
if (!string.IsNullOrEmpty(kv) && !string.IsNullOrEmpty(divInput))
692695
{
693-
log.Error("Div Input parameter is not yet supported.");
694-
throw new KeyStoreException("Div Input parameter is not yet supported.");
696+
// TODO: the key diversification algorithm should be an user choice
697+
kv = AN10922KeyDiversification.Diversify(kv, divInput);
695698
}
696-
697-
var key = await GetKey(keyIdentifier, keClass, keyContainerSelector);
698-
return key?.GetAggregatedValueAsString();
699+
return kv;
699700
}
700701

701702
/// <summary>

0 commit comments

Comments
 (0)