1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "pk11pub.h"
#include "nssutil.h"
#include <stdio.h>
#include "prerror.h"
#include "nss.h"
#include "gtest/gtest.h"
#include "nss_scoped_ptrs.h"
#include "cpputil.h"
#include "databuffer.h"
#include "util.h"
#define MAX_KEY_SIZE 24
namespace nss_test {
static const uint8_t kIv[] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
static const uint8_t kInput[] = {
0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0xff, 0xee, 0xdd, 0xcc,
0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00};
class EncryptDeriveTest
: public ::testing::Test,
public ::testing::WithParamInterface<CK_MECHANISM_TYPE> {
public:
void TestEncryptDerive() {
ScopedPK11SymKey derived_key(PK11_Derive(key_.get(), derive_mech(),
derive_param(), encrypt_mech(),
CKA_DECRYPT, keysize()));
ASSERT_TRUE(derived_key);
uint8_t derived_key_data[MAX_KEY_SIZE];
ASSERT_GE(sizeof(derived_key_data), keysize());
GetKeyData(derived_key, derived_key_data, keysize());
RemoveChecksum(derived_key_data);
uint8_t reference_key_data[MAX_KEY_SIZE];
unsigned int reference_len = 0;
SECStatus rv = PK11_Encrypt(key_.get(), encrypt_mech(), encrypt_param(),
reference_key_data, &reference_len, keysize(),
kInput, keysize());
ASSERT_EQ(SECSuccess, rv);
ASSERT_EQ(keysize(), static_cast<size_t>(reference_len));
RemoveChecksum(reference_key_data);
EXPECT_EQ(DataBuffer(reference_key_data, keysize()),
DataBuffer(derived_key_data, keysize()));
}
protected:
unsigned int keysize() const { return 16; }
private:
CK_MECHANISM_TYPE encrypt_mech() const { return GetParam(); }
CK_MECHANISM_TYPE derive_mech() const {
switch (encrypt_mech()) {
case CKM_DES3_ECB:
return CKM_DES3_ECB_ENCRYPT_DATA;
case CKM_DES3_CBC:
return CKM_DES3_CBC_ENCRYPT_DATA;
case CKM_AES_ECB:
return CKM_AES_ECB_ENCRYPT_DATA;
case CKM_AES_CBC:
return CKM_AES_CBC_ENCRYPT_DATA;
case CKM_CAMELLIA_ECB:
return CKM_CAMELLIA_ECB_ENCRYPT_DATA;
case CKM_CAMELLIA_CBC:
return CKM_CAMELLIA_CBC_ENCRYPT_DATA;
case CKM_SEED_ECB:
return CKM_SEED_ECB_ENCRYPT_DATA;
case CKM_SEED_CBC:
return CKM_SEED_CBC_ENCRYPT_DATA;
default:
ADD_FAILURE() << "Unknown mechanism";
break;
}
return CKM_INVALID_MECHANISM;
}
SECItem* derive_param() const {
static CK_AES_CBC_ENCRYPT_DATA_PARAMS aes_data;
static CK_DES_CBC_ENCRYPT_DATA_PARAMS des_data;
static CK_KEY_DERIVATION_STRING_DATA string_data;
static SECItem param = {siBuffer, NULL, 0};
switch (encrypt_mech()) {
case CKM_DES3_ECB:
case CKM_AES_ECB:
case CKM_CAMELLIA_ECB:
case CKM_SEED_ECB:
string_data.pData = toUcharPtr(kInput);
string_data.ulLen = keysize();
param.data = reinterpret_cast<uint8_t*>(&string_data);
param.len = sizeof(string_data);
break;
case CKM_DES3_CBC:
des_data.pData = toUcharPtr(kInput);
des_data.length = keysize();
PORT_Memcpy(des_data.iv, kIv, 8);
param.data = reinterpret_cast<uint8_t*>(&des_data);
param.len = sizeof(des_data);
break;
case CKM_AES_CBC:
case CKM_CAMELLIA_CBC:
case CKM_SEED_CBC:
aes_data.pData = toUcharPtr(kInput);
aes_data.length = keysize();
PORT_Memcpy(aes_data.iv, kIv, keysize());
param.data = reinterpret_cast<uint8_t*>(&aes_data);
param.len = sizeof(aes_data);
break;
default:
ADD_FAILURE() << "Unknown mechanism";
break;
}
return ¶m;
}
SECItem* encrypt_param() const {
static SECItem param = {siBuffer, NULL, 0};
switch (encrypt_mech()) {
case CKM_DES3_ECB:
case CKM_AES_ECB:
case CKM_CAMELLIA_ECB:
case CKM_SEED_ECB:
// No parameter needed here.
break;
case CKM_DES3_CBC:
case CKM_AES_CBC:
case CKM_CAMELLIA_CBC:
case CKM_SEED_CBC:
param.data = toUcharPtr(kIv);
param.len = keysize();
break;
default:
ADD_FAILURE() << "Unknown mechanism";
break;
}
return ¶m;
}
virtual void SetUp() {
slot_.reset(PK11_GetBestSlot(derive_mech(), NULL));
ASSERT_TRUE(slot_);
key_.reset(PK11_TokenKeyGenWithFlags(slot_.get(), encrypt_mech(), NULL,
keysize(), NULL,
CKF_ENCRYPT | CKF_DERIVE, 0, NULL));
ASSERT_TRUE(key_);
}
void GetKeyData(ScopedPK11SymKey& key, uint8_t* buf, size_t max_len) const {
ASSERT_EQ(SECSuccess, PK11_ExtractKeyValue(key.get()));
SECItem* data = PK11_GetKeyData(key.get());
ASSERT_TRUE(data);
ASSERT_EQ(max_len, static_cast<size_t>(data->len));
PORT_Memcpy(buf, data->data, data->len);
}
// Remove checksum if the key is a 3DES key.
void RemoveChecksum(uint8_t* key_data) const {
if (encrypt_mech() != CKM_DES3_CBC && encrypt_mech() != CKM_DES3_ECB) {
return;
}
for (size_t i = 0; i < keysize(); ++i) {
key_data[i] &= 0xfe;
}
}
ScopedPK11SlotInfo slot_;
ScopedPK11SymKey key_;
};
TEST_P(EncryptDeriveTest, Test) { TestEncryptDerive(); }
static const CK_MECHANISM_TYPE kEncryptDeriveMechanisms[] = {
CKM_DES3_ECB, CKM_DES3_CBC, CKM_AES_ECB, CKM_AES_ECB, CKM_AES_CBC,
CKM_CAMELLIA_ECB, CKM_CAMELLIA_CBC, CKM_SEED_ECB, CKM_SEED_CBC};
INSTANTIATE_TEST_CASE_P(EncryptDeriveTests, EncryptDeriveTest,
::testing::ValuesIn(kEncryptDeriveMechanisms));
// This class handles the case where 3DES takes a 192-bit key
// where all 24 octets will be used.
class EncryptDerive3Test : public EncryptDeriveTest {
protected:
unsigned int keysize() const { return 24; }
};
TEST_P(EncryptDerive3Test, Test) { TestEncryptDerive(); }
static const CK_MECHANISM_TYPE kDES3EncryptDeriveMechanisms[] = {CKM_DES3_ECB,
CKM_DES3_CBC};
INSTANTIATE_TEST_CASE_P(Encrypt3DeriveTests, EncryptDerive3Test,
::testing::ValuesIn(kDES3EncryptDeriveMechanisms));
} // namespace nss_test
|