*** empty log message ***
[arla.git] / rxgk / rxgk_hcrypto.c
blobe160dc80060a1ab0d2797b49337947da9ca4034f
1 /*
2 * Copyright (c) 2002 - 2007, Stockholms universitet
3 * (Stockholm University, Stockholm Sweden)
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * 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.
17 * 3. Neither the name of the university nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
34 #include "rxgk_locl.h"
35 #include <errno.h>
37 RCSID("$Id$");
39 #ifdef AFS_HCRYPTO
41 krb5_context _rxgkk5ctx;
43 void
44 rxgk_crypto_start(void)
46 if (_rxgkk5ctx == NULL)
47 krb5_init_context(&_rxgkk5ctx);
50 int
51 rxgk_crypto_init(struct rxgk_keyblock *tk, key_stuff *k)
53 krb5_keyblock tk_kb;
54 int ret;
56 ret = krb5_keyblock_init(_rxgkk5ctx, tk->enctype, tk->data, tk->length,
57 &tk_kb);
59 if (ret)
60 return EINVAL;
62 ret = krb5_crypto_init (_rxgkk5ctx, &tk_kb, tk->enctype, &k->ks_scrypto);
63 krb5_free_keyblock_contents(_rxgkk5ctx, &tk_kb);
64 if (ret)
65 return EINVAL;
67 k->ks_overhead = krb5_crypto_overhead(_rxgkk5ctx, k->ks_scrypto);
70 krb5_cksumtype type;
71 ret = krb5_crypto_get_checksum_type(_rxgkk5ctx, k->ks_scrypto, &type);
72 ret = krb5_checksumsize(_rxgkk5ctx, type, &k->ks_cksumsize);
75 return 0;
78 struct rxgk_pkg_hdr {
79 uint32_t call_number;
80 uint32_t channel_and_seq;
81 uint32_t svcid_len;
84 static void
85 getheader(struct rx_connection *conn,
86 struct rx_packet *pkt,
87 struct rxgk_pkg_hdr *h)
89 uint32_t t;
91 /* Collect selected pkt fields */
92 h->call_number = htonl(pkt->header.callNumber);
93 t = ((pkt->header.cid & RX_CHANNELMASK) << (32 - RX_CIDSHIFT))
94 | ((pkt->header.seq & 0x3fffffff));
95 h->channel_and_seq = htonl(t);
98 int
99 rxgk_prepare_packet(struct rx_packet *p, struct rx_connection *conn,
100 int level, key_stuff *k, end_stuff *e,
101 int keyusage_enc, int keyusage_mic)
103 size_t len = rx_GetDataSize(p);
104 size_t off = rx_GetSecurityHeaderSize(conn);
105 int ret;
107 if (level == RXGK_WIRE_ENCRYPT) {
108 krb5_data plain, cipher;
109 struct rxgk_pkg_hdr hdr;
111 memset(&cipher, 0, sizeof(cipher));
113 assert(sizeof(hdr) == off);
115 plain.length = len + sizeof(hdr);
116 plain.data = osi_Alloc(plain.length);
118 getheader(conn, p, &hdr);
119 hdr.svcid_len = htonl((conn->serviceId << 16) | rx_GetDataSize(p));
120 memcpy(plain.data, &hdr, sizeof(hdr));
122 rx_packetread(p, off, len, (unsigned char*)plain.data + sizeof(hdr));
124 ret = krb5_encrypt(_rxgkk5ctx, k->ks_scrypto, keyusage_enc,
125 plain.data, plain.length, &cipher);
126 osi_Free(plain.data, plain.length);
128 if (ret == 0) {
129 if (cipher.length > len + sizeof(hdr))
130 rxi_RoundUpPacket(p, cipher.length - len - sizeof(hdr));
131 rx_packetwrite(p, 0, cipher.length, cipher.data);
132 rx_SetDataSize(p, cipher.length);
133 krb5_data_free(&cipher);
135 } else if (level == RXGK_WIRE_INTEGRITY) {
136 krb5_checksum cksum;
137 krb5_data scratch;
139 memset(&cksum, 0, sizeof(cksum));
141 scratch.length = len;
142 scratch.data = osi_Alloc(scratch.length);
144 rx_packetread(p, off, len, scratch.data);
146 ret = krb5_create_checksum(_rxgkk5ctx, k->ks_scrypto, keyusage_mic, 0,
147 scratch.data, scratch.length, &cksum);
148 osi_Free(scratch.data, scratch.length);
149 rx_SetDataSize(p, len);
151 /* write header into trailier */
153 } else if (level == RXGK_WIRE_AUTH_ONLY) {
154 ret = 0;
155 } else {
156 abort();
158 return ret;
165 rxgk_check_packet(struct rx_packet *p, struct rx_connection *conn,
166 int level, key_stuff *k, end_stuff *e,
167 int keyusage_enc, int keyusage_mic)
169 size_t len = rx_GetDataSize(p);
170 size_t off = rx_GetSecurityHeaderSize(conn);
171 int ret;
173 if (level == RXGK_WIRE_ENCRYPT) {
174 krb5_data cipher, plain;
175 struct rxgk_pkg_hdr hdr;
177 plain.data = NULL;
178 plain.length = 0;
180 cipher.length = len;
181 cipher.data = osi_Alloc(cipher.length);
183 getheader(conn, p, &hdr);
184 rx_packetread(p, 0, cipher.length, cipher.data);
186 ret = krb5_decrypt(_rxgkk5ctx, k->ks_scrypto, keyusage_enc,
187 cipher.data, cipher.length, &plain);
188 osi_Free(cipher.data, cipher.length);
189 if (ret == 0) {
190 if (plain.length < sizeof(hdr)) {
191 ret = EINVAL;
192 goto out;
194 if (memcmp(plain.data, &hdr, 8) != 0) {
195 ret = ENOENT;
196 goto out;
198 len = ntohl(((uint32_t *)plain.data)[2]) & 0xffff;
199 if (len > plain.length - sizeof(hdr)) {
200 ret = EIO;
201 goto out;
203 rx_packetwrite(p, off,
204 len,
205 (unsigned char*)plain.data + sizeof(hdr));
206 rx_SetDataSize(p, len);
207 out:
208 krb5_data_free(&plain);
211 } else if (level == RXGK_WIRE_INTEGRITY) {
212 krb5_data scratch;
213 krb5_checksum cksum;
215 memset(&cksum, 0, sizeof(cksum));
217 scratch.length = len;
218 scratch.data = osi_Alloc(scratch.length);
220 rx_Pullup(p, off);
221 rx_packetread(p, off, len-off, scratch.data);
222 scratch.length = len - off;
224 ret = krb5_verify_checksum(_rxgkk5ctx, k->ks_scrypto, keyusage_mic,
225 scratch.data, scratch.length,
226 &cksum);
227 osi_Free(scratch.data, scratch.length);
228 if (ret == 0)
229 rx_SetDataSize(p, len - off);
231 } else if (level == RXGK_WIRE_AUTH_ONLY) {
232 ret = 0;
233 } else {
234 abort();
237 return ret;
241 rxgk_encrypt_buffer(RXGK_Token *in, RXGK_Token *out,
242 struct rxgk_keyblock *key, int keyusage)
244 krb5_keyblock keyblock;
245 krb5_crypto crypto;
246 krb5_data data;
247 int ret;
249 ret = krb5_keyblock_init(_rxgkk5ctx, key->enctype,
250 key->data, key->length, &keyblock);
251 if (ret)
252 return EINVAL;
254 ret = krb5_crypto_init(_rxgkk5ctx, &keyblock, 0, &crypto);
255 krb5_free_keyblock_contents(_rxgkk5ctx, &keyblock);
256 if (ret)
257 return EINVAL;
259 ret = krb5_encrypt(_rxgkk5ctx, crypto, keyusage, in->val, in->len, &data);
260 krb5_crypto_destroy(_rxgkk5ctx, crypto);
262 out->val = data.data;
263 out->len = data.length;
265 return ret;
269 rxgk_decrypt_buffer(RXGK_Token *in, RXGK_Token *out,
270 struct rxgk_keyblock *key, int keyusage)
272 krb5_keyblock keyblock;
273 krb5_crypto crypto;
274 krb5_data data;
275 int ret;
277 ret = krb5_keyblock_init(_rxgkk5ctx, key->enctype,
278 key->data, key->length, &keyblock);
279 if (ret)
280 return EINVAL;
282 ret = krb5_crypto_init(_rxgkk5ctx, &keyblock, 0, &crypto);
283 krb5_free_keyblock_contents(_rxgkk5ctx, &keyblock);
284 if (ret)
285 return EINVAL;
287 ret = krb5_decrypt(_rxgkk5ctx, crypto, keyusage, in->val, in->len, &data);
288 krb5_crypto_destroy(_rxgkk5ctx, crypto);
290 out->val = data.data;
291 out->len = data.length;
293 return ret;
296 #if DEBUG
297 static void
298 print_key(char *name, struct rxgk_keyblock *key)
300 int i;
302 fprintf(stderr, "type: %s", name);
303 for (i = 0; i < key->length; i++)
304 fprintf(stderr, " %02x", ((unsigned char*)key->data)[i]);
305 fprintf(stderr, "\n");
307 #endif
310 rxgk_derive_transport_key(struct rxgk_keyblock *k0,
311 struct rxgk_keyblock *tk,
312 uint32_t epoch, uint32_t cid, int64_t start_time)
314 int i;
315 uint32_t x;
316 /* XXX get real key */
318 if (k0->enctype != RXGK_CRYPTO_AES256_CTS_HMAC_SHA1_96) {
319 return EINVAL;
322 tk->length = 32;
323 tk->enctype = RXGK_CRYPTO_AES256_CTS_HMAC_SHA1_96;
325 tk->data = malloc(tk->length);
326 if (tk->data == NULL)
327 return ENOMEM;
329 x = epoch * 4711 + cid * 33 + start_time;
330 for (i = 0; i < tk->length; i++) {
331 x += i * 3 + ((unsigned char *)k0->data)[i%k0->length];
332 ((unsigned char *)tk->data)[i] = 0x23 + x * 47;
335 #if DEBUG
336 print_key("k0: ", k0);
337 print_key("tk: ", tk);
338 #endif
340 return 0;
343 #endif /* AFS_HCRYPTO */