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