totp

Simple cli tool for storing TOTP secrets and generating tokens
git clone https://git.inz.fi/totp/
Log | Files | Refs | Submodules

sha1.c (3260B)


      1 #include <stdint.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 #include <assert.h>
      5 
      6 #include <arpa/inet.h>
      7 
      8 #include "sha1.h"
      9 #include "util.h"
     10 
     11 static inline uint32_t _sha1_rotl32(uint32_t x, uint8_t n)
     12 {
     13 	return x << n | x >> (32 - n);
     14 }
     15 
     16 static inline void _sha1_add5(uint32_t *dest, const uint32_t *src)
     17 {
     18 	size_t i;
     19 
     20 	for (i = 0; i < 5; i++)
     21 		dest[i] += src[i];
     22 }
     23 
     24 static inline void _sha1_rotmod5(uint32_t *a, uint32_t f, uint32_t k, uint32_t w)
     25 {
     26 	uint32_t t = _sha1_rotl32(a[0], 5) + f + a[4] + k + w;
     27 	memmove(a + 1, a, 4 * sizeof(*a));
     28 	a[2] = _sha1_rotl32(a[2], 30);
     29 	a[0] = t;
     30 }
     31 
     32 static inline uint32_t _sha1_getnw(uint32_t *w, size_t i)
     33 {
     34 	return w[i & 15] = _sha1_rotl32(w[(i + 13) & 15] ^ w[(i + 8) & 15] ^ w[(i + 2) & 15] ^ w[i & 15], 1);
     35 }
     36 
     37 void sha1_init(struct sha1 *s)
     38 {
     39 	memcpy(s->h, (uint32_t[]){ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 }, 5 * sizeof(*s->h));
     40 	s->len = 0;
     41 }
     42 
     43 static inline void _sha1_update(uint32_t *h, const void *data)
     44 {
     45 	const uint32_t k[4] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 }; 
     46 	const uint32_t *d = data;
     47 
     48 	uint32_t w[16];
     49 	size_t i;
     50 
     51 	uint32_t wr[5];
     52 	memcpy(wr, h, sizeof(wr));
     53 
     54 	for (i = 0; i < 16; i++)
     55 		_sha1_rotmod5(wr, (wr[1] & wr[2]) | (~wr[1] & wr[3]), k[0], w[i] = ntohl(d[i]));
     56 	for (; i < 20; i++)
     57 		_sha1_rotmod5(wr, (wr[1] & wr[2]) | (~wr[1] & wr[3]), k[0], _sha1_getnw(w, i));
     58 	for (; i < 40; i++)
     59 		_sha1_rotmod5(wr, wr[1] ^ wr[2] ^ wr[3], k[1], _sha1_getnw(w, i));
     60 	for (; i < 60; i++)
     61 		_sha1_rotmod5(wr, (wr[1] & wr[2]) | (wr[1] & wr[3]) | (wr[2] & wr[3]), k[2], _sha1_getnw(w, i));
     62 	for (; i < 80; i++)
     63 		_sha1_rotmod5(wr, wr[1] ^ wr[2] ^ wr[3], k[3], _sha1_getnw(w, i));
     64 
     65 	_sha1_add5(h, wr);
     66 }
     67 
     68 void sha1_update(struct sha1 *s, const void *data, size_t len)
     69 {
     70 	uint8_t *bw = s->buffer + (s->len & (sizeof(s->buffer) - 1));
     71 	uint8_t *bend = 1[&s->buffer];
     72 
     73 	if (data == bw) {
     74 		if (bw + len == bend)
     75 			_sha1_update(s->h, s->buffer);
     76 	} else if (bw + len > bend) {
     77 		const uint8_t *d = data;
     78 		const uint8_t *dend = d + len;
     79 
     80 		if (bw != s->buffer) {
     81 			memcpy(bw, d, bend - bw);
     82 			_sha1_update(s->h, s->buffer);
     83 			d += bend - bw;
     84 		}
     85 
     86 		while ((size_t)(dend - d) > sizeof(s->buffer)) {
     87 			_sha1_update(s->h, d);
     88 			d += sizeof(s->buffer);
     89 		}
     90 
     91 		memcpy(s->buffer, d, dend - d);
     92 	} else {
     93 		memcpy(bw, data, len);
     94 	}
     95 	s->len += len;
     96 }
     97 
     98 void sha1_finish(struct sha1 *s)
     99 {
    100 	size_t i;
    101 	uint8_t *bw = s->buffer + (s->len & (sizeof(s->buffer) - 1));
    102 	uint8_t *bend = 1[&s->buffer];
    103 
    104 	*bw++ = 0x80;
    105 	memset(bw, 0, bend - bw);
    106 
    107 	if (bw + sizeof(uint64_t) >= bend) {
    108 		_sha1_update(s->h, s->buffer);
    109 		memset(s->buffer, 0, bw - s->buffer);
    110 	}
    111 
    112 	writebeu64(bend - sizeof(uint64_t), s->len << 3);
    113 	_sha1_update(s->h, s->buffer);
    114 
    115 	for (i = 0; i < sizeof(s->h) / sizeof(*s->h); i++)
    116 		writebeu32(&s->h[i], s->h[i]);
    117 }
    118 
    119 void sha1_hmac(const void *key, size_t keylen,
    120 	       const void *data, size_t datalen,
    121 	       void *h)
    122 {
    123 	hmac(key, keylen,
    124 	     data, datalen,
    125 	     (digest_init)sha1_init,
    126 	     (digest_update)sha1_update,
    127 	     (digest_finish)sha1_finish,
    128 	     sizeof(struct sha1),
    129 	     sizeof(((struct sha1 *)0)->buffer),
    130 	     sizeof(((struct sha1 *)0)->h),
    131 	     (ptrdiff_t)&((struct sha1 *)0)->buffer,
    132 	     (ptrdiff_t)&((struct sha1 *)0)->h,
    133 	     h);
    134 }