/src/openssl111/crypto/siphash/siphash.c
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | /* | 
| 2 |  |  * Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved. | 
| 3 |  |  * | 
| 4 |  |  * Licensed under the OpenSSL license (the "License").  You may not use | 
| 5 |  |  * this file except in compliance with the License.  You can obtain a copy | 
| 6 |  |  * in the file LICENSE in the source distribution or at | 
| 7 |  |  * https://www.openssl.org/source/license.html | 
| 8 |  |  */ | 
| 9 |  |  | 
| 10 |  | /* Based on https://131002.net/siphash C reference implementation */ | 
| 11 |  | /* | 
| 12 |  |    SipHash reference C implementation | 
| 13 |  |  | 
| 14 |  |    Copyright (c) 2012-2016 Jean-Philippe Aumasson | 
| 15 |  |    Copyright (c) 2012-2014 Daniel J. Bernstein | 
| 16 |  |  | 
| 17 |  |    To the extent possible under law, the author(s) have dedicated all copyright | 
| 18 |  |    and related and neighboring rights to this software to the public domain | 
| 19 |  |    worldwide. This software is distributed without any warranty. | 
| 20 |  |  | 
| 21 |  |    You should have received a copy of the CC0 Public Domain Dedication along | 
| 22 |  |    with this software. If not, see | 
| 23 |  |    <http://creativecommons.org/publicdomain/zero/1.0/>. | 
| 24 |  |  */ | 
| 25 |  |  | 
| 26 |  | #include <stdlib.h> | 
| 27 |  | #include <string.h> | 
| 28 |  | #include <openssl/crypto.h> | 
| 29 |  |  | 
| 30 |  | #include "crypto/siphash.h" | 
| 31 |  | #include "siphash_local.h" | 
| 32 |  |  | 
| 33 |  | /* default: SipHash-2-4 */ | 
| 34 | 0 | #define SIPHASH_C_ROUNDS 2 | 
| 35 | 0 | #define SIPHASH_D_ROUNDS 4 | 
| 36 |  |  | 
| 37 | 0 | #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) | 
| 38 |  |  | 
| 39 |  | #define U32TO8_LE(p, v)                                                        \ | 
| 40 | 0 |     (p)[0] = (uint8_t)((v));                                                   \ | 
| 41 | 0 |     (p)[1] = (uint8_t)((v) >> 8);                                              \ | 
| 42 | 0 |     (p)[2] = (uint8_t)((v) >> 16);                                             \ | 
| 43 | 0 |     (p)[3] = (uint8_t)((v) >> 24); | 
| 44 |  |  | 
| 45 |  | #define U64TO8_LE(p, v)                                                        \ | 
| 46 | 0 |     U32TO8_LE((p), (uint32_t)((v)));                                           \ | 
| 47 | 0 |     U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); | 
| 48 |  |  | 
| 49 |  | #define U8TO64_LE(p)                                                           \ | 
| 50 | 0 |     (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) |                        \ | 
| 51 | 0 |      ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) |                 \ | 
| 52 | 0 |      ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) |                 \ | 
| 53 | 0 |      ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) | 
| 54 |  |  | 
| 55 |  | #define SIPROUND                                                               \ | 
| 56 | 0 |     do {                                                                       \ | 
| 57 | 0 |         v0 += v1;                                                              \ | 
| 58 | 0 |         v1 = ROTL(v1, 13);                                                     \ | 
| 59 | 0 |         v1 ^= v0;                                                              \ | 
| 60 | 0 |         v0 = ROTL(v0, 32);                                                     \ | 
| 61 | 0 |         v2 += v3;                                                              \ | 
| 62 | 0 |         v3 = ROTL(v3, 16);                                                     \ | 
| 63 | 0 |         v3 ^= v2;                                                              \ | 
| 64 | 0 |         v0 += v3;                                                              \ | 
| 65 | 0 |         v3 = ROTL(v3, 21);                                                     \ | 
| 66 | 0 |         v3 ^= v0;                                                              \ | 
| 67 | 0 |         v2 += v1;                                                              \ | 
| 68 | 0 |         v1 = ROTL(v1, 17);                                                     \ | 
| 69 | 0 |         v1 ^= v2;                                                              \ | 
| 70 | 0 |         v2 = ROTL(v2, 32);                                                     \ | 
| 71 | 0 |     } while (0) | 
| 72 |  |  | 
| 73 |  | size_t SipHash_ctx_size(void) | 
| 74 | 0 | { | 
| 75 | 0 |     return sizeof(SIPHASH); | 
| 76 | 0 | } | 
| 77 |  |  | 
| 78 |  | size_t SipHash_hash_size(SIPHASH *ctx) | 
| 79 | 0 | { | 
| 80 | 0 |     return ctx->hash_size; | 
| 81 | 0 | } | 
| 82 |  |  | 
| 83 |  | static size_t siphash_adjust_hash_size(size_t hash_size) | 
| 84 | 0 | { | 
| 85 | 0 |     if (hash_size == 0) | 
| 86 | 0 |         hash_size = SIPHASH_MAX_DIGEST_SIZE; | 
| 87 | 0 |     return hash_size; | 
| 88 | 0 | } | 
| 89 |  |  | 
| 90 |  | int SipHash_set_hash_size(SIPHASH *ctx, size_t hash_size) | 
| 91 | 0 | { | 
| 92 | 0 |     hash_size = siphash_adjust_hash_size(hash_size); | 
| 93 | 0 |     if (hash_size != SIPHASH_MIN_DIGEST_SIZE | 
| 94 | 0 |         && hash_size != SIPHASH_MAX_DIGEST_SIZE) | 
| 95 | 0 |         return 0; | 
| 96 |  |  | 
| 97 |  |     /* | 
| 98 |  |      * It's possible that the key was set first.  If the hash size changes, | 
| 99 |  |      * we need to adjust v1 (see SipHash_Init(). | 
| 100 |  |      */ | 
| 101 |  |  | 
| 102 |  |     /* Start by adjusting the stored size, to make things easier */ | 
| 103 | 0 |     ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size); | 
| 104 |  |  | 
| 105 |  |     /* Now, adjust ctx->v1 if the old and the new size differ */ | 
| 106 | 0 |     if ((size_t)ctx->hash_size != hash_size) { | 
| 107 | 0 |         ctx->v1 ^= 0xee; | 
| 108 | 0 |         ctx->hash_size = hash_size; | 
| 109 | 0 |     } | 
| 110 | 0 |     return 1; | 
| 111 | 0 | } | 
| 112 |  |  | 
| 113 |  | /* hash_size = crounds = drounds = 0 means SipHash24 with 16-byte output */ | 
| 114 |  | int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int crounds, int drounds) | 
| 115 | 0 | { | 
| 116 | 0 |     uint64_t k0 = U8TO64_LE(k); | 
| 117 | 0 |     uint64_t k1 = U8TO64_LE(k + 8); | 
| 118 |  |  | 
| 119 |  |     /* If the hash size wasn't set, i.e. is zero */ | 
| 120 | 0 |     ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size); | 
| 121 |  | 
 | 
| 122 | 0 |     if (drounds == 0) | 
| 123 | 0 |         drounds = SIPHASH_D_ROUNDS; | 
| 124 | 0 |     if (crounds == 0) | 
| 125 | 0 |         crounds = SIPHASH_C_ROUNDS; | 
| 126 |  | 
 | 
| 127 | 0 |     ctx->crounds = crounds; | 
| 128 | 0 |     ctx->drounds = drounds; | 
| 129 |  | 
 | 
| 130 | 0 |     ctx->len = 0; | 
| 131 | 0 |     ctx->total_inlen = 0; | 
| 132 |  | 
 | 
| 133 | 0 |     ctx->v0 = 0x736f6d6570736575ULL ^ k0; | 
| 134 | 0 |     ctx->v1 = 0x646f72616e646f6dULL ^ k1; | 
| 135 | 0 |     ctx->v2 = 0x6c7967656e657261ULL ^ k0; | 
| 136 | 0 |     ctx->v3 = 0x7465646279746573ULL ^ k1; | 
| 137 |  | 
 | 
| 138 | 0 |     if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE) | 
| 139 | 0 |         ctx->v1 ^= 0xee; | 
| 140 |  | 
 | 
| 141 | 0 |     return 1; | 
| 142 | 0 | } | 
| 143 |  |  | 
| 144 |  | void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen) | 
| 145 | 0 | { | 
| 146 | 0 |     uint64_t m; | 
| 147 | 0 |     const uint8_t *end; | 
| 148 | 0 |     int left; | 
| 149 | 0 |     int i; | 
| 150 | 0 |     uint64_t v0 = ctx->v0; | 
| 151 | 0 |     uint64_t v1 = ctx->v1; | 
| 152 | 0 |     uint64_t v2 = ctx->v2; | 
| 153 | 0 |     uint64_t v3 = ctx->v3; | 
| 154 |  | 
 | 
| 155 | 0 |     ctx->total_inlen += inlen; | 
| 156 |  | 
 | 
| 157 | 0 |     if (ctx->len) { | 
| 158 |  |         /* deal with leavings */ | 
| 159 | 0 |         size_t available = SIPHASH_BLOCK_SIZE - ctx->len; | 
| 160 |  |  | 
| 161 |  |         /* not enough to fill leavings */ | 
| 162 | 0 |         if (inlen < available) { | 
| 163 | 0 |             memcpy(&ctx->leavings[ctx->len], in, inlen); | 
| 164 | 0 |             ctx->len += inlen; | 
| 165 | 0 |             return; | 
| 166 | 0 |         } | 
| 167 |  |  | 
| 168 |  |         /* copy data into leavings and reduce input */ | 
| 169 | 0 |         memcpy(&ctx->leavings[ctx->len], in, available); | 
| 170 | 0 |         inlen -= available; | 
| 171 | 0 |         in += available; | 
| 172 |  |  | 
| 173 |  |         /* process leavings */ | 
| 174 | 0 |         m = U8TO64_LE(ctx->leavings); | 
| 175 | 0 |         v3 ^= m; | 
| 176 | 0 |         for (i = 0; i < ctx->crounds; ++i) | 
| 177 | 0 |             SIPROUND; | 
| 178 | 0 |         v0 ^= m; | 
| 179 | 0 |     } | 
| 180 | 0 |     left = inlen & (SIPHASH_BLOCK_SIZE-1); /* gets put into leavings */ | 
| 181 | 0 |     end = in + inlen - left; | 
| 182 |  | 
 | 
| 183 | 0 |     for (; in != end; in += 8) { | 
| 184 | 0 |         m = U8TO64_LE(in); | 
| 185 | 0 |         v3 ^= m; | 
| 186 | 0 |         for (i = 0; i < ctx->crounds; ++i) | 
| 187 | 0 |             SIPROUND; | 
| 188 | 0 |         v0 ^= m; | 
| 189 | 0 |     } | 
| 190 |  |  | 
| 191 |  |     /* save leavings and other ctx */ | 
| 192 | 0 |     if (left) | 
| 193 | 0 |         memcpy(ctx->leavings, end, left); | 
| 194 | 0 |     ctx->len = left; | 
| 195 |  | 
 | 
| 196 | 0 |     ctx->v0 = v0; | 
| 197 | 0 |     ctx->v1 = v1; | 
| 198 | 0 |     ctx->v2 = v2; | 
| 199 | 0 |     ctx->v3 = v3; | 
| 200 | 0 | } | 
| 201 |  |  | 
| 202 |  | int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen) | 
| 203 | 0 | { | 
| 204 |  |     /* finalize hash */ | 
| 205 | 0 |     int i; | 
| 206 | 0 |     uint64_t b = ctx->total_inlen << 56; | 
| 207 | 0 |     uint64_t v0 = ctx->v0; | 
| 208 | 0 |     uint64_t v1 = ctx->v1; | 
| 209 | 0 |     uint64_t v2 = ctx->v2; | 
| 210 | 0 |     uint64_t v3 = ctx->v3; | 
| 211 |  | 
 | 
| 212 | 0 |     if (outlen != (size_t)ctx->hash_size) | 
| 213 | 0 |         return 0; | 
| 214 |  |  | 
| 215 | 0 |     switch (ctx->len) { | 
| 216 | 0 |     case 7: | 
| 217 | 0 |         b |= ((uint64_t)ctx->leavings[6]) << 48; | 
| 218 |  |         /* fall thru */ | 
| 219 | 0 |     case 6: | 
| 220 | 0 |         b |= ((uint64_t)ctx->leavings[5]) << 40; | 
| 221 |  |         /* fall thru */ | 
| 222 | 0 |     case 5: | 
| 223 | 0 |         b |= ((uint64_t)ctx->leavings[4]) << 32; | 
| 224 |  |         /* fall thru */ | 
| 225 | 0 |     case 4: | 
| 226 | 0 |         b |= ((uint64_t)ctx->leavings[3]) << 24; | 
| 227 |  |         /* fall thru */ | 
| 228 | 0 |     case 3: | 
| 229 | 0 |         b |= ((uint64_t)ctx->leavings[2]) << 16; | 
| 230 |  |         /* fall thru */ | 
| 231 | 0 |     case 2: | 
| 232 | 0 |         b |= ((uint64_t)ctx->leavings[1]) <<  8; | 
| 233 |  |         /* fall thru */ | 
| 234 | 0 |     case 1: | 
| 235 | 0 |         b |= ((uint64_t)ctx->leavings[0]); | 
| 236 | 0 |     case 0: | 
| 237 | 0 |         break; | 
| 238 | 0 |     } | 
| 239 |  |  | 
| 240 | 0 |     v3 ^= b; | 
| 241 | 0 |     for (i = 0; i < ctx->crounds; ++i) | 
| 242 | 0 |         SIPROUND; | 
| 243 | 0 |     v0 ^= b; | 
| 244 | 0 |     if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE) | 
| 245 | 0 |         v2 ^= 0xee; | 
| 246 | 0 |     else | 
| 247 | 0 |         v2 ^= 0xff; | 
| 248 | 0 |     for (i = 0; i < ctx->drounds; ++i) | 
| 249 | 0 |         SIPROUND; | 
| 250 | 0 |     b = v0 ^ v1 ^ v2  ^ v3; | 
| 251 | 0 |     U64TO8_LE(out, b); | 
| 252 | 0 |     if (ctx->hash_size == SIPHASH_MIN_DIGEST_SIZE) | 
| 253 | 0 |         return 1; | 
| 254 | 0 |     v1 ^= 0xdd; | 
| 255 | 0 |     for (i = 0; i < ctx->drounds; ++i) | 
| 256 | 0 |         SIPROUND; | 
| 257 | 0 |     b = v0 ^ v1 ^ v2  ^ v3; | 
| 258 | 0 |     U64TO8_LE(out + 8, b); | 
| 259 | 0 |     return 1; | 
| 260 | 0 | } |