· 6 years ago · Dec 19, 2019, 09:56 PM
1public SecretKey kdf_AES_CMAC_SCP03_SYMKEY(SymmetricKey masterKey, byte[] context, byte kdfConstant,
2 int kdfOutputSizeBytes, boolean allowCounterData) throws EBaseException {
3
4 String method = "NistSP800_108KDF.kdf_AES_CMAC_SCP03_SYMKEY:";
5 String generatorInstanceName = null;
6
7 if (masterKey == null || context == null || kdfOutputSizeBytes <= 0) {
8 throw new EBaseException(method + " Invalid input!");
9 }
10
11 // Decide if we want to allow extraction of derived key data for challenge strings.
12
13 if(allowCounterData == true) {
14 generatorInstanceName = "KbkdfCounterData";
15 } else {
16 generatorInstanceName = "KbkdfCounter";
17 }
18
19 try {
20 /* We want a counter-mode KBKDF which generates data, not keys. */
21 KeyGenerator kg = KeyGenerator.getInstance(generatorInstanceName, "Mozilla-JSS");
22 System.err.println("Done get KeyGenerator instance");
23 /* Start by building parameters for the Counter mode KDF. */
24 KBKDFCounterParams kcp = new KBKDFCounterParams();
25
26 System.err.println("Done new DBKDFCounterParams");
27
28 /* SCP03 mandates use of AES/CMAC for the KDF's PRF. */
29 kcp.setPRF(PKCS11Algorithm.CKM_AES_CMAC);
30
31 System.err.println("Done setPRF ");
32
33 SecretKey scMaster = new SecretKeyFacade(masterKey);
34 /* We've been passed the PRF key as master. */
35 kcp.setPRFKey(scMaster);
36
37 System.err.println("Done setPRFKey masterKey");
38
39 /* We've been passed the output size of the base key as kdfOutputSizeBytes. */
40 kcp.setKeySize(kdfOutputSizeBytes);
41
42 System.err.println("Done setKeySize");
43
44 /* Now we need to add the parameters for the SCP03 KDF. */
45
46 /* First is the 12-byte label. */
47 kcp.addParameter(new KBKDFByteArrayParam(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, kdfConstant }));
48
49 /* Then comes a one byte separation indicator. */
50 kcp.addParameter(new KBKDFByteArrayParam(new byte[] { 0x00 }));
51
52 /* Then comes the 2-byte, big-endian length parameter. Method doesn't matter as we only have a single key. Note that it is width in bits, not bytes. */
53 kcp.addParameter(new KBKDFDKMLengthParam(PKCS11Constants.CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS, true, 2*8));
54
55 /* Then comes a 1-byte counter. Endianness doesn't matter. Size in bits again. */
56 kcp.addParameter(new KBKDFIterationVariableParam(true, 1*8));
57
58 /* Lastly comes the context. */
59 kcp.addParameter(new KBKDFByteArrayParam(context));
60 System.err.println("Done adding parameters");
61
62 /* Pass our parameters to the KeyGenerator. */
63 kg.init(kcp);
64
65 System.err.println("Done init kcp");
66
67
68 /* Return the derived key */
69
70 return kg.generateKey();
71
72 } catch (Exception e) {
73 throw new EBaseException(e.getMessage(), e);
74 }
75 }
76
77 public byte[] kdf_AES_CMAC_SCP03_CHALLENGE(SymmetricKey masterKey, byte[] context, byte kdfConstant,
78 int kdfOutputSizeBytes) throws EBaseException {
79
80 String method = "NistSP800_108KDF.kdf_AES_CMAC_SCP03:";
81 // sanity checking
82
83 if (masterKey == null || context == null || kdfOutputSizeBytes <= 0) {
84 throw new EBaseException(method + " Invalid input!");
85 }
86
87 try {
88 boolean allowCounterData = true;
89 SecretKey key = this.kdf_AES_CMAC_SCP03_SYMKEY(masterKey,context, kdfConstant,kdfOutputSizeBytes, allowCounterData);
90
91 /* Extract the value and return it. Only guaranteed to succeed in FIPS mode if KbkdfCounterData was used. */
92 return key.getEncoded();
93 } catch (Exception e) {
94 throw new EBaseException(e.getMessage(), e);
95 }
96
97 }