1108833Ssam/* $FreeBSD$ */
2108833Ssam/*
3108833Ssam * The big num stuff is a bit broken at the moment and I've not yet fixed it.
4108833Ssam * The symtom is that odd size big nums will fail.  Test code below (it only
5108833Ssam * uses modexp currently).
6108833Ssam *
7108833Ssam * --Jason L. Wright
8108833Ssam */
9108833Ssam#include <sys/types.h>
10108833Ssam#include <sys/ioctl.h>
11108833Ssam#include <machine/endian.h>
12108833Ssam#include <sys/time.h>
13108833Ssam#include <crypto/cryptodev.h>
14108833Ssam#include <openssl/bn.h>
15167755Ssam
16167755Ssam#include <paths.h>
17108833Ssam#include <fcntl.h>
18108833Ssam#include <err.h>
19108833Ssam#include <string.h>
20108833Ssam#include <unistd.h>
21108833Ssam#include <stdlib.h>
22108833Ssam
23167755Ssamint	crid = CRYPTO_FLAG_HARDWARE;
24167755Ssamint	verbose = 0;
25108833Ssam
26167755Ssamstatic int
27167755Ssamdevcrypto(void)
28167755Ssam{
29167755Ssam	static int fd = -1;
30167755Ssam
31167755Ssam	if (fd < 0) {
32167755Ssam		fd = open(_PATH_DEV "crypto", O_RDWR, 0);
33167755Ssam		if (fd < 0)
34167755Ssam			err(1, _PATH_DEV "crypto");
35167755Ssam		if (fcntl(fd, F_SETFD, 1) == -1)
36167755Ssam			err(1, "fcntl(F_SETFD) (devcrypto)");
37167755Ssam	}
38167755Ssam	return fd;
39167755Ssam}
40167755Ssam
41167755Ssamstatic int
42167755Ssamcrlookup(const char *devname)
43167755Ssam{
44167755Ssam	struct crypt_find_op find;
45167755Ssam
46167755Ssam	find.crid = -1;
47167755Ssam	strlcpy(find.name, devname, sizeof(find.name));
48167755Ssam	if (ioctl(devcrypto(), CIOCFINDDEV, &find) == -1)
49167755Ssam		err(1, "ioctl(CIOCFINDDEV)");
50167755Ssam	return find.crid;
51167755Ssam}
52167755Ssam
53167755Ssamstatic const char *
54167755Ssamcrfind(int crid)
55167755Ssam{
56167755Ssam	static struct crypt_find_op find;
57167755Ssam
58167755Ssam	bzero(&find, sizeof(find));
59167755Ssam	find.crid = crid;
60167755Ssam	if (ioctl(devcrypto(), CIOCFINDDEV, &find) == -1)
61167755Ssam		err(1, "ioctl(CIOCFINDDEV)");
62167755Ssam	return find.name;
63167755Ssam}
64167755Ssam
65108833Ssam/*
66108833Ssam * Convert a little endian byte string in 'p' that
67108833Ssam * is 'plen' bytes long to a BIGNUM. If 'dst' is NULL,
68108833Ssam * a new BIGNUM is allocated.  Returns NULL on failure.
69108833Ssam *
70108833Ssam * XXX there has got to be a more efficient way to do
71108833Ssam * this, but I haven't figured out enough of the OpenSSL
72108833Ssam * magic.
73108833Ssam */
74108833SsamBIGNUM *
75108833Ssamle_to_bignum(BIGNUM *dst, u_int8_t *p, int plen)
76108833Ssam{
77108833Ssam	u_int8_t *pd;
78108833Ssam	int i;
79108833Ssam
80108833Ssam	if (plen == 0)
81108833Ssam		return (NULL);
82108833Ssam
83108833Ssam	if ((pd = (u_int8_t *)malloc(plen)) == NULL)
84108833Ssam		return (NULL);
85108833Ssam
86108833Ssam	for (i = 0; i < plen; i++)
87108833Ssam		pd[i] = p[plen - i - 1];
88108833Ssam
89108833Ssam	dst = BN_bin2bn(pd, plen, dst);
90108833Ssam	free(pd);
91108833Ssam	return (dst);
92108833Ssam}
93108833Ssam
94108833Ssam/*
95108833Ssam * Convert a BIGNUM to a little endian byte string.
96108833Ssam * If 'rd' is NULL, allocate space for it, otherwise
97108833Ssam * 'rd' is assumed to have room for BN_num_bytes(n)
98108833Ssam * bytes.  Returns NULL on failure.
99108833Ssam */
100108833Ssamu_int8_t *
101108833Ssambignum_to_le(BIGNUM *n, u_int8_t *rd)
102108833Ssam{
103108833Ssam	int i, j, k;
104108833Ssam	int blen = BN_num_bytes(n);
105108833Ssam
106108833Ssam	if (blen == 0)
107108833Ssam		return (NULL);
108108833Ssam	if (rd == NULL)
109108833Ssam		rd = (u_int8_t *)malloc(blen);
110108833Ssam	if (rd == NULL)
111108833Ssam		return (NULL);
112108833Ssam
113108833Ssam	for (i = 0, j = 0; i < n->top; i++) {
114108833Ssam		for (k = 0; k < BN_BITS2 / 8; k++) {
115108833Ssam			if ((j + k) >= blen)
116108833Ssam				goto out;
117108833Ssam			rd[j + k] = n->d[i] >> (k * 8);
118108833Ssam		}
119108833Ssam		j += BN_BITS2 / 8;
120108833Ssam	}
121108833Ssamout:
122108833Ssam	return (rd);
123108833Ssam}
124108833Ssam
125108833Ssamint
126108833SsamUB_mod_exp(BIGNUM *res, BIGNUM *a, BIGNUM *b, BIGNUM *c, BN_CTX *ctx)
127108833Ssam{
128108833Ssam	struct crypt_kop kop;
129108833Ssam	u_int8_t *ale, *ble, *cle;
130167755Ssam	static int crypto_fd = -1;
131108833Ssam
132167755Ssam	if (crypto_fd == -1 && ioctl(devcrypto(), CRIOGET, &crypto_fd) == -1)
133167755Ssam		err(1, "CRIOGET");
134108833Ssam
135108833Ssam	if ((ale = bignum_to_le(a, NULL)) == NULL)
136108833Ssam		err(1, "bignum_to_le, a");
137108833Ssam	if ((ble = bignum_to_le(b, NULL)) == NULL)
138108833Ssam		err(1, "bignum_to_le, b");
139108833Ssam	if ((cle = bignum_to_le(c, NULL)) == NULL)
140108833Ssam		err(1, "bignum_to_le, c");
141108833Ssam
142108833Ssam	bzero(&kop, sizeof(kop));
143108833Ssam	kop.crk_op = CRK_MOD_EXP;
144108833Ssam	kop.crk_iparams = 3;
145108833Ssam	kop.crk_oparams = 1;
146167755Ssam	kop.crk_crid = crid;
147108833Ssam	kop.crk_param[0].crp_p = ale;
148108833Ssam	kop.crk_param[0].crp_nbits = BN_num_bytes(a) * 8;
149108833Ssam	kop.crk_param[1].crp_p = ble;
150108833Ssam	kop.crk_param[1].crp_nbits = BN_num_bytes(b) * 8;
151108833Ssam	kop.crk_param[2].crp_p = cle;
152108833Ssam	kop.crk_param[2].crp_nbits = BN_num_bytes(c) * 8;
153108833Ssam	kop.crk_param[3].crp_p = cle;
154108833Ssam	kop.crk_param[3].crp_nbits = BN_num_bytes(c) * 8;
155108833Ssam
156167755Ssam	if (ioctl(crypto_fd, CIOCKEY2, &kop) == -1)
157167755Ssam		err(1, "CIOCKEY2");
158167755Ssam	if (verbose)
159167755Ssam		printf("device = %s\n", crfind(kop.crk_crid));
160108833Ssam
161108833Ssam	bzero(ale, BN_num_bytes(a));
162108833Ssam	free(ale);
163108833Ssam	bzero(ble, BN_num_bytes(b));
164108833Ssam	free(ble);
165108833Ssam
166108833Ssam	if (kop.crk_status != 0) {
167108833Ssam		printf("error %d\n", kop.crk_status);
168108833Ssam		bzero(cle, BN_num_bytes(c));
169108833Ssam		free(cle);
170108833Ssam		return (-1);
171108833Ssam	} else {
172108833Ssam		res = le_to_bignum(res, cle, BN_num_bytes(c));
173108833Ssam		bzero(cle, BN_num_bytes(c));
174108833Ssam		free(cle);
175108833Ssam		if (res == NULL)
176108833Ssam			err(1, "le_to_bignum");
177108833Ssam		return (0);
178108833Ssam	}
179108833Ssam	return (0);
180108833Ssam}
181108833Ssam
182108833Ssamvoid
183108833Ssamshow_result(a, b, c, sw, hw)
184108833SsamBIGNUM *a, *b, *c, *sw, *hw;
185108833Ssam{
186108833Ssam	printf("\n");
187108833Ssam
188108833Ssam	printf("A = ");
189108833Ssam	BN_print_fp(stdout, a);
190108833Ssam	printf("\n");
191108833Ssam
192108833Ssam	printf("B = ");
193108833Ssam	BN_print_fp(stdout, b);
194108833Ssam	printf("\n");
195108833Ssam
196108833Ssam	printf("C = ");
197108833Ssam	BN_print_fp(stdout, c);
198108833Ssam	printf("\n");
199108833Ssam
200108833Ssam	printf("sw= ");
201108833Ssam	BN_print_fp(stdout, sw);
202108833Ssam	printf("\n");
203108833Ssam
204108833Ssam	printf("hw= ");
205108833Ssam	BN_print_fp(stdout, hw);
206108833Ssam	printf("\n");
207108833Ssam
208108833Ssam	printf("\n");
209108833Ssam}
210108833Ssam
211108833Ssamvoid
212108833Ssamtestit(void)
213108833Ssam{
214108833Ssam	BIGNUM *a, *b, *c, *r1, *r2;
215108833Ssam	BN_CTX *ctx;
216108833Ssam
217108833Ssam	ctx = BN_CTX_new();
218108833Ssam
219108833Ssam	a = BN_new();
220108833Ssam	b = BN_new();
221108833Ssam	c = BN_new();
222108833Ssam	r1 = BN_new();
223108833Ssam	r2 = BN_new();
224108833Ssam
225108833Ssam	BN_pseudo_rand(a, 1023, 0, 0);
226108833Ssam	BN_pseudo_rand(b, 1023, 0, 0);
227108833Ssam	BN_pseudo_rand(c, 1024, 0, 0);
228108833Ssam
229108833Ssam	if (BN_cmp(a, c) > 0) {
230108833Ssam		BIGNUM *rem = BN_new();
231108833Ssam
232108833Ssam		BN_mod(rem, a, c, ctx);
233108833Ssam		UB_mod_exp(r2, rem, b, c, ctx);
234108833Ssam		BN_free(rem);
235108833Ssam	} else {
236108833Ssam		UB_mod_exp(r2, a, b, c, ctx);
237108833Ssam	}
238108833Ssam	BN_mod_exp(r1, a, b, c, ctx);
239108833Ssam
240108833Ssam	if (BN_cmp(r1, r2) != 0) {
241108833Ssam		show_result(a, b, c, r1, r2);
242108833Ssam	}
243108833Ssam
244108833Ssam	BN_free(r2);
245108833Ssam	BN_free(r1);
246108833Ssam	BN_free(c);
247108833Ssam	BN_free(b);
248108833Ssam	BN_free(a);
249108833Ssam	BN_CTX_free(ctx);
250108833Ssam}
251108833Ssam
252167755Ssamstatic void
253167755Ssamusage(const char* cmd)
254167755Ssam{
255167755Ssam	printf("usage: %s [-d dev] [-v] [count]\n", cmd);
256167755Ssam	printf("count is the number of bignum ops to do\n");
257167755Ssam	printf("\n");
258167755Ssam	printf("-d use specific device\n");
259167755Ssam	printf("-v be verbose\n");
260167755Ssam	exit(-1);
261167755Ssam}
262167755Ssam
263108833Ssamint
264167755Ssammain(int argc, char *argv[])
265108833Ssam{
266167755Ssam	int c, i;
267108833Ssam
268167755Ssam	while ((c = getopt(argc, argv, "d:v")) != -1) {
269167755Ssam		switch (c) {
270167755Ssam		case 'd':
271167755Ssam			crid = crlookup(optarg);
272167755Ssam			break;
273167755Ssam		case 'v':
274167755Ssam			verbose = 1;
275167755Ssam			break;
276167755Ssam		default:
277167755Ssam			usage(argv[0]);
278167755Ssam		}
279167755Ssam	}
280167755Ssam	argc -= optind, argv += optind;
281167755Ssam
282108833Ssam	for (i = 0; i < 1000; i++) {
283108833Ssam		fprintf(stderr, "test %d\n", i);
284108833Ssam		testit();
285108833Ssam	}
286108833Ssam	return (0);
287108833Ssam}
288