1 /* $FreeBSD$ */
2 /*
3  * The big num stuff is a bit broken at the moment and I've not yet fixed it.
4  * The symtom is that odd size big nums will fail.  Test code below (it only
5  * uses modexp currently).
6  *
7  * --Jason L. Wright
8  */
9 #include <sys/types.h>
10 #include <sys/ioctl.h>
11 #include <machine/endian.h>
12 #include <sys/time.h>
13 #include <crypto/cryptodev.h>
14 #include <openssl/bn.h>
15 
16 #include <paths.h>
17 #include <fcntl.h>
18 #include <err.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 
23 int	crid = CRYPTO_FLAG_HARDWARE;
24 int	verbose = 0;
25 
26 static int
27 devcrypto(void)
28 {
29 	static int fd = -1;
30 
31 	if (fd < 0) {
32 		fd = open(_PATH_DEV "crypto", O_RDWR, 0);
33 		if (fd < 0)
34 			err(1, _PATH_DEV "crypto");
35 		if (fcntl(fd, F_SETFD, 1) == -1)
36 			err(1, "fcntl(F_SETFD) (devcrypto)");
37 	}
38 	return fd;
39 }
40 
41 static int
42 crlookup(const char *devname)
43 {
44 	struct crypt_find_op find;
45 
46 	find.crid = -1;
47 	strlcpy(find.name, devname, sizeof(find.name));
48 	if (ioctl(devcrypto(), CIOCFINDDEV, &find) == -1)
49 		err(1, "ioctl(CIOCFINDDEV)");
50 	return find.crid;
51 }
52 
53 static const char *
54 crfind(int crid)
55 {
56 	static struct crypt_find_op find;
57 
58 	bzero(&find, sizeof(find));
59 	find.crid = crid;
60 	if (ioctl(devcrypto(), CIOCFINDDEV, &find) == -1)
61 		err(1, "ioctl(CIOCFINDDEV)");
62 	return find.name;
63 }
64 
65 /*
66  * Convert a little endian byte string in 'p' that
67  * is 'plen' bytes long to a BIGNUM. If 'dst' is NULL,
68  * a new BIGNUM is allocated.  Returns NULL on failure.
69  *
70  * XXX there has got to be a more efficient way to do
71  * this, but I haven't figured out enough of the OpenSSL
72  * magic.
73  */
74 BIGNUM *
75 le_to_bignum(BIGNUM *dst, u_int8_t *p, int plen)
76 {
77 	u_int8_t *pd;
78 	int i;
79 
80 	if (plen == 0)
81 		return (NULL);
82 
83 	if ((pd = (u_int8_t *)malloc(plen)) == NULL)
84 		return (NULL);
85 
86 	for (i = 0; i < plen; i++)
87 		pd[i] = p[plen - i - 1];
88 
89 	dst = BN_bin2bn(pd, plen, dst);
90 	free(pd);
91 	return (dst);
92 }
93 
94 /*
95  * Convert a BIGNUM to a little endian byte string.
96  * If 'rd' is NULL, allocate space for it, otherwise
97  * 'rd' is assumed to have room for BN_num_bytes(n)
98  * bytes.  Returns NULL on failure.
99  */
100 u_int8_t *
101 bignum_to_le(BIGNUM *n, u_int8_t *rd)
102 {
103 	int i, j, k;
104 	int blen = BN_num_bytes(n);
105 
106 	if (blen == 0)
107 		return (NULL);
108 	if (rd == NULL)
109 		rd = (u_int8_t *)malloc(blen);
110 	if (rd == NULL)
111 		return (NULL);
112 
113 	for (i = 0, j = 0; i < n->top; i++) {
114 		for (k = 0; k < BN_BITS2 / 8; k++) {
115 			if ((j + k) >= blen)
116 				goto out;
117 			rd[j + k] = n->d[i] >> (k * 8);
118 		}
119 		j += BN_BITS2 / 8;
120 	}
121 out:
122 	return (rd);
123 }
124 
125 int
126 UB_mod_exp(BIGNUM *res, BIGNUM *a, BIGNUM *b, BIGNUM *c, BN_CTX *ctx)
127 {
128 	struct crypt_kop kop;
129 	u_int8_t *ale, *ble, *cle;
130 	static int crypto_fd = -1;
131 
132 	if (crypto_fd == -1 && ioctl(devcrypto(), CRIOGET, &crypto_fd) == -1)
133 			err(1, "CRIOGET");
134 
135 	if ((ale = bignum_to_le(a, NULL)) == NULL)
136 		err(1, "bignum_to_le, a");
137 	if ((ble = bignum_to_le(b, NULL)) == NULL)
138 		err(1, "bignum_to_le, b");
139 	if ((cle = bignum_to_le(c, NULL)) == NULL)
140 		err(1, "bignum_to_le, c");
141 
142 	bzero(&kop, sizeof(kop));
143 	kop.crk_op = CRK_MOD_EXP;
144 	kop.crk_iparams = 3;
145 	kop.crk_oparams = 1;
146 	kop.crk_crid = crid;
147 	kop.crk_param[0].crp_p = ale;
148 	kop.crk_param[0].crp_nbits = BN_num_bytes(a) * 8;
149 	kop.crk_param[1].crp_p = ble;
150 	kop.crk_param[1].crp_nbits = BN_num_bytes(b) * 8;
151 	kop.crk_param[2].crp_p = cle;
152 	kop.crk_param[2].crp_nbits = BN_num_bytes(c) * 8;
153 	kop.crk_param[3].crp_p = cle;
154 	kop.crk_param[3].crp_nbits = BN_num_bytes(c) * 8;
155 
156 	if (ioctl(crypto_fd, CIOCKEY2, &kop) == -1)
157 		err(1, "CIOCKEY2");
158 	if (verbose)
159 		printf("device = %s\n", crfind(kop.crk_crid));
160 
161 	bzero(ale, BN_num_bytes(a));
162 	free(ale);
163 	bzero(ble, BN_num_bytes(b));
164 	free(ble);
165 
166 	if (kop.crk_status != 0) {
167 		printf("error %d\n", kop.crk_status);
168 		bzero(cle, BN_num_bytes(c));
169 		free(cle);
170 		return (-1);
171 	} else {
172 		res = le_to_bignum(res, cle, BN_num_bytes(c));
173 		bzero(cle, BN_num_bytes(c));
174 		free(cle);
175 		if (res == NULL)
176 			err(1, "le_to_bignum");
177 		return (0);
178 	}
179 	return (0);
180 }
181 
182 void
183 show_result(a, b, c, sw, hw)
184 BIGNUM *a, *b, *c, *sw, *hw;
185 {
186 	printf("\n");
187 
188 	printf("A = ");
189 	BN_print_fp(stdout, a);
190 	printf("\n");
191 
192 	printf("B = ");
193 	BN_print_fp(stdout, b);
194 	printf("\n");
195 
196 	printf("C = ");
197 	BN_print_fp(stdout, c);
198 	printf("\n");
199 
200 	printf("sw= ");
201 	BN_print_fp(stdout, sw);
202 	printf("\n");
203 
204 	printf("hw= ");
205 	BN_print_fp(stdout, hw);
206 	printf("\n");
207 
208 	printf("\n");
209 }
210 
211 void
212 testit(void)
213 {
214 	BIGNUM *a, *b, *c, *r1, *r2;
215 	BN_CTX *ctx;
216 
217 	ctx = BN_CTX_new();
218 
219 	a = BN_new();
220 	b = BN_new();
221 	c = BN_new();
222 	r1 = BN_new();
223 	r2 = BN_new();
224 
225 	BN_pseudo_rand(a, 1023, 0, 0);
226 	BN_pseudo_rand(b, 1023, 0, 0);
227 	BN_pseudo_rand(c, 1024, 0, 0);
228 
229 	if (BN_cmp(a, c) > 0) {
230 		BIGNUM *rem = BN_new();
231 
232 		BN_mod(rem, a, c, ctx);
233 		UB_mod_exp(r2, rem, b, c, ctx);
234 		BN_free(rem);
235 	} else {
236 		UB_mod_exp(r2, a, b, c, ctx);
237 	}
238 	BN_mod_exp(r1, a, b, c, ctx);
239 
240 	if (BN_cmp(r1, r2) != 0) {
241 		show_result(a, b, c, r1, r2);
242 	}
243 
244 	BN_free(r2);
245 	BN_free(r1);
246 	BN_free(c);
247 	BN_free(b);
248 	BN_free(a);
249 	BN_CTX_free(ctx);
250 }
251 
252 static void
253 usage(const char* cmd)
254 {
255 	printf("usage: %s [-d dev] [-v] [count]\n", cmd);
256 	printf("count is the number of bignum ops to do\n");
257 	printf("\n");
258 	printf("-d use specific device\n");
259 	printf("-v be verbose\n");
260 	exit(-1);
261 }
262 
263 int
264 main(int argc, char *argv[])
265 {
266 	int c, i;
267 
268 	while ((c = getopt(argc, argv, "d:v")) != -1) {
269 		switch (c) {
270 		case 'd':
271 			crid = crlookup(optarg);
272 			break;
273 		case 'v':
274 			verbose = 1;
275 			break;
276 		default:
277 			usage(argv[0]);
278 		}
279 	}
280 	argc -= optind, argv += optind;
281 
282 	for (i = 0; i < 1000; i++) {
283 		fprintf(stderr, "test %d\n", i);
284 		testit();
285 	}
286 	return (0);
287 }
288