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 
25 int	crid = CRYPTO_FLAG_HARDWARE;
26 int	verbose = 0;
27 
28 static int
devcrypto(void)29 devcrypto(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 
43 static int
crlookup(const char * devname)44 crlookup(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 
55 static const char *
crfind(int crid)56 crfind(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  */
71 static BIGNUM *
le_to_bignum(BIGNUM * res,const void * p,int plen)72 le_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  */
87 static void *
bignum_to_le(const BIGNUM * n)88 bignum_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 
111 static int
UB_mod_exp(BIGNUM * res,const BIGNUM * a,const BIGNUM * b,const BIGNUM * c)112 UB_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 	int crypto_fd = devcrypto();
117 
118 	if ((ale = bignum_to_le(a)) == NULL)
119 		err(1, "bignum_to_le, a");
120 	if ((ble = bignum_to_le(b)) == NULL)
121 		err(1, "bignum_to_le, b");
122 	if ((cle = bignum_to_le(c)) == NULL)
123 		err(1, "bignum_to_le, c");
124 
125 	bzero(&kop, sizeof(kop));
126 	kop.crk_op = CRK_MOD_EXP;
127 	kop.crk_iparams = 3;
128 	kop.crk_oparams = 1;
129 	kop.crk_crid = crid;
130 	kop.crk_param[0].crp_p = ale;
131 	kop.crk_param[0].crp_nbits = BN_num_bytes(a) * 8;
132 	kop.crk_param[1].crp_p = ble;
133 	kop.crk_param[1].crp_nbits = BN_num_bytes(b) * 8;
134 	kop.crk_param[2].crp_p = cle;
135 	kop.crk_param[2].crp_nbits = BN_num_bytes(c) * 8;
136 	kop.crk_param[3].crp_p = cle;
137 	kop.crk_param[3].crp_nbits = BN_num_bytes(c) * 8;
138 
139 	if (ioctl(crypto_fd, CIOCKEY2, &kop) == -1)
140 		err(1, "CIOCKEY2");
141 	if (verbose)
142 		printf("device = %s\n", crfind(kop.crk_crid));
143 
144 	explicit_bzero(ale, BN_num_bytes(a));
145 	free(ale);
146 	explicit_bzero(ble, BN_num_bytes(b));
147 	free(ble);
148 
149 	if (kop.crk_status != 0) {
150 		printf("error %d\n", kop.crk_status);
151 		explicit_bzero(cle, BN_num_bytes(c));
152 		free(cle);
153 		return (-1);
154 	} else {
155 		res = le_to_bignum(res, cle, BN_num_bytes(c));
156 		explicit_bzero(cle, BN_num_bytes(c));
157 		free(cle);
158 		if (res == NULL)
159 			err(1, "le_to_bignum");
160 		return (0);
161 	}
162 	return (0);
163 }
164 
165 static void
show_result(const BIGNUM * a,const BIGNUM * b,const BIGNUM * c,const BIGNUM * sw,const BIGNUM * hw)166 show_result(const BIGNUM *a, const BIGNUM *b, const BIGNUM *c,
167     const BIGNUM *sw, const BIGNUM *hw)
168 {
169 	printf("\n");
170 
171 	printf("A = ");
172 	BN_print_fp(stdout, a);
173 	printf("\n");
174 
175 	printf("B = ");
176 	BN_print_fp(stdout, b);
177 	printf("\n");
178 
179 	printf("C = ");
180 	BN_print_fp(stdout, c);
181 	printf("\n");
182 
183 	printf("sw= ");
184 	BN_print_fp(stdout, sw);
185 	printf("\n");
186 
187 	printf("hw= ");
188 	BN_print_fp(stdout, hw);
189 	printf("\n");
190 
191 	printf("\n");
192 }
193 
194 static void
testit(void)195 testit(void)
196 {
197 	BIGNUM *a, *b, *c, *r1, *r2;
198 	BN_CTX *ctx;
199 
200 	ctx = BN_CTX_new();
201 
202 	a = BN_new();
203 	b = BN_new();
204 	c = BN_new();
205 	r1 = BN_new();
206 	r2 = BN_new();
207 
208 	BN_pseudo_rand(a, 1023, 0, 0);
209 	BN_pseudo_rand(b, 1023, 0, 0);
210 	BN_pseudo_rand(c, 1024, 0, 0);
211 
212 	if (BN_cmp(a, c) > 0) {
213 		BIGNUM *rem = BN_new();
214 
215 		BN_mod(rem, a, c, ctx);
216 		UB_mod_exp(r2, rem, b, c);
217 		BN_free(rem);
218 	} else {
219 		UB_mod_exp(r2, a, b, c);
220 	}
221 	BN_mod_exp(r1, a, b, c, ctx);
222 
223 	if (BN_cmp(r1, r2) != 0) {
224 		show_result(a, b, c, r1, r2);
225 	}
226 
227 	BN_free(r2);
228 	BN_free(r1);
229 	BN_free(c);
230 	BN_free(b);
231 	BN_free(a);
232 	BN_CTX_free(ctx);
233 }
234 
235 static void
usage(const char * cmd)236 usage(const char* cmd)
237 {
238 	printf("usage: %s [-d dev] [-v] [count]\n", cmd);
239 	printf("count is the number of bignum ops to do\n");
240 	printf("\n");
241 	printf("-d use specific device\n");
242 	printf("-v be verbose\n");
243 	exit(-1);
244 }
245 
246 int
main(int argc,char * argv[])247 main(int argc, char *argv[])
248 {
249 	int c, i;
250 
251 	while ((c = getopt(argc, argv, "d:v")) != -1) {
252 		switch (c) {
253 		case 'd':
254 			crid = crlookup(optarg);
255 			break;
256 		case 'v':
257 			verbose = 1;
258 			break;
259 		default:
260 			usage(argv[0]);
261 		}
262 	}
263 	argc -= optind, argv += optind;
264 
265 	for (i = 0; i < 1000; i++) {
266 		fprintf(stderr, "test %d\n", i);
267 		testit();
268 	}
269 	return (0);
270 }
271