1780fb4a2SCy Schubert /* 2780fb4a2SCy Schubert * SHA-512 hash implementation and interface functions 3780fb4a2SCy Schubert * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com> 4780fb4a2SCy Schubert * 5780fb4a2SCy Schubert * This software may be distributed under the terms of the BSD license. 6780fb4a2SCy Schubert * See README for more details. 7780fb4a2SCy Schubert */ 8780fb4a2SCy Schubert 9780fb4a2SCy Schubert #include "includes.h" 10780fb4a2SCy Schubert 11780fb4a2SCy Schubert #include "common.h" 12780fb4a2SCy Schubert #include "sha512_i.h" 13780fb4a2SCy Schubert #include "crypto.h" 14780fb4a2SCy Schubert 15780fb4a2SCy Schubert 16780fb4a2SCy Schubert /** 17780fb4a2SCy Schubert * sha512_vector - SHA512 hash for data vector 18780fb4a2SCy Schubert * @num_elem: Number of elements in the data vector 19780fb4a2SCy Schubert * @addr: Pointers to the data areas 20780fb4a2SCy Schubert * @len: Lengths of the data blocks 21780fb4a2SCy Schubert * @mac: Buffer for the hash 22780fb4a2SCy Schubert * Returns: 0 on success, -1 of failure 23780fb4a2SCy Schubert */ 24780fb4a2SCy Schubert int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len, 25780fb4a2SCy Schubert u8 *mac) 26780fb4a2SCy Schubert { 27780fb4a2SCy Schubert struct sha512_state ctx; 28780fb4a2SCy Schubert size_t i; 29780fb4a2SCy Schubert 30780fb4a2SCy Schubert sha512_init(&ctx); 31780fb4a2SCy Schubert for (i = 0; i < num_elem; i++) 32780fb4a2SCy Schubert if (sha512_process(&ctx, addr[i], len[i])) 33780fb4a2SCy Schubert return -1; 34780fb4a2SCy Schubert if (sha512_done(&ctx, mac)) 35780fb4a2SCy Schubert return -1; 36780fb4a2SCy Schubert return 0; 37780fb4a2SCy Schubert } 38780fb4a2SCy Schubert 39780fb4a2SCy Schubert 40780fb4a2SCy Schubert /* ===== start - public domain SHA512 implementation ===== */ 41780fb4a2SCy Schubert 42780fb4a2SCy Schubert /* This is based on SHA512 implementation in LibTomCrypt that was released into 43780fb4a2SCy Schubert * public domain by Tom St Denis. */ 44780fb4a2SCy Schubert 45780fb4a2SCy Schubert #define CONST64(n) n ## ULL 46780fb4a2SCy Schubert 47780fb4a2SCy Schubert /* the K array */ 48780fb4a2SCy Schubert static const u64 K[80] = { 49780fb4a2SCy Schubert CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd), 50780fb4a2SCy Schubert CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc), 51780fb4a2SCy Schubert CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019), 52780fb4a2SCy Schubert CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118), 53780fb4a2SCy Schubert CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe), 54780fb4a2SCy Schubert CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2), 55780fb4a2SCy Schubert CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1), 56780fb4a2SCy Schubert CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694), 57780fb4a2SCy Schubert CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3), 58780fb4a2SCy Schubert CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65), 59780fb4a2SCy Schubert CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483), 60780fb4a2SCy Schubert CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5), 61780fb4a2SCy Schubert CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210), 62780fb4a2SCy Schubert CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4), 63780fb4a2SCy Schubert CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725), 64780fb4a2SCy Schubert CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70), 65780fb4a2SCy Schubert CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926), 66780fb4a2SCy Schubert CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df), 67780fb4a2SCy Schubert CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8), 68780fb4a2SCy Schubert CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b), 69780fb4a2SCy Schubert CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001), 70780fb4a2SCy Schubert CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30), 71780fb4a2SCy Schubert CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910), 72780fb4a2SCy Schubert CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8), 73780fb4a2SCy Schubert CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53), 74780fb4a2SCy Schubert CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8), 75780fb4a2SCy Schubert CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb), 76780fb4a2SCy Schubert CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3), 77780fb4a2SCy Schubert CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60), 78780fb4a2SCy Schubert CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec), 79780fb4a2SCy Schubert CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9), 80780fb4a2SCy Schubert CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b), 81780fb4a2SCy Schubert CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207), 82780fb4a2SCy Schubert CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178), 83780fb4a2SCy Schubert CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6), 84780fb4a2SCy Schubert CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b), 85780fb4a2SCy Schubert CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493), 86780fb4a2SCy Schubert CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c), 87780fb4a2SCy Schubert CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a), 88780fb4a2SCy Schubert CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817) 89780fb4a2SCy Schubert }; 90780fb4a2SCy Schubert 91780fb4a2SCy Schubert /* Various logical functions */ 92780fb4a2SCy Schubert #define Ch(x,y,z) (z ^ (x & (y ^ z))) 93780fb4a2SCy Schubert #define Maj(x,y,z) (((x | y) & z) | (x & y)) 94780fb4a2SCy Schubert #define S(x, n) ROR64c(x, n) 95780fb4a2SCy Schubert #define R(x, n) (((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((u64) n)) 96780fb4a2SCy Schubert #define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) 97780fb4a2SCy Schubert #define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) 98780fb4a2SCy Schubert #define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) 99780fb4a2SCy Schubert #define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) 100780fb4a2SCy Schubert #ifndef MIN 101780fb4a2SCy Schubert #define MIN(x, y) (((x) < (y)) ? (x) : (y)) 102780fb4a2SCy Schubert #endif 103780fb4a2SCy Schubert 104780fb4a2SCy Schubert #define ROR64c(x, y) \ 105780fb4a2SCy Schubert ( ((((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((u64) (y) & CONST64(63))) | \ 106780fb4a2SCy Schubert ((x) << ((u64) (64 - ((y) & CONST64(63)))))) & \ 107780fb4a2SCy Schubert CONST64(0xFFFFFFFFFFFFFFFF)) 108780fb4a2SCy Schubert 109780fb4a2SCy Schubert /* compress 1024-bits */ 110780fb4a2SCy Schubert static int sha512_compress(struct sha512_state *md, unsigned char *buf) 111780fb4a2SCy Schubert { 112*4bc52338SCy Schubert u64 S[8], t0, t1; 113*4bc52338SCy Schubert u64 *W; 114780fb4a2SCy Schubert int i; 115780fb4a2SCy Schubert 116*4bc52338SCy Schubert W = os_malloc(80 * sizeof(u64)); 117*4bc52338SCy Schubert if (!W) 118*4bc52338SCy Schubert return -1; 119*4bc52338SCy Schubert 120780fb4a2SCy Schubert /* copy state into S */ 121780fb4a2SCy Schubert for (i = 0; i < 8; i++) { 122780fb4a2SCy Schubert S[i] = md->state[i]; 123780fb4a2SCy Schubert } 124780fb4a2SCy Schubert 125780fb4a2SCy Schubert /* copy the state into 1024-bits into W[0..15] */ 126780fb4a2SCy Schubert for (i = 0; i < 16; i++) 127780fb4a2SCy Schubert W[i] = WPA_GET_BE64(buf + (8 * i)); 128780fb4a2SCy Schubert 129780fb4a2SCy Schubert /* fill W[16..79] */ 130780fb4a2SCy Schubert for (i = 16; i < 80; i++) { 131780fb4a2SCy Schubert W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + 132780fb4a2SCy Schubert W[i - 16]; 133780fb4a2SCy Schubert } 134780fb4a2SCy Schubert 135780fb4a2SCy Schubert /* Compress */ 136780fb4a2SCy Schubert for (i = 0; i < 80; i++) { 137780fb4a2SCy Schubert t0 = S[7] + Sigma1(S[4]) + Ch(S[4], S[5], S[6]) + K[i] + W[i]; 138780fb4a2SCy Schubert t1 = Sigma0(S[0]) + Maj(S[0], S[1], S[2]); 139780fb4a2SCy Schubert S[7] = S[6]; 140780fb4a2SCy Schubert S[6] = S[5]; 141780fb4a2SCy Schubert S[5] = S[4]; 142780fb4a2SCy Schubert S[4] = S[3] + t0; 143780fb4a2SCy Schubert S[3] = S[2]; 144780fb4a2SCy Schubert S[2] = S[1]; 145780fb4a2SCy Schubert S[1] = S[0]; 146780fb4a2SCy Schubert S[0] = t0 + t1; 147780fb4a2SCy Schubert } 148780fb4a2SCy Schubert 149780fb4a2SCy Schubert /* feedback */ 150780fb4a2SCy Schubert for (i = 0; i < 8; i++) { 151780fb4a2SCy Schubert md->state[i] = md->state[i] + S[i]; 152780fb4a2SCy Schubert } 153780fb4a2SCy Schubert 154*4bc52338SCy Schubert os_free(W); 155780fb4a2SCy Schubert return 0; 156780fb4a2SCy Schubert } 157780fb4a2SCy Schubert 158780fb4a2SCy Schubert 159780fb4a2SCy Schubert /** 160780fb4a2SCy Schubert Initialize the hash state 161780fb4a2SCy Schubert @param md The hash state you wish to initialize 162780fb4a2SCy Schubert @return CRYPT_OK if successful 163780fb4a2SCy Schubert */ 164780fb4a2SCy Schubert void sha512_init(struct sha512_state *md) 165780fb4a2SCy Schubert { 166780fb4a2SCy Schubert md->curlen = 0; 167780fb4a2SCy Schubert md->length = 0; 168780fb4a2SCy Schubert md->state[0] = CONST64(0x6a09e667f3bcc908); 169780fb4a2SCy Schubert md->state[1] = CONST64(0xbb67ae8584caa73b); 170780fb4a2SCy Schubert md->state[2] = CONST64(0x3c6ef372fe94f82b); 171780fb4a2SCy Schubert md->state[3] = CONST64(0xa54ff53a5f1d36f1); 172780fb4a2SCy Schubert md->state[4] = CONST64(0x510e527fade682d1); 173780fb4a2SCy Schubert md->state[5] = CONST64(0x9b05688c2b3e6c1f); 174780fb4a2SCy Schubert md->state[6] = CONST64(0x1f83d9abfb41bd6b); 175780fb4a2SCy Schubert md->state[7] = CONST64(0x5be0cd19137e2179); 176780fb4a2SCy Schubert } 177780fb4a2SCy Schubert 178780fb4a2SCy Schubert 179780fb4a2SCy Schubert /** 180780fb4a2SCy Schubert Process a block of memory though the hash 181780fb4a2SCy Schubert @param md The hash state 182780fb4a2SCy Schubert @param in The data to hash 183780fb4a2SCy Schubert @param inlen The length of the data (octets) 184780fb4a2SCy Schubert @return CRYPT_OK if successful 185780fb4a2SCy Schubert */ 186780fb4a2SCy Schubert int sha512_process(struct sha512_state *md, const unsigned char *in, 187780fb4a2SCy Schubert unsigned long inlen) 188780fb4a2SCy Schubert { 189780fb4a2SCy Schubert unsigned long n; 190780fb4a2SCy Schubert 191780fb4a2SCy Schubert if (md->curlen >= sizeof(md->buf)) 192780fb4a2SCy Schubert return -1; 193780fb4a2SCy Schubert 194780fb4a2SCy Schubert while (inlen > 0) { 195780fb4a2SCy Schubert if (md->curlen == 0 && inlen >= SHA512_BLOCK_SIZE) { 196780fb4a2SCy Schubert if (sha512_compress(md, (unsigned char *) in) < 0) 197780fb4a2SCy Schubert return -1; 198780fb4a2SCy Schubert md->length += SHA512_BLOCK_SIZE * 8; 199780fb4a2SCy Schubert in += SHA512_BLOCK_SIZE; 200780fb4a2SCy Schubert inlen -= SHA512_BLOCK_SIZE; 201780fb4a2SCy Schubert } else { 202780fb4a2SCy Schubert n = MIN(inlen, (SHA512_BLOCK_SIZE - md->curlen)); 203780fb4a2SCy Schubert os_memcpy(md->buf + md->curlen, in, n); 204780fb4a2SCy Schubert md->curlen += n; 205780fb4a2SCy Schubert in += n; 206780fb4a2SCy Schubert inlen -= n; 207780fb4a2SCy Schubert if (md->curlen == SHA512_BLOCK_SIZE) { 208780fb4a2SCy Schubert if (sha512_compress(md, md->buf) < 0) 209780fb4a2SCy Schubert return -1; 210780fb4a2SCy Schubert md->length += 8 * SHA512_BLOCK_SIZE; 211780fb4a2SCy Schubert md->curlen = 0; 212780fb4a2SCy Schubert } 213780fb4a2SCy Schubert } 214780fb4a2SCy Schubert } 215780fb4a2SCy Schubert 216780fb4a2SCy Schubert return 0; 217780fb4a2SCy Schubert } 218780fb4a2SCy Schubert 219780fb4a2SCy Schubert 220780fb4a2SCy Schubert /** 221780fb4a2SCy Schubert Terminate the hash to get the digest 222780fb4a2SCy Schubert @param md The hash state 223780fb4a2SCy Schubert @param out [out] The destination of the hash (64 bytes) 224780fb4a2SCy Schubert @return CRYPT_OK if successful 225780fb4a2SCy Schubert */ 226780fb4a2SCy Schubert int sha512_done(struct sha512_state *md, unsigned char *out) 227780fb4a2SCy Schubert { 228780fb4a2SCy Schubert int i; 229780fb4a2SCy Schubert 230780fb4a2SCy Schubert if (md->curlen >= sizeof(md->buf)) 231780fb4a2SCy Schubert return -1; 232780fb4a2SCy Schubert 233780fb4a2SCy Schubert /* increase the length of the message */ 234780fb4a2SCy Schubert md->length += md->curlen * CONST64(8); 235780fb4a2SCy Schubert 236780fb4a2SCy Schubert /* append the '1' bit */ 237780fb4a2SCy Schubert md->buf[md->curlen++] = (unsigned char) 0x80; 238780fb4a2SCy Schubert 239780fb4a2SCy Schubert /* if the length is currently above 112 bytes we append zeros 240780fb4a2SCy Schubert * then compress. Then we can fall back to padding zeros and length 241780fb4a2SCy Schubert * encoding like normal. 242780fb4a2SCy Schubert */ 243780fb4a2SCy Schubert if (md->curlen > 112) { 244780fb4a2SCy Schubert while (md->curlen < 128) { 245780fb4a2SCy Schubert md->buf[md->curlen++] = (unsigned char) 0; 246780fb4a2SCy Schubert } 247780fb4a2SCy Schubert sha512_compress(md, md->buf); 248780fb4a2SCy Schubert md->curlen = 0; 249780fb4a2SCy Schubert } 250780fb4a2SCy Schubert 251780fb4a2SCy Schubert /* pad up to 120 bytes of zeroes 252780fb4a2SCy Schubert * note: that from 112 to 120 is the 64 MSB of the length. We assume 253780fb4a2SCy Schubert * that you won't hash > 2^64 bits of data... :-) 254780fb4a2SCy Schubert */ 255780fb4a2SCy Schubert while (md->curlen < 120) { 256780fb4a2SCy Schubert md->buf[md->curlen++] = (unsigned char) 0; 257780fb4a2SCy Schubert } 258780fb4a2SCy Schubert 259780fb4a2SCy Schubert /* store length */ 260780fb4a2SCy Schubert WPA_PUT_BE64(md->buf + 120, md->length); 261780fb4a2SCy Schubert sha512_compress(md, md->buf); 262780fb4a2SCy Schubert 263780fb4a2SCy Schubert /* copy output */ 264780fb4a2SCy Schubert for (i = 0; i < 8; i++) 265780fb4a2SCy Schubert WPA_PUT_BE64(out + (8 * i), md->state[i]); 266780fb4a2SCy Schubert 267780fb4a2SCy Schubert return 0; 268780fb4a2SCy Schubert } 269780fb4a2SCy Schubert 270780fb4a2SCy Schubert /* ===== end - public domain SHA512 implementation ===== */ 271