xref: /openbsd-src/sys/crypto/idgen.c (revision 6a126883bc80051260ef4a80c3b9b17c95b29772)
1*6a126883Stobhe /*	$OpenBSD: idgen.c,v 1.8 2020/07/22 13:54:30 tobhe Exp $	*/
2ca6e56f2Sdjm /*
3ca6e56f2Sdjm  * Copyright (c) 2008 Damien Miller <djm@mindrot.org>
4ca6e56f2Sdjm  *
5ca6e56f2Sdjm  * Permission to use, copy, modify, and distribute this software for any
6ca6e56f2Sdjm  * purpose with or without fee is hereby granted, provided that the above
7ca6e56f2Sdjm  * copyright notice and this permission notice appear in all copies.
8ca6e56f2Sdjm  *
9ca6e56f2Sdjm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10ca6e56f2Sdjm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11ca6e56f2Sdjm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12ca6e56f2Sdjm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13ca6e56f2Sdjm  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14ca6e56f2Sdjm  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15ca6e56f2Sdjm  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16ca6e56f2Sdjm  */
17ca6e56f2Sdjm 
18ca6e56f2Sdjm /*
1920d6f976Sdjm  * IDGEN32: non-repeating ID generation covering an almost maximal 32-bit
2020d6f976Sdjm  * range.
2120d6f976Sdjm  *
2220d6f976Sdjm  * IDGEN32 is based on public domain SKIP32 by Greg Rose.
23ca6e56f2Sdjm  */
24ca6e56f2Sdjm 
25ca6e56f2Sdjm #include <sys/types.h>
26ca6e56f2Sdjm #include <sys/systm.h>
27fb430e18Sdjm #include <sys/time.h>
28ca6e56f2Sdjm 
29fb430e18Sdjm #include <crypto/idgen.h>
30ca6e56f2Sdjm 
3120d6f976Sdjm static const u_int8_t idgen32_ftable[256] = {
32ca6e56f2Sdjm 	0xa3, 0xd7, 0x09, 0x83, 0xf8, 0x48, 0xf6, 0xf4,
33ca6e56f2Sdjm 	0xb3, 0x21, 0x15, 0x78, 0x99, 0xb1, 0xaf, 0xf9,
34ca6e56f2Sdjm 	0xe7, 0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e,
35ca6e56f2Sdjm 	0x52, 0x95, 0xd9, 0x1e, 0x4e, 0x38, 0x44, 0x28,
36ca6e56f2Sdjm 	0x0a, 0xdf, 0x02, 0xa0, 0x17, 0xf1, 0x60, 0x68,
37ca6e56f2Sdjm 	0x12, 0xb7, 0x7a, 0xc3, 0xe9, 0xfa, 0x3d, 0x53,
38ca6e56f2Sdjm 	0x96, 0x84, 0x6b, 0xba, 0xf2, 0x63, 0x9a, 0x19,
39ca6e56f2Sdjm 	0x7c, 0xae, 0xe5, 0xf5, 0xf7, 0x16, 0x6a, 0xa2,
40ca6e56f2Sdjm 	0x39, 0xb6, 0x7b, 0x0f, 0xc1, 0x93, 0x81, 0x1b,
41ca6e56f2Sdjm 	0xee, 0xb4, 0x1a, 0xea, 0xd0, 0x91, 0x2f, 0xb8,
42ca6e56f2Sdjm 	0x55, 0xb9, 0xda, 0x85, 0x3f, 0x41, 0xbf, 0xe0,
43ca6e56f2Sdjm 	0x5a, 0x58, 0x80, 0x5f, 0x66, 0x0b, 0xd8, 0x90,
44ca6e56f2Sdjm 	0x35, 0xd5, 0xc0, 0xa7, 0x33, 0x06, 0x65, 0x69,
45ca6e56f2Sdjm 	0x45, 0x00, 0x94, 0x56, 0x6d, 0x98, 0x9b, 0x76,
46ca6e56f2Sdjm 	0x97, 0xfc, 0xb2, 0xc2, 0xb0, 0xfe, 0xdb, 0x20,
47ca6e56f2Sdjm 	0xe1, 0xeb, 0xd6, 0xe4, 0xdd, 0x47, 0x4a, 0x1d,
48ca6e56f2Sdjm 	0x42, 0xed, 0x9e, 0x6e, 0x49, 0x3c, 0xcd, 0x43,
49ca6e56f2Sdjm 	0x27, 0xd2, 0x07, 0xd4, 0xde, 0xc7, 0x67, 0x18,
50ca6e56f2Sdjm 	0x89, 0xcb, 0x30, 0x1f, 0x8d, 0xc6, 0x8f, 0xaa,
51ca6e56f2Sdjm 	0xc8, 0x74, 0xdc, 0xc9, 0x5d, 0x5c, 0x31, 0xa4,
52ca6e56f2Sdjm 	0x70, 0x88, 0x61, 0x2c, 0x9f, 0x0d, 0x2b, 0x87,
53ca6e56f2Sdjm 	0x50, 0x82, 0x54, 0x64, 0x26, 0x7d, 0x03, 0x40,
54ca6e56f2Sdjm 	0x34, 0x4b, 0x1c, 0x73, 0xd1, 0xc4, 0xfd, 0x3b,
55ca6e56f2Sdjm 	0xcc, 0xfb, 0x7f, 0xab, 0xe6, 0x3e, 0x5b, 0xa5,
56ca6e56f2Sdjm 	0xad, 0x04, 0x23, 0x9c, 0x14, 0x51, 0x22, 0xf0,
57ca6e56f2Sdjm 	0x29, 0x79, 0x71, 0x7e, 0xff, 0x8c, 0x0e, 0xe2,
58ca6e56f2Sdjm 	0x0c, 0xef, 0xbc, 0x72, 0x75, 0x6f, 0x37, 0xa1,
59ca6e56f2Sdjm 	0xec, 0xd3, 0x8e, 0x62, 0x8b, 0x86, 0x10, 0xe8,
60ca6e56f2Sdjm 	0x08, 0x77, 0x11, 0xbe, 0x92, 0x4f, 0x24, 0xc5,
61ca6e56f2Sdjm 	0x32, 0x36, 0x9d, 0xcf, 0xf3, 0xa6, 0xbb, 0xac,
62ca6e56f2Sdjm 	0x5e, 0x6c, 0xa9, 0x13, 0x57, 0x25, 0xb5, 0xe3,
63ca6e56f2Sdjm 	0xbd, 0xa8, 0x3a, 0x01, 0x05, 0x59, 0x2a, 0x46
64ca6e56f2Sdjm };
65ca6e56f2Sdjm 
66ca6e56f2Sdjm static u_int16_t
idgen32_g(u_int8_t * key,int k,u_int16_t w)67ca6e56f2Sdjm idgen32_g(u_int8_t *key, int k, u_int16_t w)
68ca6e56f2Sdjm {
69ca6e56f2Sdjm 	u_int8_t g1, g2, g3, g4, g5, g6;
70ca6e56f2Sdjm 	u_int o = k * 4;
71ca6e56f2Sdjm 
72ca6e56f2Sdjm 	g1 = (w >> 8) & 0xff;
73ca6e56f2Sdjm 	g2 = w & 0xff;
74ca6e56f2Sdjm 
7520d6f976Sdjm 	g3 = idgen32_ftable[g2 ^ key[o++ & (IDGEN32_KEYLEN - 1)]] ^ g1;
7620d6f976Sdjm 	g4 = idgen32_ftable[g3 ^ key[o++ & (IDGEN32_KEYLEN - 1)]] ^ g2;
7720d6f976Sdjm 	g5 = idgen32_ftable[g4 ^ key[o++ & (IDGEN32_KEYLEN - 1)]] ^ g3;
7820d6f976Sdjm 	g6 = idgen32_ftable[g5 ^ key[o++ & (IDGEN32_KEYLEN - 1)]] ^ g4;
79ca6e56f2Sdjm 
80ca6e56f2Sdjm 	return (g5 << 8) | g6;
81ca6e56f2Sdjm }
82ca6e56f2Sdjm 
83fb430e18Sdjm static u_int32_t
idgen32_permute(struct idgen32_ctx * ctx,u_int32_t in)8420d6f976Sdjm idgen32_permute(struct idgen32_ctx *ctx, u_int32_t in)
85ca6e56f2Sdjm {
86ca6e56f2Sdjm 	u_int i, r;
87ca6e56f2Sdjm 	u_int16_t wl, wr;
88ca6e56f2Sdjm 
89ca6e56f2Sdjm 	wl = (in >> 16) & 0x7fff;
90ca6e56f2Sdjm 	wr = in & 0xffff;
91ca6e56f2Sdjm 
92ca6e56f2Sdjm 	/* Doubled up rounds, with an odd round at the end to swap */
93ca6e56f2Sdjm 	for (i = r = 0; i < IDGEN32_ROUNDS / 2; ++i) {
9420d6f976Sdjm 		wr ^= (idgen32_g(ctx->id32_key, r, wl) ^ r);
95ca6e56f2Sdjm 		r++;
9620d6f976Sdjm 		wl ^= (idgen32_g(ctx->id32_key, r, wr) ^ r) & 0x7fff;
97ca6e56f2Sdjm 		r++;
98ca6e56f2Sdjm 	}
9920d6f976Sdjm 	wr ^= (idgen32_g(ctx->id32_key, r, wl) ^ r);
100ca6e56f2Sdjm 
101ca6e56f2Sdjm 	return (wl << 16) | wr;
102ca6e56f2Sdjm }
103ca6e56f2Sdjm 
104fb430e18Sdjm static void
idgen32_rekey(struct idgen32_ctx * ctx)105ca6e56f2Sdjm idgen32_rekey(struct idgen32_ctx *ctx)
106ca6e56f2Sdjm {
10720d6f976Sdjm 	ctx->id32_counter = 0;
10820d6f976Sdjm 	ctx->id32_hibit ^= 0x80000000;
10920d6f976Sdjm 	ctx->id32_offset = arc4random();
11020d6f976Sdjm 	arc4random_buf(ctx->id32_key, sizeof(ctx->id32_key));
1113209772dScheloha 	ctx->id32_rekey_time = getuptime() + IDGEN32_REKEY_TIME;
112ca6e56f2Sdjm }
113ca6e56f2Sdjm 
114ca6e56f2Sdjm void
idgen32_init(struct idgen32_ctx * ctx)115ca6e56f2Sdjm idgen32_init(struct idgen32_ctx *ctx)
116ca6e56f2Sdjm {
117bc77ecb9Smiod 	bzero(ctx, sizeof(*ctx));
11820d6f976Sdjm 	ctx->id32_hibit = arc4random() & 0x80000000;
119ca6e56f2Sdjm 	idgen32_rekey(ctx);
120ca6e56f2Sdjm }
121ca6e56f2Sdjm 
122ca6e56f2Sdjm u_int32_t
idgen32(struct idgen32_ctx * ctx)123ca6e56f2Sdjm idgen32(struct idgen32_ctx *ctx)
124ca6e56f2Sdjm {
125ca6e56f2Sdjm 	u_int32_t ret;
126ca6e56f2Sdjm 
127ca6e56f2Sdjm 	do {
128ca6e56f2Sdjm 		/* Rekey a little early to avoid "card counting" attack */
12920d6f976Sdjm 		if (ctx->id32_counter > IDGEN32_REKEY_LIMIT ||
1303209772dScheloha 		    ctx->id32_rekey_time < getuptime())
131ca6e56f2Sdjm 			idgen32_rekey(ctx);
13220d6f976Sdjm 		ret = ctx->id32_hibit | idgen32_permute(ctx,
13320d6f976Sdjm 		    (ctx->id32_offset + ctx->id32_counter++) & 0x7fffffff);
13420d6f976Sdjm 	} while (ret == 0); /* Zero IDs are often special, so avoid */
135ca6e56f2Sdjm 
13620d6f976Sdjm 	return ret;
137ca6e56f2Sdjm }
13820d6f976Sdjm 
139