1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://opensource.org/licenses/CDDL-1.0.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2013 Saso Kiselkov. All rights reserved.
24  */
25 
26 /*
27  * This is just to keep the compiler happy about sys/time.h not declaring
28  * gettimeofday due to -D_KERNEL (we can do this since we're actually
29  * running in userspace, but we need -D_KERNEL for the remaining SHA2 code).
30  */
31 
32 #include <stdarg.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdio.h>
36 
37 #include <sys/time.h>
38 #include <sys/sha2.h>
39 #include <sys/stdtypes.h>
40 #include <sys/zfs_impl.h>
41 
42 /*
43  * Test messages from:
44  * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
45  */
46 
47 static const char *test_msg0 = "abc";
48 static const char *test_msg1 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
49 	"nlmnomnopnopq";
50 static const char *test_msg2 = "abcdefghbcdefghicdefghijdefghijkefghijklfgh"
51 	"ijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";
52 
53 /*
54  * Test digests from:
55  * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
56  */
57 static const uint8_t	sha256_test_digests[][32] = {
58 	{
59 		/* for test_msg0 */
60 		0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
61 		0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
62 		0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
63 		0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD
64 	},
65 	{
66 		/* for test_msg1 */
67 		0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
68 		0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
69 		0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
70 		0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1
71 	}
72 	/* no test vector for test_msg2 */
73 };
74 
75 static const uint8_t	sha384_test_digests[][48] = {
76 	{
77 		/* for test_msg0 */
78 		0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B,
79 		0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07,
80 		0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63,
81 		0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED,
82 		0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23,
83 		0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7
84 	},
85 	{
86 		/* no test vector for test_msg1 */
87 		0
88 	},
89 	{
90 		/* for test_msg2 */
91 		0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8,
92 		0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47,
93 		0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2,
94 		0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12,
95 		0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9,
96 		0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39
97 	}
98 };
99 
100 static const uint8_t	sha512_test_digests[][64] = {
101 	{
102 		/* for test_msg0 */
103 		0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA,
104 		0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31,
105 		0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2,
106 		0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A,
107 		0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8,
108 		0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD,
109 		0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E,
110 		0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F
111 	},
112 	{
113 		/* no test vector for test_msg1 */
114 		0
115 	},
116 	{
117 		/* for test_msg2 */
118 		0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA,
119 		0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F,
120 		0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1,
121 		0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18,
122 		0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4,
123 		0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A,
124 		0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54,
125 		0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09
126 	}
127 };
128 
129 static const uint8_t	sha512_224_test_digests[][28] = {
130 	{
131 		/* for test_msg0 */
132 		0x46, 0x34, 0x27, 0x0F, 0x70, 0x7B, 0x6A, 0x54,
133 		0xDA, 0xAE, 0x75, 0x30, 0x46, 0x08, 0x42, 0xE2,
134 		0x0E, 0x37, 0xED, 0x26, 0x5C, 0xEE, 0xE9, 0xA4,
135 		0x3E, 0x89, 0x24, 0xAA
136 	},
137 	{
138 		/* no test vector for test_msg1 */
139 		0
140 	},
141 	{
142 		/* for test_msg2 */
143 		0x23, 0xFE, 0xC5, 0xBB, 0x94, 0xD6, 0x0B, 0x23,
144 		0x30, 0x81, 0x92, 0x64, 0x0B, 0x0C, 0x45, 0x33,
145 		0x35, 0xD6, 0x64, 0x73, 0x4F, 0xE4, 0x0E, 0x72,
146 		0x68, 0x67, 0x4A, 0xF9
147 	}
148 };
149 
150 static const uint8_t	sha512_256_test_digests[][32] = {
151 	{
152 		/* for test_msg0 */
153 		0x53, 0x04, 0x8E, 0x26, 0x81, 0x94, 0x1E, 0xF9,
154 		0x9B, 0x2E, 0x29, 0xB7, 0x6B, 0x4C, 0x7D, 0xAB,
155 		0xE4, 0xC2, 0xD0, 0xC6, 0x34, 0xFC, 0x6D, 0x46,
156 		0xE0, 0xE2, 0xF1, 0x31, 0x07, 0xE7, 0xAF, 0x23
157 	},
158 	{
159 		/* no test vector for test_msg1 */
160 		0
161 	},
162 	{
163 		/* for test_msg2 */
164 		0x39, 0x28, 0xE1, 0x84, 0xFB, 0x86, 0x90, 0xF8,
165 		0x40, 0xDA, 0x39, 0x88, 0x12, 0x1D, 0x31, 0xBE,
166 		0x65, 0xCB, 0x9D, 0x3E, 0xF8, 0x3E, 0xE6, 0x14,
167 		0x6F, 0xEA, 0xC8, 0x61, 0xE1, 0x9B, 0x56, 0x3A
168 	}
169 };
170 
171 int
172 main(int argc, char *argv[])
173 {
174 	boolean_t	failed = B_FALSE;
175 	uint64_t	cpu_mhz = 0;
176 
177 	const zfs_impl_t *sha256 = zfs_impl_get_ops("sha256");
178 	const zfs_impl_t *sha512 = zfs_impl_get_ops("sha512");
179 	uint32_t id;
180 
181 	if (argc == 2)
182 		cpu_mhz = atoi(argv[1]);
183 
184 	if (!sha256)
185 		return (1);
186 
187 	if (!sha512)
188 		return (1);
189 
190 #define	SHA2_ALGO_TEST(_m, mode, diglen, testdigest)			\
191 	do {								\
192 		SHA2_CTX		ctx;				\
193 		uint8_t			digest[diglen / 8];		\
194 		SHA2Init(SHA ## mode ## _MECH_INFO_TYPE, &ctx);		\
195 		SHA2Update(&ctx, _m, strlen(_m));			\
196 		SHA2Final(digest, &ctx);				\
197 		(void) printf("SHA%-9sMessage: " #_m			\
198 		    "\tResult: ", #mode);				\
199 		if (memcmp(digest, testdigest, diglen / 8) == 0) {	\
200 			(void) printf("OK\n");				\
201 		} else {						\
202 			(void) printf("FAILED!\n");			\
203 			failed = B_TRUE;				\
204 		}							\
205 	} while (0)
206 
207 #define	SHA2_PERF_TEST(mode, diglen, name)				\
208 	do {								\
209 		SHA2_CTX	ctx;					\
210 		uint8_t		digest[diglen / 8];			\
211 		uint8_t		block[131072];				\
212 		uint64_t	delta;					\
213 		double		cpb = 0;				\
214 		int		i;					\
215 		struct timeval	start, end;				\
216 		memset(block, 0, sizeof (block));			\
217 		(void) gettimeofday(&start, NULL);			\
218 		SHA2Init(SHA ## mode ## _MECH_INFO_TYPE, &ctx);		\
219 		for (i = 0; i < 8192; i++)				\
220 			SHA2Update(&ctx, block, sizeof (block));	\
221 		SHA2Final(digest, &ctx);				\
222 		(void) gettimeofday(&end, NULL);			\
223 		delta = (end.tv_sec * 1000000llu + end.tv_usec) -	\
224 		    (start.tv_sec * 1000000llu + start.tv_usec);	\
225 		if (cpu_mhz != 0) {					\
226 			cpb = (cpu_mhz * 1e6 * ((double)delta /		\
227 			    1000000)) / (8192 * 128 * 1024);		\
228 		}							\
229 		(void) printf("sha%s-%-9s%7llu us (%.02f CPB)\n", #mode,\
230 		    name, (u_longlong_t)delta, cpb);			\
231 	} while (0)
232 
233 	(void) printf("Running algorithm correctness tests:\n");
234 	SHA2_ALGO_TEST(test_msg0, 256, 256, sha256_test_digests[0]);
235 	SHA2_ALGO_TEST(test_msg1, 256, 256, sha256_test_digests[1]);
236 	SHA2_ALGO_TEST(test_msg0, 384, 384, sha384_test_digests[0]);
237 	SHA2_ALGO_TEST(test_msg2, 384, 384, sha384_test_digests[2]);
238 	SHA2_ALGO_TEST(test_msg0, 512, 512, sha512_test_digests[0]);
239 	SHA2_ALGO_TEST(test_msg2, 512, 512, sha512_test_digests[2]);
240 	SHA2_ALGO_TEST(test_msg0, 512_224, 224, sha512_224_test_digests[0]);
241 	SHA2_ALGO_TEST(test_msg2, 512_224, 224, sha512_224_test_digests[2]);
242 	SHA2_ALGO_TEST(test_msg0, 512_256, 256, sha512_256_test_digests[0]);
243 	SHA2_ALGO_TEST(test_msg2, 512_256, 256, sha512_256_test_digests[2]);
244 
245 	if (failed)
246 		return (1);
247 
248 	(void) printf("Running performance tests (hashing 1024 MiB of "
249 	    "data):\n");
250 
251 	for (id = 0; id < sha256->getcnt(); id++) {
252 		sha256->setid(id);
253 		const char *name = sha256->getname();
254 		SHA2_PERF_TEST(256, 256, name);
255 	}
256 
257 	for (id = 0; id < sha512->getcnt(); id++) {
258 		sha512->setid(id);
259 		const char *name = sha512->getname();
260 		SHA2_PERF_TEST(512, 512, name);
261 	}
262 
263 	return (0);
264 }
265