fix
[libpgclient.git] / src / hmac.c
blob6730226b85ca6a5a0b465cbca9bc49faeb716bc6
1 /*Copyright (c) Brian B.
3 This library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Lesser General Public
5 License as published by the Free Software Foundation; either
6 version 3 of the License, or (at your option) any later version.
7 See the file LICENSE included with this distribution for more
8 information.
10 Portions Copyright (c) 1994, Regents of the University of California
13 #include <string.h>
14 #include "hmac.h"
16 static const uint32_t sha_init_value [8] = {
17 0x6a09e667UL,
18 0xbb67ae85UL,
19 0x3c6ef372UL,
20 0xa54ff53aUL,
21 0x510e527fUL,
22 0x9b05688cUL,
23 0x1f83d9abUL,
24 0x5be0cd19UL
27 static const uint32_t K256[64] = {
28 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
29 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
30 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
31 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
32 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
33 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
34 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
35 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
36 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
37 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
38 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
39 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
40 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
41 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
42 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
43 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
46 void sha_init (sha_t *ctx) {
47 memcpy(ctx->state, sha_init_value, SHA_DIGEST_LEN);
48 memset(ctx->buf, 0, SHA_BLOCK_LEN);
49 ctx->bitcount = 0;
52 #define SHA_SHORT_BLOCK_LEN (SHA_BLOCK_LEN - 8)
54 #define R(b,x) ((x) >> (b))
55 #define S32(b,x) (((x) >> (b)) | ((x) << (32 - (b))))
56 #define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z)))
57 #define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
58 #define Sigma0(x) (S32(2, (x)) ^ S32(13, (x)) ^ S32(22, (x)))
59 #define Sigma1(x) (S32(6, (x)) ^ S32(11, (x)) ^ S32(25, (x)))
60 #define sigma0(x) (S32(7, (x)) ^ S32(18, (x)) ^ R(3 , (x)))
61 #define sigma1(x) (S32(17, (x)) ^ S32(19, (x)) ^ R(10, (x)))
63 #if BYTE_ORDER == LITTLE_ENDIAN
64 #define REVERSE32(w,x) { \
65 uint32_t tmp = (w); \
66 tmp = (tmp >> 16) | (tmp << 16); \
67 (x) = ((tmp & 0xff00ff00UL) >> 8) | ((tmp & 0x00ff00ffUL) << 8); \
69 #define REVERSE64(w,x) { \
70 uint64_t tmp = (w); \
71 tmp = (tmp >> 32) | (tmp << 32); \
72 tmp = ((tmp & 0xff00ff00ff00ff00ULL) >> 8) | \
73 ((tmp & 0x00ff00ff00ff00ffULL) << 8); \
74 (x) = ((tmp & 0xffff0000ffff0000ULL) >> 16) | \
75 ((tmp & 0x0000ffff0000ffffULL) << 16); \
77 #endif
79 static void sha_transform (sha_t *ctx, const uint8_t *data) {
80 uint32_t a = ctx->state[0],
81 b = ctx->state[1],
82 c = ctx->state[2],
83 d = ctx->state[3],
84 e = ctx->state[4],
85 f = ctx->state[5],
86 g = ctx->state[6],
87 h = ctx->state[7],
88 s0, s1, T1, T2, *w256 = (uint32_t*)ctx->buf;
89 int j = 0;
90 do {
91 w256[j] = (uint32_t)data[3] | ((uint32_t)data[2] << 8) | ((uint32_t)data[1] << 16) | ((uint32_t)data[0] << 24);
92 data += 4;
93 T1 = h + Sigma1(e) + Ch(e, f, g) + K256[j] + w256[j];
94 T2 = Sigma0(a) + Maj(a, b, c);
95 h = g;
96 g = f;
97 f = e;
98 e = d + T1;
99 d = c;
100 c = b;
101 b = a;
102 a = T1 + T2;
103 j++;
104 } while (j < 16);
105 do {
106 s0 = w256[(j+1) & 0x0f];
107 s0 = sigma0(s0);
108 s1 = w256[(j+14) & 0x0f];
109 s1 = sigma1(s1);
110 T1 = h + Sigma1(e) + Ch(e, f, g) + K256[j] + (w256[j & 0x0f] += s1 + w256[(j + 9) & 0x0f] + s0);
111 T2 = Sigma0(a) + Maj(a, b, c);
112 h = g;
113 g = f;
114 f = e;
115 e = d + T1;
116 d = c;
117 c = b;
118 b = a;
119 a = T1 + T2;
120 j++;
121 } while (j < 64);
122 ctx->state[0] += a;
123 ctx->state[1] += b;
124 ctx->state[2] += c;
125 ctx->state[3] += d;
126 ctx->state[4] += e;
127 ctx->state[5] += f;
128 ctx->state[6] += g;
129 ctx->state[7] += h;
132 void sha_update (sha_t *ctx, const uint8_t *data, size_t len) {
133 size_t f, u;
134 if (0 == len) return;
135 if ((u = (ctx->bitcount >> 3) % SHA_BLOCK_LEN) > 0) {
136 f = SHA_BLOCK_LEN - u;
137 if (len >= f) {
138 memcpy(&ctx->buf[u], data, f);
139 ctx->bitcount += f << 3;
140 len -= f;
141 data += f;
142 sha_transform(ctx, ctx->buf);
143 } else {
144 memcpy(&ctx->buf[u], data, len);
145 ctx->bitcount += len << 3;
146 return;
149 while (len >= SHA_BLOCK_LEN) {
150 sha_transform(ctx, data);
151 ctx->bitcount += SHA_BLOCK_LEN << 3;
152 len -= SHA_BLOCK_LEN;
153 data += SHA_BLOCK_LEN;
155 if (len > 0) {
156 memcpy(ctx->buf, data, len);
157 ctx->bitcount += len << 3;
161 static void sha_last (sha_t *ctx) {
162 uint32_t u = (ctx->bitcount >> 3) % SHA_BLOCK_LEN;
163 #if BYTE_ORDER == LITTLE_ENDIAN
164 REVERSE64(ctx->bitcount, ctx->bitcount);
165 #endif
166 if (u > 0) {
167 ctx->buf[u++] = 0x80;
168 if (u <= SHA_SHORT_BLOCK_LEN)
169 memset(&ctx->buf[u], 0, SHA_SHORT_BLOCK_LEN - u);
170 else {
171 if (u < SHA_BLOCK_LEN)
172 memset(&ctx->buf[u], 0, SHA_BLOCK_LEN - u);
173 sha_transform(ctx, ctx->buf);
174 memset(ctx->buf, 0, SHA_SHORT_BLOCK_LEN);
176 } else {
177 memset(ctx->buf, 0, SHA_SHORT_BLOCK_LEN);
178 *ctx->buf = 0x80;
180 *(uint64_t*)&ctx->buf[SHA_SHORT_BLOCK_LEN] = ctx->bitcount;
181 sha_transform(ctx, ctx->buf);
184 void sha_final (sha_t *ctx, uint8_t *digest) {
185 if (digest) {
186 sha_last(ctx);
187 #if BYTE_ORDER == LITTLE_ENDIAN
188 for (int j = 0; j < 8; ++j)
189 REVERSE32(ctx->state[j], ctx->state[j]);
190 #endif
191 memcpy(digest, ctx->state, SHA_DIGEST_LEN);
193 memset(ctx, 0, sizeof(sha_t));
196 void hmac_init (hmac_t *ctx, uint8_t *key, size_t len) {
197 uint8_t sbuf [SHA_DIGEST_LEN];
198 memset(ctx->opad, HMAC_OPAD, SHA_BLOCK_LEN);
199 memset(ctx->ipad, HMAC_IPAD, SHA_BLOCK_LEN);
200 if (len > SHA_BLOCK_LEN) {
201 memset(sbuf, 0, sizeof sbuf);
202 sha_init(&ctx->hash);
203 sha_update(&ctx->hash, key, len);
204 sha_final(&ctx->hash, sbuf);
205 key = sbuf;
206 len = SHA_DIGEST_LEN;
208 for (int i = 0; i < len; ++i) {
209 ctx->ipad[i] ^= key[i];
210 ctx->opad[i] ^= key[i];
212 sha_init(&ctx->hash);
213 sha_update(&ctx->hash, ctx->ipad, SHA_BLOCK_LEN);
216 void hmac_update (hmac_t *ctx, const uint8_t *data, size_t len) {
217 sha_update(&ctx->hash, data, len);
220 void hmac_final (hmac_t *ctx, uint8_t *dst, size_t len) {
221 uint8_t *x = calloc(SHA_DIGEST_LEN, sizeof(uint8_t));
222 sha_final(&ctx->hash, x);
223 sha_init(&ctx->hash);
224 sha_update(&ctx->hash, ctx->opad, SHA_BLOCK_LEN);
225 sha_update(&ctx->hash, x, SHA_DIGEST_LEN);
226 sha_final(&ctx->hash, dst);
227 free(x);