#include #include #include #include #include #include #define WSTR(s) (s),sizeof(s)-1 #define HEX_BYTES 129 extern char *__progname; #include #include #define ALIGN(x) __attribute__((__aligned__(x))) enum blake2b_constant { BLAKE2B_BLOCKBYTES = 128, BLAKE2B_OUTBYTES = 64, BLAKE2B_KEYBYTES = 64, BLAKE2B_SALTBYTES = 16, BLAKE2B_PERSONALBYTES = 16 }; typedef struct __blake2b_param { uint8_t digest_length; uint8_t key_length; uint8_t fanout; uint8_t depth; uint32_t leaf_length; uint64_t node_offset; uint8_t reserved[14]; uint8_t salt[BLAKE2B_SALTBYTES]; uint8_t personal[BLAKE2B_PERSONALBYTES]; } blake2b_param; ALIGN(64) typedef struct __blake2b_state { uint64_t h[8]; uint64_t t[2]; uint64_t f[2]; uint8_t buf[2 * BLAKE2B_BLOCKBYTES]; size_t buflen; uint8_t last_node; } blake2b_state; static inline uint64_t load64(const void *src) { #if defined(NATIVE_LITTLE_ENDIAN) return *(uint64_t *) (src); #else const uint8_t *p = (uint8_t *) src; uint64_t w = *p++; w |= (uint64_t) (*p++) << 8; w |= (uint64_t) (*p++) << 16; w |= (uint64_t) (*p++) << 24; w |= (uint64_t) (*p++) << 32; w |= (uint64_t) (*p++) << 40; w |= (uint64_t) (*p++) << 48; w |= (uint64_t) (*p++) << 56; return w; #endif } static inline void store32(void *dst, uint32_t w) { #if defined(NATIVE_LITTLE_ENDIAN) *(uint32_t *)(dst) = w; #else uint8_t *p = (uint8_t *) dst; *p++ = (uint8_t) w; w >>= 8; *p++ = (uint8_t) w; w >>= 8; *p++ = (uint8_t) w; w >>= 8; *p++ = (uint8_t) w; #endif } static inline void store64(void *dst, uint64_t w) { #if defined(NATIVE_LITTLE_ENDIAN) *(uint64_t *)(dst) = w; #else uint8_t *p = (uint8_t *) dst; *p++ = (uint8_t) w; w >>= 8; *p++ = (uint8_t) w; w >>= 8; *p++ = (uint8_t) w; w >>= 8; *p++ = (uint8_t) w; w >>= 8; *p++ = (uint8_t) w; w >>= 8; *p++ = (uint8_t) w; w >>= 8; *p++ = (uint8_t) w; w >>= 8; *p++ = (uint8_t) w; #endif } static inline uint64_t rotr64(const uint64_t w, const unsigned c) { return (w >> c) | (w << (64 - c)); } static const uint64_t blake2b_IV[8] = { 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL }; static const uint8_t blake2b_sigma[12][16] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15}, {14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3}, {11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4}, { 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8}, { 9, 0, 5, 7, 2, 4,10,15,14, 1,11,12, 6, 8, 3,13}, { 2,12, 6,10, 0,11, 8, 3, 4,13, 7, 5,15,14, 1, 9}, {12, 5, 1,15,14,13, 4,10, 0, 7, 6, 3, 9, 2, 8,11}, {13,11, 7,14,12, 1, 3, 9, 5, 0,15, 4, 8, 6, 2,10}, { 6,15,14, 9,11, 3, 0, 8,12, 2,13, 7, 1, 4,10, 5}, {10, 2, 8, 4, 7, 6, 1, 5,15,11, 9,14, 3,12,13, 0}, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15}, {14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3} }; static inline int blake2b_set_lastnode(blake2b_state *S) { S->f[1] = ~0ULL; return 0; } /* Some helper functions, not necessarily useful */ static inline int blake2b_set_lastblock(blake2b_state *S) { if (S->last_node) blake2b_set_lastnode(S); S->f[0] = ~0ULL; return 0; } static inline int blake2b_increment_counter(blake2b_state *S, const uint64_t inc) { S->t[0] += inc; S->t[1] += (S->t[0] < inc); return 0; } static inline int blake2b_init0(blake2b_state *S) { int i; memset(S, 0, sizeof(blake2b_state)); for(i = 0; i < 8; ++i) S->h[i] = blake2b_IV[i]; return 0; } /* init xors IV with input parameter block */ int blake2b_init_param(blake2b_state *S, const blake2b_param *P) { int i; blake2b_init0(S); const uint8_t *p = (const uint8_t *)(P); /* IV XOR ParamBlock */ for (i = 0; i < 8; ++i) S->h[i] ^= load64(p + sizeof(S->h[i]) * i); return 0; } int blake2b_init(blake2b_state *S, const uint8_t outlen) { blake2b_param P[1]; if ((!outlen) || (outlen > BLAKE2B_OUTBYTES)) return -1; P->digest_length = outlen; // P->key_length = 0; P->fanout = 1; P->depth = 1; store32(&P->leaf_length, 0); store64(&P->node_offset, 0); memset(P->reserved, 0, sizeof(P->reserved)); memset(P->salt, 0, sizeof(P->salt)); memset(P->personal, 0, sizeof(P->personal)); return blake2b_init_param(S, P); } static int blake2b_compress(blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES]) { uint64_t m[16]; uint64_t v[16]; int i; for (i = 0; i < 16; ++i) m[i] = load64(block + i * sizeof(m[i])); for(i = 0; i < 8; ++i) v[i] = S->h[i]; v[ 8] = blake2b_IV[0]; v[ 9] = blake2b_IV[1]; v[10] = blake2b_IV[2]; v[11] = blake2b_IV[3]; v[12] = S->t[0] ^ blake2b_IV[4]; v[13] = S->t[1] ^ blake2b_IV[5]; v[14] = S->f[0] ^ blake2b_IV[6]; v[15] = S->f[1] ^ blake2b_IV[7]; #define G(r,i,a,b,c,d) \ do { \ a = a + b + m[blake2b_sigma[r][2*i+0]]; \ d = rotr64(d ^ a, 32); \ c = c + d; \ b = rotr64(b ^ c, 24); \ a = a + b + m[blake2b_sigma[r][2*i+1]]; \ d = rotr64(d ^ a, 16); \ c = c + d; \ b = rotr64(b ^ c, 63); \ } while(0) #define ROUND(r) \ do { \ G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ G(r,2,v[ 2],v[ 6],v[10],v[14]); \ G(r,3,v[ 3],v[ 7],v[11],v[15]); \ G(r,4,v[ 0],v[ 5],v[10],v[15]); \ G(r,5,v[ 1],v[ 6],v[11],v[12]); \ G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ } while(0) ROUND(0); ROUND(1); ROUND(2); ROUND(3); ROUND(4); ROUND(5); ROUND(6); ROUND(7); ROUND(8); ROUND(9); ROUND(10); ROUND(11); for (i = 0; i < 8; ++i) S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; #undef G #undef ROUND return 0; } /* inlen now in bytes */ int blake2b_update(blake2b_state *S, const uint8_t *in, uint64_t inlen) { while (inlen > 0) { size_t left = S->buflen; size_t fill = 2 * BLAKE2B_BLOCKBYTES - left; if (inlen > fill) { memcpy(S->buf + left, in, fill); /* Fill buffer */ S->buflen += fill; blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); blake2b_compress(S, S->buf); /* Compress */ memcpy(S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES); S->buflen -= BLAKE2B_BLOCKBYTES; in += fill; inlen -= fill; } else { /* inlen <= fill */ memcpy(S->buf + left, in, inlen); S->buflen += inlen; in += inlen; inlen -= inlen; } } return 0; } int blake2b_final(blake2b_state *S, unsigned char *out, unsigned char outlen) { int i; unsigned char buffer[BLAKE2B_OUTBYTES]; if (S->buflen > BLAKE2B_BLOCKBYTES) { blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); blake2b_compress(S, S->buf); S->buflen -= BLAKE2B_BLOCKBYTES; memcpy(S->buf, S->buf + BLAKE2B_BLOCKBYTES, S->buflen); } blake2b_increment_counter(S, S->buflen); blake2b_set_lastblock(S); memset(S->buf + S->buflen, 0, 2 * BLAKE2B_BLOCKBYTES - S->buflen); blake2b_compress(S, S->buf); for (i = 0; i < 8; ++i) store64(buffer + sizeof(S->h[i]) * i, S->h[i]); memcpy( out, buffer, outlen ); return 0; } static int blake2b_stream(FILE *stream, void *resstream, unsigned int outlen) { int ret = -1; size_t sum, n; blake2b_state S[1]; static const size_t buffer_length = 32768; uint8_t buffer[32768]; blake2b_init(S, outlen); for (;;) { sum = 0; for (;;) { n = fread(buffer + sum, 1, buffer_length - sum, stream); sum += n; if (buffer_length == sum) break; if (0 == n) { if (ferror(stream)) goto cleanup_buffer; goto final_process; } if (feof(stream)) goto final_process; } blake2b_update(S, buffer, buffer_length); } final_process:; if (sum > 0) blake2b_update(S, buffer, sum); blake2b_final(S, resstream, outlen); ret = 0; cleanup_buffer: return ret; } static int blake2b_file(const char *path, unsigned char hash[BLAKE2B_OUTBYTES]) { FILE *f; if((f = fopen(path, "rb")) == NULL) { write(2, WSTR("Could not open '")); write(2, path, strlen(path)); write(2, WSTR("': ")); write(2, strerror(errno), strlen(strerror(errno))); write(2, WSTR("\n")); exit(1); } if (blake2b_stream(f, hash, BLAKE2B_OUTBYTES) < 0) { write(2, WSTR("Failed to hash '")); write(2, path, strlen(path)); write(2, WSTR("\n")); exit(1); } fclose(f); return 0; } char * bin2hex(char * const h, const size_t hl, const unsigned char *b, const size_t bl) { static const char x[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; size_t i = (size_t) 0U; size_t j = (size_t) 0U; if (bl >= SIZE_MAX / 2 || hl < bl * 2U) abort(); while (i < bl) { h[j++] = x[b[i] >> 4]; h[j++] = x[b[i] & 0xf]; i++; } h[j] = 0; return h; } static int blake2b_check(char *filename) { size_t n; FILE *f; int nb_err1, nb_err2; int nb_tot1, nb_tot2; unsigned char sum[BLAKE2B_OUTBYTES]; char buf[129]; /* b2 hex sum string */ char line[1024]; if((f = fopen(filename, "rb" )) == NULL) { write(2, WSTR("failed to open: ")); write(2, filename, strlen(filename)); write(2, WSTR("\n")); return 1; } nb_err1 = 0; nb_err2 = 0; nb_tot1 = 0; nb_tot2 = 0; memset(line, 0, sizeof(line)); n = sizeof(line); while(fgets(line, (int)n - 1, f) != NULL) { n = strlen(line); if(n < 132) continue; if(line[128] != ' '|| line[129] != ' ') continue; if(line[n - 1] == '\n') { n--; line[n] = '\0'; } if(line[n - 1] == '\r') { n--; line[n] = '\0'; } nb_tot1++; if(blake2b_file(line + 130, sum ) != 0) { nb_err1++; continue; } nb_tot2++; // bin2hex(buf, 129, sum, BLAKE2B_OUTBYTES); bin2hex(buf, HEX_BYTES, sum, BLAKE2B_OUTBYTES); // if(memcmp(line, buf, 128) != 0 ) { if(memcmp(line, buf, HEX_BYTES - 1) != 0 ) { nb_err2++; write(2, WSTR("wrong checksum: ")); // fprintf( stderr, "wrong checksum: %s\n", line + 128 ); } n = sizeof( line ); } /* if( nb_err1 != 0 ) { printf( "WARNING: %d (out of %d) input files could " "not be read\n", nb_err1, nb_tot1 ); } if( nb_err2 != 0 ) { printf( "WARNING: %d (out of %d) computed checksums did " "not match\n", nb_err2, nb_tot2 ); } */ return (nb_err1 != 0 || nb_err2 != 0); } int main(int argc, char **argv) { unsigned char hash[BLAKE2B_OUTBYTES] = {0}; char hex[HEX_BYTES]; int i; opterr = 1; if(argc == 1) { write(1, WSTR("usage: b2sum [-c] file\n")); exit(111); } if (strcmp("-c", argv[1]) != 0) for (i = optind; i < argc; ++i) { blake2b_file(argv[i], hash); bin2hex(hex, HEX_BYTES, hash, BLAKE2B_OUTBYTES); write(1, hex, strlen(hex)); write(1, WSTR(" ")); write(1, argv[i], strlen(argv[i])); write(1, WSTR("\n")); } else if (argc == 3) blake2b_check(argv[2]); return 0; }