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