1120945Snectar/*
2233294Sstas * Copyright (c) 2003 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5120945Snectar *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9120945Snectar *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12120945Snectar *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16120945Snectar *
17120945Snectar * 3. Neither the name of KTH nor the names of its contributors may be
18120945Snectar *    used to endorse or promote products derived from this software without
19120945Snectar *    specific prior written permission.
20120945Snectar *
21120945Snectar * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22120945Snectar * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23120945Snectar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24120945Snectar * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25120945Snectar * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26120945Snectar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27120945Snectar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28120945Snectar * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29120945Snectar * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30120945Snectar * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31120945Snectar * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
32120945Snectar
33120945Snectar#include "krb5_locl.h"
34178825Sdfr#include <hex.h>
35178825Sdfr#include <err.h>
36233294Sstas#include <assert.h>
37120945Snectar
38120945Snectar#ifdef HAVE_OPENSSL
39120945Snectar#include <openssl/evp.h>
40120945Snectar#endif
41120945Snectar
42120945Snectarstatic int verbose = 0;
43120945Snectar
44120945Snectarstatic void
45178825Sdfrhex_dump_data(const void *data, size_t length)
46120945Snectar{
47178825Sdfr    char *p;
48120945Snectar
49178825Sdfr    hex_encode(data, length, &p);
50178825Sdfr    printf("%s\n", p);
51178825Sdfr    free(p);
52120945Snectar}
53120945Snectar
54120945Snectarstruct {
55120945Snectar    char *password;
56120945Snectar    char *salt;
57120945Snectar    int saltlen;
58120945Snectar    int iterations;
59120945Snectar    krb5_enctype enctype;
60178825Sdfr    size_t keylen;
61120945Snectar    char *pbkdf2;
62120945Snectar    char *key;
63120945Snectar} keys[] = {
64233294Sstas    {
65120945Snectar	"password", "ATHENA.MIT.EDUraeburn", -1,
66233294Sstas	1,
67120945Snectar	ETYPE_AES128_CTS_HMAC_SHA1_96, 16,
68120945Snectar	"\xcd\xed\xb5\x28\x1b\xb2\xf8\x01\x56\x5a\x11\x22\xb2\x56\x35\x15",
69120945Snectar	"\x42\x26\x3c\x6e\x89\xf4\xfc\x28\xb8\xdf\x68\xee\x09\x79\x9f\x15"
70120945Snectar    },
71120945Snectar    {
72120945Snectar	"password", "ATHENA.MIT.EDUraeburn", -1,
73233294Sstas	1,
74120945Snectar	ETYPE_AES256_CTS_HMAC_SHA1_96, 32,
75120945Snectar	"\xcd\xed\xb5\x28\x1b\xb2\xf8\x01\x56\x5a\x11\x22\xb2\x56\x35\x15"
76120945Snectar	"\x0a\xd1\xf7\xa0\x4b\xb9\xf3\xa3\x33\xec\xc0\xe2\xe1\xf7\x08\x37",
77120945Snectar	"\xfe\x69\x7b\x52\xbc\x0d\x3c\xe1\x44\x32\xba\x03\x6a\x92\xe6\x5b"
78120945Snectar	"\xbb\x52\x28\x09\x90\xa2\xfa\x27\x88\x39\x98\xd7\x2a\xf3\x01\x61"
79120945Snectar    },
80120945Snectar    {
81120945Snectar	"password", "ATHENA.MIT.EDUraeburn", -1,
82120945Snectar	2,
83120945Snectar	ETYPE_AES128_CTS_HMAC_SHA1_96, 16,
84120945Snectar	"\x01\xdb\xee\x7f\x4a\x9e\x24\x3e\x98\x8b\x62\xc7\x3c\xda\x93\x5d",
85120945Snectar	"\xc6\x51\xbf\x29\xe2\x30\x0a\xc2\x7f\xa4\x69\xd6\x93\xbd\xda\x13"
86120945Snectar    },
87120945Snectar    {
88120945Snectar	"password", "ATHENA.MIT.EDUraeburn", -1,
89233294Sstas	2,
90120945Snectar	ETYPE_AES256_CTS_HMAC_SHA1_96, 32,
91120945Snectar	"\x01\xdb\xee\x7f\x4a\x9e\x24\x3e\x98\x8b\x62\xc7\x3c\xda\x93\x5d"
92120945Snectar	"\xa0\x53\x78\xb9\x32\x44\xec\x8f\x48\xa9\x9e\x61\xad\x79\x9d\x86",
93120945Snectar	"\xa2\xe1\x6d\x16\xb3\x60\x69\xc1\x35\xd5\xe9\xd2\xe2\x5f\x89\x61"
94120945Snectar	"\x02\x68\x56\x18\xb9\x59\x14\xb4\x67\xc6\x76\x22\x22\x58\x24\xff"
95120945Snectar    },
96120945Snectar    {
97120945Snectar	"password", "ATHENA.MIT.EDUraeburn", -1,
98233294Sstas	1200,
99120945Snectar	ETYPE_AES128_CTS_HMAC_SHA1_96, 16,
100120945Snectar	"\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b",
101120945Snectar	"\x4c\x01\xcd\x46\xd6\x32\xd0\x1e\x6d\xbe\x23\x0a\x01\xed\x64\x2a"
102120945Snectar    },
103120945Snectar    {
104120945Snectar	"password", "ATHENA.MIT.EDUraeburn", -1,
105233294Sstas	1200,
106120945Snectar	ETYPE_AES256_CTS_HMAC_SHA1_96, 32,
107120945Snectar	"\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b"
108120945Snectar	"\xa7\xe5\x2d\xdb\xc5\xe5\x14\x2f\x70\x8a\x31\xe2\xe6\x2b\x1e\x13",
109120945Snectar	"\x55\xa6\xac\x74\x0a\xd1\x7b\x48\x46\x94\x10\x51\xe1\xe8\xb0\xa7"
110120945Snectar	"\x54\x8d\x93\xb0\xab\x30\xa8\xbc\x3f\xf1\x62\x80\x38\x2b\x8c\x2a"
111120945Snectar    },
112120945Snectar    {
113120945Snectar	"password", "\x12\x34\x56\x78\x78\x56\x34\x12", 8,
114120945Snectar	5,
115120945Snectar	ETYPE_AES128_CTS_HMAC_SHA1_96, 16,
116120945Snectar	"\xd1\xda\xa7\x86\x15\xf2\x87\xe6\xa1\xc8\xb1\x20\xd7\x06\x2a\x49",
117120945Snectar	"\xe9\xb2\x3d\x52\x27\x37\x47\xdd\x5c\x35\xcb\x55\xbe\x61\x9d\x8e"
118120945Snectar    },
119120945Snectar    {
120120945Snectar	"password", "\x12\x34\x56\x78\x78\x56\x34\x12", 8,
121120945Snectar	5,
122120945Snectar	ETYPE_AES256_CTS_HMAC_SHA1_96, 32,
123120945Snectar	"\xd1\xda\xa7\x86\x15\xf2\x87\xe6\xa1\xc8\xb1\x20\xd7\x06\x2a\x49"
124120945Snectar	"\x3f\x98\xd2\x03\xe6\xbe\x49\xa6\xad\xf4\xfa\x57\x4b\x6e\x64\xee",
125120945Snectar	"\x97\xa4\xe7\x86\xbe\x20\xd8\x1a\x38\x2d\x5e\xbc\x96\xd5\x90\x9c"
126120945Snectar	"\xab\xcd\xad\xc8\x7c\xa4\x8f\x57\x45\x04\x15\x9f\x16\xc3\x6e\x31"
127120945Snectar    },
128120945Snectar    {
129120945Snectar	"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
130120945Snectar	"pass phrase equals block size", -1,
131120945Snectar	1200,
132120945Snectar	ETYPE_AES128_CTS_HMAC_SHA1_96, 16,
133120945Snectar	"\x13\x9c\x30\xc0\x96\x6b\xc3\x2b\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9",
134120945Snectar	"\x59\xd1\xbb\x78\x9a\x82\x8b\x1a\xa5\x4e\xf9\xc2\x88\x3f\x69\xed"
135120945Snectar    },
136120945Snectar    {
137120945Snectar	"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
138120945Snectar	"pass phrase equals block size", -1,
139120945Snectar	1200,
140120945Snectar	ETYPE_AES256_CTS_HMAC_SHA1_96, 32,
141120945Snectar	"\x13\x9c\x30\xc0\x96\x6b\xc3\x2b\xa5\x5f\xdb\xf2\x12\x53\x0a\xc9"
142120945Snectar	"\xc5\xec\x59\xf1\xa4\x52\xf5\xcc\x9a\xd9\x40\xfe\xa0\x59\x8e\xd1",
143120945Snectar	"\x89\xad\xee\x36\x08\xdb\x8b\xc7\x1f\x1b\xfb\xfe\x45\x94\x86\xb0"
144120945Snectar	"\x56\x18\xb7\x0c\xba\xe2\x20\x92\x53\x4e\x56\xc5\x53\xba\x4b\x34"
145120945Snectar    },
146120945Snectar    {
147120945Snectar	"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
148120945Snectar	"pass phrase exceeds block size", -1,
149120945Snectar	1200,
150120945Snectar	ETYPE_AES128_CTS_HMAC_SHA1_96, 16,
151120945Snectar	"\x9c\xca\xd6\xd4\x68\x77\x0c\xd5\x1b\x10\xe6\xa6\x87\x21\xbe\x61",
152120945Snectar	"\xcb\x80\x05\xdc\x5f\x90\x17\x9a\x7f\x02\x10\x4c\x00\x18\x75\x1d"
153120945Snectar    },
154120945Snectar    {
155120945Snectar	"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
156120945Snectar	"pass phrase exceeds block size", -1,
157120945Snectar	1200,
158120945Snectar	ETYPE_AES256_CTS_HMAC_SHA1_96, 32,
159120945Snectar	"\x9c\xca\xd6\xd4\x68\x77\x0c\xd5\x1b\x10\xe6\xa6\x87\x21\xbe\x61"
160120945Snectar	"\x1a\x8b\x4d\x28\x26\x01\xdb\x3b\x36\xbe\x92\x46\x91\x5e\xc8\x2a",
161120945Snectar	"\xd7\x8c\x5c\x9c\xb8\x72\xa8\xc9\xda\xd4\x69\x7f\x0b\xb5\xb2\xd2"
162120945Snectar	"\x14\x96\xc8\x2b\xeb\x2c\xae\xda\x21\x12\xfc\xee\xa0\x57\x40\x1b"
163120945Snectar
164120945Snectar    },
165120945Snectar    {
166120945Snectar	"\xf0\x9d\x84\x9e" /* g-clef */, "EXAMPLE.COMpianist", -1,
167120945Snectar	50,
168120945Snectar	ETYPE_AES128_CTS_HMAC_SHA1_96, 16,
169120945Snectar	"\x6b\x9c\xf2\x6d\x45\x45\x5a\x43\xa5\xb8\xbb\x27\x6a\x40\x3b\x39",
170120945Snectar	"\xf1\x49\xc1\xf2\xe1\x54\xa7\x34\x52\xd4\x3e\x7f\xe6\x2a\x56\xe5"
171120945Snectar    },
172120945Snectar    {
173120945Snectar	"\xf0\x9d\x84\x9e" /* g-clef */, "EXAMPLE.COMpianist", -1,
174120945Snectar	50,
175120945Snectar	ETYPE_AES256_CTS_HMAC_SHA1_96, 32,
176120945Snectar	"\x6b\x9c\xf2\x6d\x45\x45\x5a\x43\xa5\xb8\xbb\x27\x6a\x40\x3b\x39"
177120945Snectar	"\xe7\xfe\x37\xa0\xc4\x1e\x02\xc2\x81\xff\x30\x69\xe1\xe9\x4f\x52",
178120945Snectar	"\x4b\x6d\x98\x39\xf8\x44\x06\xdf\x1f\x09\xcc\x16\x6d\xb4\xb8\x3c"
179120945Snectar	"\x57\x18\x48\xb7\x84\xa3\xd6\xbd\xc3\x46\x58\x9a\x3e\x39\x3f\x9e"
180120945Snectar    },
181120945Snectar    {
182233294Sstas	"foo", "", -1,
183120945Snectar	0,
184120945Snectar	ETYPE_ARCFOUR_HMAC_MD5, 16,
185120945Snectar	NULL,
186120945Snectar	"\xac\x8e\x65\x7f\x83\xdf\x82\xbe\xea\x5d\x43\xbd\xaf\x78\x00\xcc"
187120945Snectar    },
188120945Snectar    {
189233294Sstas	"test", "", -1,
190120945Snectar	0,
191120945Snectar	ETYPE_ARCFOUR_HMAC_MD5, 16,
192120945Snectar	NULL,
193120945Snectar	"\x0c\xb6\x94\x88\x05\xf7\x97\xbf\x2a\x82\x80\x79\x73\xb8\x95\x37"
194120945Snectar    }
195120945Snectar};
196120945Snectar
197120945Snectarstatic int
198120945Snectarstring_to_key_test(krb5_context context)
199120945Snectar{
200120945Snectar    krb5_data password, opaque;
201120945Snectar    krb5_error_code ret;
202120945Snectar    krb5_salt salt;
203120945Snectar    int i, val = 0;
204120945Snectar    char iter[4];
205120945Snectar
206120945Snectar    for (i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) {
207120945Snectar
208120945Snectar	password.data = keys[i].password;
209120945Snectar	password.length = strlen(password.data);
210120945Snectar
211120945Snectar	salt.salttype = KRB5_PW_SALT;
212120945Snectar	salt.saltvalue.data = keys[i].salt;
213120945Snectar	if (keys[i].saltlen == -1)
214120945Snectar	    salt.saltvalue.length = strlen(salt.saltvalue.data);
215120945Snectar	else
216120945Snectar	    salt.saltvalue.length = keys[i].saltlen;
217233294Sstas
218120945Snectar	opaque.data = iter;
219120945Snectar	opaque.length = sizeof(iter);
220120945Snectar	_krb5_put_int(iter, keys[i].iterations, 4);
221233294Sstas
222178825Sdfr	if (keys[i].pbkdf2) {
223178825Sdfr	    unsigned char keyout[32];
224120945Snectar
225178825Sdfr	    if (keys[i].keylen > sizeof(keyout))
226178825Sdfr		abort();
227120945Snectar
228120945Snectar	    PKCS5_PBKDF2_HMAC_SHA1(password.data, password.length,
229120945Snectar				   salt.saltvalue.data, salt.saltvalue.length,
230233294Sstas				   keys[i].iterations,
231120945Snectar				   keys[i].keylen, keyout);
232233294Sstas
233120945Snectar	    if (memcmp(keyout, keys[i].pbkdf2, keys[i].keylen) != 0) {
234178825Sdfr		krb5_warnx(context, "%d: pbkdf2", i);
235120945Snectar		val = 1;
236120945Snectar		continue;
237120945Snectar	    }
238233294Sstas
239178825Sdfr	    if (verbose) {
240178825Sdfr		printf("PBKDF2:\n");
241178825Sdfr		hex_dump_data(keyout, keys[i].keylen);
242178825Sdfr	    }
243178825Sdfr	}
244178825Sdfr
245178825Sdfr	{
246178825Sdfr	    krb5_keyblock key;
247178825Sdfr
248178825Sdfr	    ret = krb5_string_to_key_data_salt_opaque (context,
249178825Sdfr						       keys[i].enctype,
250233294Sstas						       password,
251233294Sstas						       salt,
252233294Sstas						       opaque,
253178825Sdfr						       &key);
254120945Snectar	    if (ret) {
255233294Sstas		krb5_warn(context, ret, "%d: string_to_key_data_salt_opaque",
256178825Sdfr			  i);
257120945Snectar		val = 1;
258120945Snectar		continue;
259120945Snectar	    }
260233294Sstas
261120945Snectar	    if (key.keyvalue.length != keys[i].keylen) {
262178825Sdfr		krb5_warnx(context, "%d: key wrong length (%lu/%lu)",
263233294Sstas			   i, (unsigned long)key.keyvalue.length,
264178825Sdfr			   (unsigned long)keys[i].keylen);
265120945Snectar		val = 1;
266120945Snectar		continue;
267120945Snectar	    }
268233294Sstas
269178825Sdfr	    if (memcmp(key.keyvalue.data, keys[i].key, keys[i].keylen) != 0) {
270178825Sdfr		krb5_warnx(context, "%d: key wrong", i);
271120945Snectar		val = 1;
272120945Snectar		continue;
273120945Snectar	    }
274233294Sstas
275120945Snectar	    if (verbose) {
276178825Sdfr		printf("key:\n");
277178825Sdfr		hex_dump_data(key.keyvalue.data, key.keyvalue.length);
278120945Snectar	    }
279120945Snectar	    krb5_free_keyblock_contents(context, &key);
280120945Snectar	}
281120945Snectar    }
282120945Snectar    return val;
283120945Snectar}
284120945Snectar
285233294Sstasstatic int
286233294Sstaskrb_enc(krb5_context context,
287233294Sstas	krb5_crypto crypto,
288233294Sstas	unsigned usage,
289233294Sstas	krb5_data *cipher,
290233294Sstas	krb5_data *clear)
291233294Sstas{
292233294Sstas    krb5_data decrypt;
293233294Sstas    krb5_error_code ret;
294178825Sdfr
295233294Sstas    krb5_data_zero(&decrypt);
296233294Sstas
297233294Sstas    ret = krb5_decrypt(context,
298233294Sstas		       crypto,
299233294Sstas		       usage,
300233294Sstas		       cipher->data,
301233294Sstas		       cipher->length,
302233294Sstas		       &decrypt);
303233294Sstas
304233294Sstas    if (ret) {
305233294Sstas	krb5_warn(context, ret, "krb5_decrypt");
306233294Sstas	return ret;
307120945Snectar    }
308178825Sdfr
309233294Sstas    if (decrypt.length != clear->length ||
310233294Sstas	memcmp(decrypt.data, clear->data, decrypt.length) != 0) {
311233294Sstas	krb5_warnx(context, "clear text not same");
312233294Sstas	return EINVAL;
313178825Sdfr    }
314178825Sdfr
315233294Sstas    krb5_data_free(&decrypt);
316178825Sdfr
317233294Sstas    return 0;
318233294Sstas}
319178825Sdfr
320233294Sstasstatic int
321233294Sstaskrb_enc_iov2(krb5_context context,
322233294Sstas	     krb5_crypto crypto,
323233294Sstas	     unsigned usage,
324233294Sstas	     size_t cipher_len,
325233294Sstas	     krb5_data *clear)
326233294Sstas{
327233294Sstas    krb5_crypto_iov iov[4];
328233294Sstas    krb5_data decrypt;
329233294Sstas    int ret;
330233294Sstas    char *p, *q;
331233294Sstas    size_t len, i;
332120945Snectar
333233294Sstas    p = clear->data;
334233294Sstas    len = clear->length;
335178825Sdfr
336233294Sstas    iov[0].flags = KRB5_CRYPTO_TYPE_HEADER;
337233294Sstas    krb5_crypto_length(context, crypto, iov[0].flags, &iov[0].data.length);
338233294Sstas    iov[0].data.data = emalloc(iov[0].data.length);
339178825Sdfr
340233294Sstas    iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
341233294Sstas    iov[1].data.length = len;
342233294Sstas    iov[1].data.data = emalloc(iov[1].data.length);
343233294Sstas    memcpy(iov[1].data.data, p, iov[1].data.length);
344120945Snectar
345233294Sstas    /* padding buffer */
346233294Sstas    iov[2].flags = KRB5_CRYPTO_TYPE_PADDING;
347233294Sstas    krb5_crypto_length(context, crypto, KRB5_CRYPTO_TYPE_PADDING, &iov[2].data.length);
348233294Sstas    iov[2].data.data = emalloc(iov[2].data.length);
349233294Sstas
350233294Sstas    iov[3].flags = KRB5_CRYPTO_TYPE_TRAILER;
351233294Sstas    krb5_crypto_length(context, crypto, iov[3].flags, &iov[3].data.length);
352233294Sstas    iov[3].data.data = emalloc(iov[3].data.length);
353233294Sstas
354233294Sstas    ret = krb5_encrypt_iov_ivec(context, crypto, usage,
355233294Sstas				iov, sizeof(iov)/sizeof(iov[0]), NULL);
356233294Sstas    if (ret)
357233294Sstas	errx(1, "encrypt iov failed: %d", ret);
358233294Sstas
359233294Sstas    /* check len */
360233294Sstas    for (i = 0, len = 0; i < sizeof(iov)/sizeof(iov[0]); i++)
361233294Sstas	len += iov[i].data.length;
362233294Sstas    if (len != cipher_len)
363233294Sstas	errx(1, "cipher len wrong");
364233294Sstas
365233294Sstas    /*
366233294Sstas     * Plain decrypt
367233294Sstas     */
368233294Sstas
369233294Sstas    p = q = emalloc(len);
370233294Sstas    for (i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) {
371233294Sstas	memcpy(q, iov[i].data.data, iov[i].data.length);
372233294Sstas	q += iov[i].data.length;
373120945Snectar    }
374120945Snectar
375233294Sstas    ret = krb5_decrypt(context, crypto, usage, p, len, &decrypt);
376233294Sstas    if (ret)
377233294Sstas	krb5_err(context, 1, ret, "krb5_decrypt");
378233294Sstas    else
379233294Sstas	krb5_data_free(&decrypt);
380120945Snectar
381233294Sstas    free(p);
382120945Snectar
383233294Sstas    /*
384233294Sstas     * Now decrypt use iov
385233294Sstas     */
386178825Sdfr
387233294Sstas    /* padding turn into data */
388233294Sstas    p = q = emalloc(iov[1].data.length + iov[2].data.length);
389120945Snectar
390233294Sstas    memcpy(q, iov[1].data.data, iov[1].data.length);
391233294Sstas    q += iov[1].data.length;
392233294Sstas    memcpy(q, iov[2].data.data, iov[2].data.length);
393120945Snectar
394233294Sstas    free(iov[1].data.data);
395233294Sstas    free(iov[2].data.data);
396120945Snectar
397233294Sstas    iov[1].data.data = p;
398233294Sstas    iov[1].data.length += iov[2].data.length;
399120945Snectar
400233294Sstas    iov[2].flags = KRB5_CRYPTO_TYPE_EMPTY;
401233294Sstas    iov[2].data.length = 0;
402120945Snectar
403233294Sstas    ret = krb5_decrypt_iov_ivec(context, crypto, usage,
404233294Sstas				iov, sizeof(iov)/sizeof(iov[0]), NULL);
405233294Sstas    free(iov[0].data.data);
406233294Sstas    free(iov[3].data.data);
407120945Snectar
408233294Sstas    if (ret)
409233294Sstas	krb5_err(context, 1, ret, "decrypt iov failed: %d", ret);
410120945Snectar
411233294Sstas    if (clear->length != iov[1].data.length)
412233294Sstas	errx(1, "length incorrect");
413178825Sdfr
414233294Sstas    p = clear->data;
415233294Sstas    if (memcmp(iov[1].data.data, p, iov[1].data.length) != 0)
416233294Sstas	errx(1, "iov[1] incorrect");
417120945Snectar
418233294Sstas    free(iov[1].data.data);
419120945Snectar
420233294Sstas    return 0;
421233294Sstas}
422120945Snectar
423120945Snectar
424233294Sstasstatic int
425233294Sstaskrb_enc_iov(krb5_context context,
426233294Sstas	    krb5_crypto crypto,
427233294Sstas	    unsigned usage,
428233294Sstas	    krb5_data *cipher,
429233294Sstas	    krb5_data *clear)
430233294Sstas{
431233294Sstas    krb5_crypto_iov iov[3];
432233294Sstas    int ret;
433233294Sstas    char *p;
434233294Sstas    size_t len;
435178825Sdfr
436233294Sstas    p = cipher->data;
437233294Sstas    len = cipher->length;
438178825Sdfr
439233294Sstas    iov[0].flags = KRB5_CRYPTO_TYPE_HEADER;
440233294Sstas    krb5_crypto_length(context, crypto, iov[0].flags, &iov[0].data.length);
441233294Sstas    iov[0].data.data = emalloc(iov[0].data.length);
442233294Sstas    memcpy(iov[0].data.data, p, iov[0].data.length);
443233294Sstas    p += iov[0].data.length;
444233294Sstas    len -= iov[0].data.length;
445233294Sstas
446233294Sstas    iov[1].flags = KRB5_CRYPTO_TYPE_TRAILER;
447233294Sstas    krb5_crypto_length(context, crypto, iov[1].flags, &iov[1].data.length);
448233294Sstas    iov[1].data.data = emalloc(iov[1].data.length);
449233294Sstas    memcpy(iov[1].data.data, p + len - iov[1].data.length, iov[1].data.length);
450233294Sstas    len -= iov[1].data.length;
451233294Sstas
452233294Sstas    iov[2].flags = KRB5_CRYPTO_TYPE_DATA;
453233294Sstas    iov[2].data.length = len;
454233294Sstas    iov[2].data.data = emalloc(len);
455233294Sstas    memcpy(iov[2].data.data, p, len);
456233294Sstas
457233294Sstas    ret = krb5_decrypt_iov_ivec(context, crypto, usage,
458233294Sstas				iov, sizeof(iov)/sizeof(iov[0]), NULL);
459233294Sstas    if (ret)
460233294Sstas	krb5_err(context, 1, ret, "krb_enc_iov decrypt iov failed: %d", ret);
461233294Sstas
462233294Sstas    if (clear->length != iov[2].data.length)
463233294Sstas	errx(1, "length incorrect");
464233294Sstas
465233294Sstas    p = clear->data;
466233294Sstas    if (memcmp(iov[2].data.data, p, iov[2].data.length) != 0)
467233294Sstas	errx(1, "iov[2] incorrect");
468233294Sstas
469233294Sstas    free(iov[0].data.data);
470233294Sstas    free(iov[1].data.data);
471233294Sstas    free(iov[2].data.data);
472233294Sstas
473233294Sstas
474233294Sstas    return 0;
475120945Snectar}
476120945Snectar
477178825Sdfrstatic int
478233294Sstaskrb_checksum_iov(krb5_context context,
479233294Sstas		 krb5_crypto crypto,
480233294Sstas		 unsigned usage,
481233294Sstas		 krb5_data *plain)
482178825Sdfr{
483233294Sstas    krb5_crypto_iov iov[4];
484233294Sstas    int ret;
485233294Sstas    char *p;
486233294Sstas    size_t len;
487120945Snectar
488233294Sstas    p = plain->data;
489233294Sstas    len = plain->length;
490178825Sdfr
491233294Sstas    iov[0].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
492233294Sstas    krb5_crypto_length(context, crypto, iov[0].flags, &iov[0].data.length);
493233294Sstas    iov[0].data.data = emalloc(iov[0].data.length);
494178825Sdfr
495233294Sstas    iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
496233294Sstas    iov[1].data.length = len;
497233294Sstas    iov[1].data.data = p;
498178825Sdfr
499233294Sstas    iov[2].flags = KRB5_CRYPTO_TYPE_TRAILER;
500233294Sstas    krb5_crypto_length(context, crypto, iov[0].flags, &iov[2].data.length);
501233294Sstas    iov[2].data.data = malloc(iov[2].data.length);
502178825Sdfr
503233294Sstas    ret = krb5_create_checksum_iov(context, crypto, usage,
504233294Sstas				   iov, sizeof(iov)/sizeof(iov[0]), NULL);
505233294Sstas    if (ret)
506233294Sstas	krb5_err(context, 1, ret, "krb5_create_checksum_iov failed");
507178825Sdfr
508233294Sstas    ret = krb5_verify_checksum_iov(context, crypto, usage, iov, sizeof(iov)/sizeof(iov[0]), NULL);
509233294Sstas    if (ret)
510233294Sstas	krb5_err(context, 1, ret, "krb5_verify_checksum_iov");
511233294Sstas
512233294Sstas    free(iov[0].data.data);
513233294Sstas    free(iov[2].data.data);
514233294Sstas
515178825Sdfr    return 0;
516178825Sdfr}
517178825Sdfr
518233294Sstas
519178825Sdfrstatic int
520178825Sdfrkrb_enc_mit(krb5_context context,
521178825Sdfr	    krb5_enctype enctype,
522178825Sdfr	    krb5_keyblock *key,
523178825Sdfr	    unsigned usage,
524233294Sstas	    krb5_data *cipher,
525178825Sdfr	    krb5_data *clear)
526178825Sdfr{
527233294Sstas#ifndef HEIMDAL_SMALLER
528178825Sdfr    krb5_error_code ret;
529178825Sdfr    krb5_enc_data e;
530178825Sdfr    krb5_data decrypt;
531178825Sdfr    size_t len;
532178825Sdfr
533178825Sdfr    e.kvno = 0;
534178825Sdfr    e.enctype = enctype;
535178825Sdfr    e.ciphertext = *cipher;
536178825Sdfr
537178825Sdfr    ret = krb5_c_decrypt(context, *key, usage, NULL, &e, &decrypt);
538178825Sdfr    if (ret)
539178825Sdfr	return ret;
540178825Sdfr
541178825Sdfr    if (decrypt.length != clear->length ||
542178825Sdfr	memcmp(decrypt.data, clear->data, decrypt.length) != 0) {
543178825Sdfr	krb5_warnx(context, "clear text not same");
544178825Sdfr	return EINVAL;
545178825Sdfr    }
546178825Sdfr
547178825Sdfr    krb5_data_free(&decrypt);
548178825Sdfr
549178825Sdfr    ret = krb5_c_encrypt_length(context, enctype, clear->length, &len);
550178825Sdfr    if (ret)
551178825Sdfr	return ret;
552178825Sdfr
553178825Sdfr    if (len != cipher->length) {
554178825Sdfr	krb5_warnx(context, "c_encrypt_length wrong %lu != %lu",
555178825Sdfr		   (unsigned long)len, (unsigned long)cipher->length);
556178825Sdfr	return EINVAL;
557178825Sdfr    }
558233294Sstas#endif /* HEIMDAL_SMALLER */
559178825Sdfr    return 0;
560178825Sdfr}
561178825Sdfr
562178825Sdfr
563178825Sdfrstruct {
564178825Sdfr    krb5_enctype enctype;
565178825Sdfr    unsigned usage;
566178825Sdfr    size_t keylen;
567178825Sdfr    void *key;
568178825Sdfr    size_t elen;
569178825Sdfr    void* edata;
570178825Sdfr    size_t plen;
571178825Sdfr    void *pdata;
572178825Sdfr} krbencs[] =  {
573233294Sstas    {
574178825Sdfr	ETYPE_AES256_CTS_HMAC_SHA1_96,
575178825Sdfr	7,
576233294Sstas	32,
577178825Sdfr	"\x47\x75\x69\x64\x65\x6c\x69\x6e\x65\x73\x20\x74\x6f\x20\x41\x75"
578178825Sdfr	"\x74\x68\x6f\x72\x73\x20\x6f\x66\x20\x49\x6e\x74\x65\x72\x6e\x65",
579178825Sdfr	44,
580178825Sdfr	"\xcf\x79\x8f\x0d\x76\xf3\xe0\xbe\x8e\x66\x94\x70\xfa\xcc\x9e\x91"
581178825Sdfr	"\xa9\xec\x1c\x5c\x21\xfb\x6e\xef\x1a\x7a\xc8\xc1\xcc\x5a\x95\x24"
582178825Sdfr	"\x6f\x9f\xf4\xd5\xbe\x5d\x59\x97\x44\xd8\x47\xcd",
583178825Sdfr	16,
584178825Sdfr	"\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x2e\x0a"
585178825Sdfr    }
586178825Sdfr};
587178825Sdfr
588178825Sdfr
589178825Sdfrstatic int
590178825Sdfrkrb_enc_test(krb5_context context)
591178825Sdfr{
592178825Sdfr    krb5_error_code ret;
593178825Sdfr    krb5_crypto crypto;
594178825Sdfr    krb5_keyblock kb;
595178825Sdfr    krb5_data cipher, plain;
596233294Sstas    int i;
597178825Sdfr
598178825Sdfr    for (i = 0; i < sizeof(krbencs)/sizeof(krbencs[0]); i++) {
599178825Sdfr
600178825Sdfr	kb.keytype = krbencs[i].enctype;
601178825Sdfr	kb.keyvalue.length = krbencs[i].keylen;
602178825Sdfr	kb.keyvalue.data = krbencs[i].key;
603178825Sdfr
604178825Sdfr	ret = krb5_crypto_init(context, &kb, krbencs[i].enctype, &crypto);
605178825Sdfr
606178825Sdfr	cipher.length = krbencs[i].elen;
607178825Sdfr	cipher.data = krbencs[i].edata;
608178825Sdfr	plain.length = krbencs[i].plen;
609178825Sdfr	plain.data = krbencs[i].pdata;
610233294Sstas
611178825Sdfr	ret = krb_enc(context, crypto, krbencs[i].usage, &cipher, &plain);
612233294Sstas
613233294Sstas	if (ret)
614233294Sstas	    errx(1, "krb_enc failed with %d for test %d", ret, i);
615233294Sstas
616233294Sstas	ret = krb_enc_iov(context, crypto, krbencs[i].usage, &cipher, &plain);
617233294Sstas	if (ret)
618233294Sstas	    errx(1, "krb_enc_iov failed with %d for test %d", ret, i);
619233294Sstas
620233294Sstas	ret = krb_enc_iov2(context, crypto, krbencs[i].usage,
621233294Sstas			   cipher.length, &plain);
622233294Sstas	if (ret)
623233294Sstas	    errx(1, "krb_enc_iov2 failed with %d for test %d", ret, i);
624233294Sstas
625233294Sstas	ret = krb_checksum_iov(context, crypto, krbencs[i].usage, &plain);
626233294Sstas	if (ret)
627233294Sstas	    errx(1, "krb_checksum_iov failed with %d for test %d", ret, i);
628233294Sstas
629178825Sdfr	krb5_crypto_destroy(context, crypto);
630178825Sdfr
631233294Sstas	ret = krb_enc_mit(context, krbencs[i].enctype, &kb,
632178825Sdfr			  krbencs[i].usage, &cipher, &plain);
633233294Sstas	if (ret)
634233294Sstas	    errx(1, "krb_enc_mit failed with %d for test %d", ret, i);
635233294Sstas    }
636178825Sdfr
637233294Sstas    return 0;
638233294Sstas}
639233294Sstas
640233294Sstasstatic int
641233294Sstasiov_test(krb5_context context)
642233294Sstas{
643233294Sstas    krb5_enctype enctype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
644233294Sstas    krb5_error_code ret;
645233294Sstas    krb5_crypto crypto;
646233294Sstas    krb5_keyblock key;
647233294Sstas    krb5_data signonly, in, in2;
648233294Sstas    krb5_crypto_iov iov[6];
649233294Sstas    size_t len, i;
650233294Sstas    unsigned char *base, *p;
651233294Sstas
652233294Sstas    ret = krb5_generate_random_keyblock(context, enctype, &key);
653233294Sstas    if (ret)
654233294Sstas	krb5_err(context, 1, ret, "krb5_generate_random_keyblock");
655233294Sstas
656233294Sstas    ret = krb5_crypto_init(context, &key, 0, &crypto);
657233294Sstas    if (ret)
658233294Sstas	krb5_err(context, 1, ret, "krb5_crypto_init");
659233294Sstas
660233294Sstas
661233294Sstas    ret = krb5_crypto_length(context, crypto, KRB5_CRYPTO_TYPE_HEADER, &len);
662233294Sstas    if (ret)
663233294Sstas	krb5_err(context, 1, ret, "krb5_crypto_length");
664233294Sstas
665233294Sstas    signonly.data = "This should be signed";
666233294Sstas    signonly.length = strlen(signonly.data);
667233294Sstas    in.data = "inputdata";
668233294Sstas    in.length = strlen(in.data);
669233294Sstas
670233294Sstas    in2.data = "INPUTDATA";
671233294Sstas    in2.length = strlen(in2.data);
672233294Sstas
673233294Sstas
674233294Sstas    memset(iov, 0, sizeof(iov));
675233294Sstas
676233294Sstas    iov[0].flags = KRB5_CRYPTO_TYPE_HEADER;
677233294Sstas    iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
678233294Sstas    iov[1].data = in;
679233294Sstas    iov[2].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
680233294Sstas    iov[2].data = signonly;
681233294Sstas    iov[3].flags = KRB5_CRYPTO_TYPE_EMPTY;
682233294Sstas    iov[4].flags = KRB5_CRYPTO_TYPE_PADDING;
683233294Sstas    iov[5].flags = KRB5_CRYPTO_TYPE_TRAILER;
684233294Sstas
685233294Sstas    ret = krb5_crypto_length_iov(context, crypto, iov,
686233294Sstas				 sizeof(iov)/sizeof(iov[0]));
687233294Sstas    if (ret)
688233294Sstas	krb5_err(context, 1, ret, "krb5_crypto_length_iov");
689233294Sstas
690233294Sstas    for (len = 0, i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) {
691233294Sstas	if (iov[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)
692233294Sstas	    continue;
693233294Sstas	len += iov[i].data.length;
694178825Sdfr    }
695178825Sdfr
696233294Sstas    base = emalloc(len);
697233294Sstas
698233294Sstas    /*
699233294Sstas     * Allocate data for the fields
700233294Sstas     */
701233294Sstas
702233294Sstas    for (p = base, i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) {
703233294Sstas	if (iov[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)
704233294Sstas	    continue;;
705233294Sstas	iov[i].data.data = p;
706233294Sstas	p += iov[i].data.length;
707233294Sstas    }
708233294Sstas    assert(iov[1].data.length == in.length);
709233294Sstas    memcpy(iov[1].data.data, in.data, iov[1].data.length);
710233294Sstas
711233294Sstas    /*
712233294Sstas     * Encrypt
713233294Sstas     */
714233294Sstas
715233294Sstas    ret = krb5_encrypt_iov_ivec(context, crypto, 7, iov,
716233294Sstas				sizeof(iov)/sizeof(iov[0]), NULL);
717233294Sstas    if (ret)
718233294Sstas	krb5_err(context, 1, ret, "krb5_encrypt_iov_ivec");
719233294Sstas
720233294Sstas    /*
721233294Sstas     * Decrypt
722233294Sstas     */
723233294Sstas
724233294Sstas    ret = krb5_decrypt_iov_ivec(context, crypto, 7,
725233294Sstas				iov, sizeof(iov)/sizeof(iov[0]), NULL);
726233294Sstas    if (ret)
727233294Sstas	krb5_err(context, 1, ret, "krb5_decrypt_iov_ivec");
728233294Sstas
729233294Sstas    /*
730233294Sstas     * Verify data
731233294Sstas     */
732233294Sstas
733233294Sstas    if (krb5_data_cmp(&iov[1].data, &in) != 0)
734233294Sstas	krb5_errx(context, 1, "decrypted data not same");
735233294Sstas
736233294Sstas    /*
737233294Sstas     * Free memory
738233294Sstas     */
739233294Sstas
740233294Sstas    free(base);
741233294Sstas
742233294Sstas    /* Set up for second try */
743233294Sstas
744233294Sstas    iov[3].flags = KRB5_CRYPTO_TYPE_DATA;
745233294Sstas    iov[3].data = in;
746233294Sstas
747233294Sstas    ret = krb5_crypto_length_iov(context, crypto,
748233294Sstas				 iov, sizeof(iov)/sizeof(iov[0]));
749233294Sstas    if (ret)
750233294Sstas	krb5_err(context, 1, ret, "krb5_crypto_length_iov");
751233294Sstas
752233294Sstas    for (len = 0, i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) {
753233294Sstas	if (iov[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)
754233294Sstas	    continue;
755233294Sstas	len += iov[i].data.length;
756233294Sstas    }
757233294Sstas
758233294Sstas    base = emalloc(len);
759233294Sstas
760233294Sstas    /*
761233294Sstas     * Allocate data for the fields
762233294Sstas     */
763233294Sstas
764233294Sstas    for (p = base, i = 0; i < sizeof(iov)/sizeof(iov[0]); i++) {
765233294Sstas	if (iov[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)
766233294Sstas	    continue;;
767233294Sstas	iov[i].data.data = p;
768233294Sstas	p += iov[i].data.length;
769233294Sstas    }
770233294Sstas    assert(iov[1].data.length == in.length);
771233294Sstas    memcpy(iov[1].data.data, in.data, iov[1].data.length);
772233294Sstas
773233294Sstas    assert(iov[3].data.length == in2.length);
774233294Sstas    memcpy(iov[3].data.data, in2.data, iov[3].data.length);
775233294Sstas
776233294Sstas
777233294Sstas
778233294Sstas    /*
779233294Sstas     * Encrypt
780233294Sstas     */
781233294Sstas
782233294Sstas    ret = krb5_encrypt_iov_ivec(context, crypto, 7,
783233294Sstas				iov, sizeof(iov)/sizeof(iov[0]), NULL);
784233294Sstas    if (ret)
785233294Sstas	krb5_err(context, 1, ret, "krb5_encrypt_iov_ivec");
786233294Sstas
787233294Sstas    /*
788233294Sstas     * Decrypt
789233294Sstas     */
790233294Sstas
791233294Sstas    ret = krb5_decrypt_iov_ivec(context, crypto, 7,
792233294Sstas				iov, sizeof(iov)/sizeof(iov[0]), NULL);
793233294Sstas    if (ret)
794233294Sstas	krb5_err(context, 1, ret, "krb5_decrypt_iov_ivec");
795233294Sstas
796233294Sstas    /*
797233294Sstas     * Verify data
798233294Sstas     */
799233294Sstas
800233294Sstas    if (krb5_data_cmp(&iov[1].data, &in) != 0)
801233294Sstas	krb5_errx(context, 1, "decrypted data 2.1 not same");
802233294Sstas
803233294Sstas    if (krb5_data_cmp(&iov[3].data, &in2) != 0)
804233294Sstas	krb5_errx(context, 1, "decrypted data 2.2 not same");
805233294Sstas
806233294Sstas    /*
807233294Sstas     * Free memory
808233294Sstas     */
809233294Sstas
810233294Sstas    free(base);
811233294Sstas
812233294Sstas    krb5_crypto_destroy(context, crypto);
813233294Sstas
814233294Sstas    krb5_free_keyblock_contents(context, &key);
815233294Sstas
816233294Sstas    return 0;
817178825Sdfr}
818178825Sdfr
819178825Sdfr
820233294Sstas
821178825Sdfrstatic int
822178825Sdfrrandom_to_key(krb5_context context)
823178825Sdfr{
824178825Sdfr    krb5_error_code ret;
825178825Sdfr    krb5_keyblock key;
826178825Sdfr
827178825Sdfr    ret = krb5_random_to_key(context,
828178825Sdfr			     ETYPE_DES3_CBC_SHA1,
829178825Sdfr			     "\x21\x39\x04\x58\x6A\xBD\x7F"
830178825Sdfr			     "\x21\x39\x04\x58\x6A\xBD\x7F"
831178825Sdfr			     "\x21\x39\x04\x58\x6A\xBD\x7F",
832178825Sdfr			     21,
833178825Sdfr			     &key);
834178825Sdfr    if (ret){
835178825Sdfr	krb5_warn(context, ret, "random_to_key");
836178825Sdfr	return 1;
837178825Sdfr    }
838178825Sdfr    if (key.keyvalue.length != 24)
839178825Sdfr	return 1;
840178825Sdfr
841178825Sdfr    if (memcmp(key.keyvalue.data,
842178825Sdfr	       "\x20\x38\x04\x58\x6b\xbc\x7f\xc7"
843178825Sdfr	       "\x20\x38\x04\x58\x6b\xbc\x7f\xc7"
844178825Sdfr	       "\x20\x38\x04\x58\x6b\xbc\x7f\xc7",
845178825Sdfr	       24) != 0)
846178825Sdfr	return 1;
847178825Sdfr
848178825Sdfr    krb5_free_keyblock_contents(context, &key);
849178825Sdfr
850178825Sdfr    return 0;
851178825Sdfr}
852178825Sdfr
853120945Snectarint
854120945Snectarmain(int argc, char **argv)
855120945Snectar{
856120945Snectar    krb5_error_code ret;
857120945Snectar    krb5_context context;
858120945Snectar    int val = 0;
859233294Sstas
860120945Snectar    ret = krb5_init_context (&context);
861120945Snectar    if (ret)
862120945Snectar	errx (1, "krb5_init_context failed: %d", ret);
863120945Snectar
864120945Snectar    val |= string_to_key_test(context);
865120945Snectar
866178825Sdfr    val |= krb_enc_test(context);
867178825Sdfr    val |= random_to_key(context);
868233294Sstas    val |= iov_test(context);
869120945Snectar
870120945Snectar    if (verbose && val == 0)
871120945Snectar	printf("all ok\n");
872120945Snectar    if (val)
873120945Snectar	printf("tests failed\n");
874120945Snectar
875120945Snectar    krb5_free_context(context);
876120945Snectar
877120945Snectar    return val;
878120945Snectar}
879