Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/kgssapi/krb5/kcrypto.c
39507 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2008 Isilon Inc http://www.isilon.com/
5
* Authors: Doug Rabson <[email protected]>
6
* Developed with Red Inc: Alfred Perlstein <[email protected]>
7
*
8
* Redistribution and use in source and binary forms, with or without
9
* modification, are permitted provided that the following conditions
10
* are met:
11
* 1. Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
#include <sys/param.h>
31
#include <sys/malloc.h>
32
#include <sys/kobj.h>
33
#include <sys/mbuf.h>
34
#include <sys/sysctl.h>
35
36
#include <kgssapi/gssapi.h>
37
#include <kgssapi/gssapi_impl.h>
38
39
#include "kcrypto.h"
40
41
static struct krb5_encryption_class *krb5_encryption_classes[] = {
42
&krb5_aes128_encryption_class,
43
&krb5_aes256_encryption_class,
44
NULL
45
};
46
47
struct krb5_encryption_class *
48
krb5_find_encryption_class(int etype)
49
{
50
int i;
51
52
for (i = 0; krb5_encryption_classes[i]; i++) {
53
if (krb5_encryption_classes[i]->ec_type == etype)
54
return (krb5_encryption_classes[i]);
55
}
56
return (NULL);
57
}
58
59
struct krb5_key_state *
60
krb5_create_key(const struct krb5_encryption_class *ec)
61
{
62
struct krb5_key_state *ks;
63
64
ks = malloc(sizeof(struct krb5_key_state), M_GSSAPI, M_WAITOK);
65
ks->ks_class = ec;
66
refcount_init(&ks->ks_refs, 1);
67
ks->ks_key = malloc(ec->ec_keylen, M_GSSAPI, M_WAITOK);
68
ec->ec_init(ks);
69
70
return (ks);
71
}
72
73
void
74
krb5_free_key(struct krb5_key_state *ks)
75
{
76
77
if (refcount_release(&ks->ks_refs)) {
78
ks->ks_class->ec_destroy(ks);
79
bzero(ks->ks_key, ks->ks_class->ec_keylen);
80
free(ks->ks_key, M_GSSAPI);
81
free(ks, M_GSSAPI);
82
}
83
}
84
85
static size_t
86
gcd(size_t a, size_t b)
87
{
88
89
if (b == 0)
90
return (a);
91
return gcd(b, a % b);
92
}
93
94
static size_t
95
lcm(size_t a, size_t b)
96
{
97
return ((a * b) / gcd(a, b));
98
}
99
100
/*
101
* Rotate right 13 of a variable precision number in 'in', storing the
102
* result in 'out'. The number is assumed to be big-endian in memory
103
* representation.
104
*/
105
static void
106
krb5_rotate_right_13(uint8_t *out, uint8_t *in, size_t numlen)
107
{
108
uint32_t carry;
109
size_t i;
110
111
/*
112
* Special case when numlen == 1. A rotate right 13 of a
113
* single byte number changes to a rotate right 5.
114
*/
115
if (numlen == 1) {
116
carry = in[0] >> 5;
117
out[0] = (in[0] << 3) | carry;
118
return;
119
}
120
121
carry = ((in[numlen - 2] & 31) << 8) | in[numlen - 1];
122
for (i = 2; i < numlen; i++) {
123
out[i] = ((in[i - 2] & 31) << 3) | (in[i - 1] >> 5);
124
}
125
out[1] = ((carry & 31) << 3) | (in[0] >> 5);
126
out[0] = carry >> 5;
127
}
128
129
/*
130
* Add two variable precision numbers in big-endian representation
131
* using ones-complement arithmetic.
132
*/
133
static void
134
krb5_ones_complement_add(uint8_t *out, const uint8_t *in, size_t len)
135
{
136
int n, i;
137
138
/*
139
* First calculate the 2s complement sum, remembering the
140
* carry.
141
*/
142
n = 0;
143
for (i = len - 1; i >= 0; i--) {
144
n = out[i] + in[i] + n;
145
out[i] = n;
146
n >>= 8;
147
}
148
/*
149
* Then add back the carry.
150
*/
151
for (i = len - 1; n && i >= 0; i--) {
152
n = out[i] + n;
153
out[i] = n;
154
n >>= 8;
155
}
156
}
157
158
static void
159
krb5_n_fold(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen)
160
{
161
size_t tmplen;
162
uint8_t *tmp;
163
size_t i;
164
uint8_t *p;
165
166
tmplen = lcm(inlen, outlen);
167
tmp = malloc(tmplen, M_GSSAPI, M_WAITOK);
168
169
bcopy(in, tmp, inlen);
170
for (i = inlen, p = tmp; i < tmplen; i += inlen, p += inlen) {
171
krb5_rotate_right_13(p + inlen, p, inlen);
172
}
173
bzero(out, outlen);
174
for (i = 0, p = tmp; i < tmplen; i += outlen, p += outlen) {
175
krb5_ones_complement_add(out, p, outlen);
176
}
177
free(tmp, M_GSSAPI);
178
}
179
180
struct krb5_key_state *
181
krb5_derive_key(struct krb5_key_state *inkey,
182
void *constant, size_t constantlen)
183
{
184
struct krb5_key_state *dk;
185
const struct krb5_encryption_class *ec = inkey->ks_class;
186
uint8_t *folded;
187
uint8_t *bytes, *p, *q;
188
struct mbuf *m;
189
int randomlen, i;
190
191
/*
192
* Expand the constant to blocklen bytes.
193
*/
194
folded = malloc(ec->ec_blocklen, M_GSSAPI, M_WAITOK);
195
krb5_n_fold(folded, ec->ec_blocklen, constant, constantlen);
196
197
/*
198
* Generate enough bytes for keybits rounded up to a multiple
199
* of blocklen.
200
*/
201
randomlen = roundup(ec->ec_keybits / 8, ec->ec_blocklen);
202
bytes = malloc(randomlen, M_GSSAPI, M_WAITOK);
203
MGET(m, M_WAITOK, MT_DATA);
204
m->m_len = ec->ec_blocklen;
205
for (i = 0, p = bytes, q = folded; i < randomlen;
206
q = p, i += ec->ec_blocklen, p += ec->ec_blocklen) {
207
bcopy(q, m->m_data, ec->ec_blocklen);
208
krb5_encrypt(inkey, m, 0, ec->ec_blocklen, NULL, 0);
209
bcopy(m->m_data, p, ec->ec_blocklen);
210
}
211
m_free(m);
212
213
dk = krb5_create_key(ec);
214
krb5_random_to_key(dk, bytes);
215
216
free(folded, M_GSSAPI);
217
free(bytes, M_GSSAPI);
218
219
return (dk);
220
}
221
222
static struct krb5_key_state *
223
krb5_get_usage_key(struct krb5_key_state *basekey, int usage, int which)
224
{
225
const struct krb5_encryption_class *ec = basekey->ks_class;
226
227
if (ec->ec_flags & EC_DERIVED_KEYS) {
228
uint8_t constant[5];
229
230
constant[0] = usage >> 24;
231
constant[1] = usage >> 16;
232
constant[2] = usage >> 8;
233
constant[3] = usage;
234
constant[4] = which;
235
return (krb5_derive_key(basekey, constant, 5));
236
} else {
237
refcount_acquire(&basekey->ks_refs);
238
return (basekey);
239
}
240
}
241
242
struct krb5_key_state *
243
krb5_get_encryption_key(struct krb5_key_state *basekey, int usage)
244
{
245
246
return (krb5_get_usage_key(basekey, usage, 0xaa));
247
}
248
249
struct krb5_key_state *
250
krb5_get_integrity_key(struct krb5_key_state *basekey, int usage)
251
{
252
253
return (krb5_get_usage_key(basekey, usage, 0x55));
254
}
255
256
struct krb5_key_state *
257
krb5_get_checksum_key(struct krb5_key_state *basekey, int usage)
258
{
259
260
return (krb5_get_usage_key(basekey, usage, 0x99));
261
}
262
263