From: Vsevolod Stakhov Date: Sat, 28 Dec 2013 01:01:59 +0000 (+0000) Subject: Use chacha20 for DNS id permutation. X-Git-Tag: 0.6.7~43 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=074ac59f6f239256161a1de202bdd5551dfb26fd;p=rspamd.git Use chacha20 for DNS id permutation. --- diff --git a/src/chacha_private.h b/src/chacha_private.h new file mode 100644 index 000000000..5034f4955 --- /dev/null +++ b/src/chacha_private.h @@ -0,0 +1,228 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +#ifndef CHACHA_PRIVATE_H_ +#define CHACHA_PRIVATE_H_ + +#include + +typedef unsigned char u8; +typedef unsigned int u32; + +typedef struct +{ + u32 input[16]; /* could be compressed */ +} chacha_ctx; + +#define U8C(v) (v##U) +#define U32C(v) (v##U) + +#define U8V(v) ((u8)(v) & U8C(0xFF)) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | \ + ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ + a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ + a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ + c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +static void chacha_keysetup(chacha_ctx *x, const u8 *k, u32 kbits, u32 ivbits) +{ + const char *constants; + + x->input[4] = U8TO32_LITTLE(k + 0); + x->input[5] = U8TO32_LITTLE(k + 4); + x->input[6] = U8TO32_LITTLE(k + 8); + x->input[7] = U8TO32_LITTLE(k + 12); + if (kbits == 256) { /* recommended */ + k += 16; + constants = sigma; + } + else { /* kbits == 128 */ + constants = tau; + } + x->input[8] = U8TO32_LITTLE(k + 0); + x->input[9] = U8TO32_LITTLE(k + 4); + x->input[10] = U8TO32_LITTLE(k + 8); + x->input[11] = U8TO32_LITTLE(k + 12); + x->input[0] = U8TO32_LITTLE(constants + 0); + x->input[1] = U8TO32_LITTLE(constants + 4); + x->input[2] = U8TO32_LITTLE(constants + 8); + x->input[3] = U8TO32_LITTLE(constants + 12); +} + +static void chacha_ivsetup(chacha_ctx *x, const u8 *iv) +{ + x->input[12] = 0; + x->input[13] = 0; + x->input[14] = U8TO32_LITTLE(iv + 0); + x->input[15] = U8TO32_LITTLE(iv + 4); +} + +static void chacha_encrypt_bytes(chacha_ctx *x, const u8 *m, u8 *c, u32 bytes) +{ + u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; + u8 *ctarget = NULL; + u8 tmp[64]; + unsigned int i; + + if (!bytes) + return; + + j0 = x->input[0]; + j1 = x->input[1]; + j2 = x->input[2]; + j3 = x->input[3]; + j4 = x->input[4]; + j5 = x->input[5]; + j6 = x->input[6]; + j7 = x->input[7]; + j8 = x->input[8]; + j9 = x->input[9]; + j10 = x->input[10]; + j11 = x->input[11]; + j12 = x->input[12]; + j13 = x->input[13]; + j14 = x->input[14]; + j15 = x->input[15]; + + for (;;) { + if (bytes < 64) { + for (i = 0; i < bytes; ++i) + tmp[i] = m[i]; + m = tmp; + ctarget = c; + c = tmp; + } + x0 = j0; + x1 = j1; + x2 = j2; + x3 = j3; + x4 = j4; + x5 = j5; + x6 = j6; + x7 = j7; + x8 = j8; + x9 = j9; + x10 = j10; + x11 = j11; + x12 = j12; + x13 = j13; + x14 = j14; + x15 = j15; + for (i = 20; i > 0; i -= 2) { + QUARTERROUND( x0, x4, x8, x12) + QUARTERROUND( x1, x5, x9, x13) + QUARTERROUND( x2, x6, x10, x14) + QUARTERROUND( x3, x7, x11, x15) + QUARTERROUND( x0, x5, x10, x15) + QUARTERROUND( x1, x6, x11, x12) + QUARTERROUND( x2, x7, x8, x13) + QUARTERROUND( x3, x4, x9, x14) + } + x0 = PLUS(x0,j0); + x1 = PLUS(x1,j1); + x2 = PLUS(x2,j2); + x3 = PLUS(x3,j3); + x4 = PLUS(x4,j4); + x5 = PLUS(x5,j5); + x6 = PLUS(x6,j6); + x7 = PLUS(x7,j7); + x8 = PLUS(x8,j8); + x9 = PLUS(x9,j9); + x10 = PLUS(x10,j10); + x11 = PLUS(x11,j11); + x12 = PLUS(x12,j12); + x13 = PLUS(x13,j13); + x14 = PLUS(x14,j14); + x15 = PLUS(x15,j15); + +#ifndef KEYSTREAM_ONLY + x0 = XOR(x0,U8TO32_LITTLE(m + 0)); + x1 = XOR(x1,U8TO32_LITTLE(m + 4)); + x2 = XOR(x2,U8TO32_LITTLE(m + 8)); + x3 = XOR(x3,U8TO32_LITTLE(m + 12)); + x4 = XOR(x4,U8TO32_LITTLE(m + 16)); + x5 = XOR(x5,U8TO32_LITTLE(m + 20)); + x6 = XOR(x6,U8TO32_LITTLE(m + 24)); + x7 = XOR(x7,U8TO32_LITTLE(m + 28)); + x8 = XOR(x8,U8TO32_LITTLE(m + 32)); + x9 = XOR(x9,U8TO32_LITTLE(m + 36)); + x10 = XOR(x10,U8TO32_LITTLE(m + 40)); + x11 = XOR(x11,U8TO32_LITTLE(m + 44)); + x12 = XOR(x12,U8TO32_LITTLE(m + 48)); + x13 = XOR(x13,U8TO32_LITTLE(m + 52)); + x14 = XOR(x14,U8TO32_LITTLE(m + 56)); + x15 = XOR(x15,U8TO32_LITTLE(m + 60)); +#endif + + j12 = PLUSONE(j12); + if (!j12) { + j13 = PLUSONE(j13); + /* stopping at 2^70 bytes per nonce is user's responsibility */ + } + + U32TO8_LITTLE(c + 0, x0); + U32TO8_LITTLE(c + 4, x1); + U32TO8_LITTLE(c + 8, x2); + U32TO8_LITTLE(c + 12, x3); + U32TO8_LITTLE(c + 16, x4); + U32TO8_LITTLE(c + 20, x5); + U32TO8_LITTLE(c + 24, x6); + U32TO8_LITTLE(c + 28, x7); + U32TO8_LITTLE(c + 32, x8); + U32TO8_LITTLE(c + 36, x9); + U32TO8_LITTLE(c + 40, x10); + U32TO8_LITTLE(c + 44, x11); + U32TO8_LITTLE(c + 48, x12); + U32TO8_LITTLE(c + 52, x13); + U32TO8_LITTLE(c + 56, x14); + U32TO8_LITTLE(c + 60, x15); + + if (bytes <= 64) { + if (bytes < 64) { + for (i = 0; i < bytes; ++i) + ctarget[i] = c[i]; + } + x->input[12] = j12; + x->input[13] = j13; + return; + } + bytes -= 64; + c += 64; +#ifndef KEYSTREAM_ONLY + m += 64; +#endif + } +} + +#endif /* CHACHA_PRIVATE_H_ */ diff --git a/src/dns.c b/src/dns.c index f387c0c48..cf70a6a86 100644 --- a/src/dns.c +++ b/src/dns.c @@ -1,6 +1,5 @@ /* - * Copyright (c) 2009-2012, Vsevolod Stakhov - * Copyright (c) 2008, 2009, 2010 William Ahern + * Copyright (c) 2009-2013, Vsevolod Stakhov * * All rights reserved. * @@ -24,16 +23,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* - * Rspamd resolver library is based on code written by William Ahern. - * - * The original library can be found at: http://25thandclement.com/~william/projects/dns.c.html - */ - #include "config.h" #include "dns.h" #include "main.h" #include "utlist.h" +#include "chacha_private.h" #ifdef HAVE_OPENSSL #include #endif @@ -53,19 +47,70 @@ static const unsigned initial_bias = 72; static const gint dns_port = 53; - -#ifdef HAVE_ARC4RANDOM -#define DNS_RANDOM arc4random -#elif defined HAVE_RANDOM -#define DNS_RANDOM random -#else -#define DNS_RANDOM rand -#endif - #define UDP_PACKET_SIZE 4096 #define DNS_COMPRESSION_BITS 0xC0 +static void dns_retransmit_handler (gint fd, short what, void *arg); + +/* + * DNS permutor utilities + */ + +#define PERMUTOR_BUF_SIZE 32768 +#define PERMUTOR_KSIZE 32 +#define PERMUTOR_IVSIZE 8 + +struct dns_permutor { + chacha_ctx ctx; + guchar perm_buf[PERMUTOR_BUF_SIZE]; + guint pos; +}; + +/** + * Init chacha20 context + * @param p + */ +static void +dns_permutor_init (struct dns_permutor *p) +{ + /* Init random key and IV */ + rspamd_random_bytes (p->perm_buf, sizeof (p->perm_buf)); + + /* Setup ctx */ + chacha_keysetup (&p->ctx, p->perm_buf, PERMUTOR_KSIZE * 8, 0); + chacha_ivsetup (&p->ctx, p->perm_buf + PERMUTOR_KSIZE); + + chacha_encrypt_bytes (&p->ctx, p->perm_buf, p->perm_buf, sizeof (p->perm_buf)); + + p->pos = 0; +} + +static struct dns_permutor * +dns_permutor_new (memory_pool_t *pool) +{ + struct dns_permutor *new; + + new = memory_pool_alloc0 (pool, sizeof (struct dns_permutor)); + dns_permutor_init (new); + + return new; +} + +static guint16 +dns_permutor_generate_id (struct dns_permutor *p) +{ + guint16 id; + if (p->pos + sizeof (guint16) >= sizeof (p->perm_buf)) { + dns_permutor_init (p); + } + + memcpy (&id, &p->perm_buf[p->pos], sizeof (guint16)); + p->pos += sizeof (guint16); + + return id; +} + /* Punycode utility */ static guint digit(unsigned n) { @@ -201,240 +246,6 @@ punycode_label_toascii(const gunichar *in, gsize in_len, gchar *out, return TRUE; } - -/* - * P E R M U T A T I O N G E N E R A T O R - */ - -#define DNS_K_TEA_BLOCK_SIZE 8 -#define DNS_K_TEA_CYCLES 32 -#define DNS_K_TEA_MAGIC 0x9E3779B9U - -static void dns_retransmit_handler (gint fd, short what, void *arg); - - -static void -dns_k_tea_init(struct dns_k_tea *tea, guint32 key[], guint cycles) -{ - memcpy(tea->key, key, sizeof tea->key); - - tea->cycles = (cycles)? cycles : DNS_K_TEA_CYCLES; -} /* dns_k_tea_init() */ - - -static void -dns_k_tea_encrypt (struct dns_k_tea *tea, guint32 v[], guint32 *w) -{ - guint32 y, z, sum, n; - - y = v[0]; - z = v[1]; - sum = 0; - - for (n = 0; n < tea->cycles; n++) { - sum += DNS_K_TEA_MAGIC; - y += ((z << 4) + tea->key[0]) ^ (z + sum) ^ ((z >> 5) + tea->key[1]); - z += ((y << 4) + tea->key[2]) ^ (y + sum) ^ ((y >> 5) + tea->key[3]); - } - - w[0] = y; - w[1] = z; - -} /* dns_k_tea_encrypt() */ - - -/* - * Permutation generator, based on a Luby-Rackoff Feistel construction. - * - * Specifically, this is a generic balanced Feistel block cipher using TEA - * (another block cipher) as the pseudo-random function, F. At best it's as - * strong as F (TEA), notwithstanding the seeding. F could be AES, SHA-1, or - * perhaps Bernstein's Salsa20 core; I am naively trying to keep things - * simple. - * - * The generator can create a permutation of any set of numbers, as long as - * the size of the set is an even power of 2. This limitation arises either - * out of an inherent property of balanced Feistel constructions, or by my - * own ignorance. I'll tackle an unbalanced construction after I wrap my - * head around Schneier and Kelsey's paper. - * - * CAVEAT EMPTOR. IANAC. - */ -#define DNS_K_PERMUTOR_ROUNDS 8 - - - -static inline guint -dns_k_permutor_powof (guint n) -{ - guint m, i = 0; - - for (m = 1; m < n; m <<= 1, i++); - - return i; -} /* dns_k_permutor_powof() */ - -static void -dns_k_permutor_init (struct dns_k_permutor *p, guint low, guint high) -{ - guint32 key[DNS_K_TEA_KEY_SIZE / sizeof (guint32)]; - guint width, i; - - p->stepi = 0; - - p->length = (high - low) + 1; - p->limit = high; - - width = dns_k_permutor_powof (p->length); - width += width % 2; - - p->shift = width / 2; - p->mask = (1U << p->shift) - 1; - p->rounds = DNS_K_PERMUTOR_ROUNDS; - -#ifndef HAVE_OPENSSL - for (i = 0; i < G_N_ELEMENTS (key); i++) { - key[i] = DNS_RANDOM (); - } -#else - if (RAND_bytes ((unsigned char *)key, sizeof (key)) != 1) { - for (i = 0; i < G_N_ELEMENTS (key); i++) { - key[i] = DNS_RANDOM (); - } - } -#endif - dns_k_tea_init (&p->tea, key, 0); - -} /* dns_k_permutor_init() */ - - -static guint -dns_k_permutor_F (struct dns_k_permutor *p, guint k, guint x) -{ - guint32 in[DNS_K_TEA_BLOCK_SIZE / sizeof (guint32)], out[DNS_K_TEA_BLOCK_SIZE / sizeof (guint32)]; - - memset(in, '\0', sizeof in); - - in[0] = k; - in[1] = x; - - dns_k_tea_encrypt (&p->tea, in, out); - - return p->mask & out[0]; -} /* dns_k_permutor_F() */ - - -static guint -dns_k_permutor_E (struct dns_k_permutor *p, guint n) -{ - guint l[2], r[2]; - guint i; - - i = 0; - l[i] = p->mask & (n >> p->shift); - r[i] = p->mask & (n >> 0); - - do { - l[(i + 1) % 2] = r[i % 2]; - r[(i + 1) % 2] = l[i % 2] ^ dns_k_permutor_F(p, i, r[i % 2]); - - i++; - } while (i < p->rounds - 1); - - return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0); -} /* dns_k_permutor_E() */ - - -static guint -dns_k_permutor_D (struct dns_k_permutor *p, guint n) -{ - guint l[2], r[2]; - guint i; - - i = p->rounds - 1; - l[i % 2] = p->mask & (n >> p->shift); - r[i % 2] = p->mask & (n >> 0); - - do { - i--; - - r[i % 2] = l[(i + 1) % 2]; - l[i % 2] = r[(i + 1) % 2] ^ dns_k_permutor_F(p, i, l[(i + 1) % 2]); - } while (i > 0); - - return ((l[i % 2] & p->mask) << p->shift) | ((r[i % 2] & p->mask) << 0); -} /* dns_k_permutor_D() */ - - -static guint -dns_k_permutor_step(struct dns_k_permutor *p) -{ - guint n; - - do { - n = dns_k_permutor_E(p, p->stepi++); - } while (n >= p->length); - - return n + (p->limit + 1 - p->length); -} /* dns_k_permutor_step() */ - - -/* - * Simple permutation box. Useful for shuffling rrsets from an iterator. - * Uses AES s-box to provide good diffusion. - */ -static guint16 -dns_k_shuffle16 (guint16 n, guint s) -{ - static const guint8 sbox[256] = - { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, - 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, - 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, - 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, - 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, - 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, - 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, - 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, - 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, - 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, - 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, - 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, - 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, - 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, - 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, - 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, - 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; - guchar a, b; - guint i; - - a = 0xff & (n >> 0); - b = 0xff & (n >> 8); - - for (i = 0; i < 4; i++) { - a ^= 0xff & s; - a = sbox[a] ^ b; - b = sbox[b] ^ a; - s >>= 8; - } - - return ((0xff00 & (a << 8)) | (0x00ff & (b << 0))); -} /* dns_k_shuffle16() */ - struct dns_request_key { guint16 id; guint16 port; @@ -497,7 +308,7 @@ make_dns_header (struct rspamd_dns_request *req) /* Set DNS header values */ header = (struct dns_header *)req->packet; memset (header, 0 , sizeof (struct dns_header)); - header->qid = dns_k_permutor_step (req->resolver->permutor); + header->qid = dns_permutor_generate_id (req->resolver->permutor); header->rd = 1; header->qdcount = htons (1); req->pos += sizeof (struct dns_header); @@ -1528,7 +1339,7 @@ make_dns_request (struct rspamd_dns_resolver *resolver, while (g_hash_table_lookup (req->io->requests, &req->id)) { /* Check for unique id */ header = (struct dns_header *)req->packet; - header->qid = dns_k_permutor_step (resolver->permutor); + header->qid = dns_permutor_generate_id (resolver->permutor); req->id = header->qid; if (++r > max_id_cycles) { msg_err ("cannot generate new id for server %s", serv->name); @@ -1622,8 +1433,7 @@ dns_resolver_init (struct event_base *ev_base, struct config_file *cfg) new = memory_pool_alloc0 (cfg->cfg_pool, sizeof (struct rspamd_dns_resolver)); new->ev_base = ev_base; - new->permutor = memory_pool_alloc (cfg->cfg_pool, sizeof (struct dns_k_permutor)); - dns_k_permutor_init (new->permutor, 0, G_MAXUINT16); + new->permutor = dns_permutor_new (cfg->cfg_pool); new->io_channels = g_hash_table_new (g_direct_hash, g_direct_equal); new->static_pool = cfg->cfg_pool; new->request_timeout = cfg->dns_timeout; diff --git a/src/dns.h b/src/dns.h index 0b701391b..68aa17e82 100644 --- a/src/dns.h +++ b/src/dns.h @@ -1,3 +1,28 @@ +/* + * Copyright (c) 2013, Vsevolod Stakhov + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + #ifndef RSPAMD_DNS_H #define RSPAMD_DNS_H @@ -40,24 +65,12 @@ struct rspamd_dns_io_channel { struct rspamd_dns_io_channel *prev, *next; }; -#define DNS_K_TEA_KEY_SIZE 16 - -struct dns_k_tea { - guint32 key[DNS_K_TEA_KEY_SIZE / sizeof (guint32)]; - guint cycles; -}; /* struct dns_k_tea */ - -struct dns_k_permutor { - guint stepi, length, limit; - guint shift, mask, rounds; - - struct dns_k_tea tea; -}; +struct dns_permutor; struct rspamd_dns_resolver { struct rspamd_dns_server servers[MAX_SERVERS]; gint servers_num; /**< number of DNS servers registered */ - struct dns_k_permutor *permutor; /**< permutor for randomizing request id */ + struct dns_permutor *permutor; /**< permutor for randomizing request id */ guint request_timeout; guint max_retransmits; guint max_errors; diff --git a/src/util.c b/src/util.c index b537e8827..db7529a92 100644 --- a/src/util.c +++ b/src/util.c @@ -2397,25 +2397,50 @@ restart: } void -rspamd_prng_seed (void) +rspamd_random_bytes (gchar *buf, gsize buflen) { - guint32 rand_seed = 0; + gint fd; + gsize i; + time_t t; #ifdef HAVE_OPENSSL - gchar rand_bytes[sizeof (guint32)]; /* Init random generator */ - if (RAND_bytes (rand_bytes, sizeof (rand_bytes)) != 1) { + if (RAND_bytes (buf, buflen) != 1) { msg_err ("cannot seed random generator using openssl: %s, using time", ERR_error_string (ERR_get_error (), NULL)); - rand_seed = time (NULL); - } - else { - memcpy (&rand_seed, rand_bytes, sizeof (guint32)); + goto fallback; } #else - rand_seed = time (NULL); + goto fallback; #endif + return; + +fallback: + /* Try to use /dev/random if no openssl is found */ + fd = open ("/dev/random", O_RDONLY); + if (fd != -1) { + if (read (fd, buf, buflen) == (gssize)buflen) { + close (fd); + return; + } + close (fd); + } + /* No /dev/random */ + for (i = 0; i < buflen;) { + /* Place least significant byte to the beginning */ + t = time (NULL); + t = GLONG_TO_BE (t); + memcpy (&buf[i], &t, MIN (sizeof (t), buflen - i)); + i += sizeof (t); + } +} + +void +rspamd_prng_seed (void) +{ + guint32 rand_seed = 0; + rspamd_random_bytes ((gchar *)&rand_seed, sizeof (rand_seed)); g_random_set_seed (rand_seed); } diff --git a/src/util.h b/src/util.h index edcfa6122..c36587cab 100644 --- a/src/util.h +++ b/src/util.h @@ -455,4 +455,11 @@ gint rspamd_read_passphrase (gchar *buf, gint size, gint rwflag, gpointer key); */ void rspamd_prng_seed (void); +/** + * Generate random bytes using the most suitable generator + * @param buf + * @param buflen + */ +void rspamd_random_bytes (gchar *buf, gsize buflen); + #endif