ObjFW  Artifact [8ad65dbc27]

Artifact 8ad65dbc273e65ffa6329c771b91b4f4b96aea2cf7dc57a57cb5304f61f9c277:

  • File src/OFSHA1Hash.m — part of check-in [13ee56edf3] at 2014-06-21 21:43:43 on branch trunk — Move all macros from OFObject.h to macros.h

    This means that OFObject.h imports macros.h now, making it unnecessary
    to manually import macros.h in almost every file. And while at it, also
    import autorelease.h in OFObject.h, so that this doesn't need to be
    manually imported in almost every file as well. (user: js, size: 5408) [annotate] [blame] [check-ins using]


/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <string.h>

#import "OFSHA1Hash.h"

#import "OFHashAlreadyCalculatedException.h"

/* blk0() and blk() perform the initial expand. */
#ifndef OF_BIG_ENDIAN
#define blk0(i)							\
	(block.l[i] = (OF_ROL(block.l[i], 24) & 0xFF00FF00) |	\
	    (OF_ROL(block.l[i], 8) & 0x00FF00FF))
#else
#define blk0(i) block.l[i]
#endif
#define blk(i) \
	(block.l[i & 15] = OF_ROL(block.l[(i + 13) & 15] ^	\
	    block.l[(i + 8) & 15] ^ block.l[(i + 2) & 15] ^	\
	    block.l[i & 15], 1))

/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v, w, x, y, z, i)						\
	z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + OF_ROL(v, 5);	\
	w = OF_ROL(w, 30);
#define R1(v, w, x, y, z, i)						\
	z += ((w & (x ^ y)) ^ y) + blk(i) +  0x5A827999 + OF_ROL(v, 5);	\
	w = OF_ROL(w, 30);
#define R2(v, w, x, y, z, i)						\
	z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + OF_ROL(v, 5);		\
	w = OF_ROL(w, 30);
#define R3(v, w, x, y, z, i)						     \
	z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + OF_ROL(v, 5); \
	w = OF_ROL(w, 30);
#define R4(v, w, x, y, z, i)						\
	z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + OF_ROL(v, 5);		\
	w = OF_ROL(w, 30);

typedef union {
	char	 c[64];
	uint32_t l[16];
} sha1_c64l16_t;

static inline void
sha1_transform(uint32_t state[5], const char buffer[64])
{
	uint32_t      a, b, c, d, e;
	sha1_c64l16_t block;

	memcpy(block.c, buffer, 64);

	/* Copy state[] to working vars */
	a = state[0];
	b = state[1];
	c = state[2];
	d = state[3];
	e = state[4];

	/* 4 rounds of 20 operations each. Loop unrolled. */
	R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
	R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
	R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
	R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
	R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
	R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
	R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
	R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
	R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
	R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
	R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
	R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
	R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
	R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
	R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
	R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
	R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
	R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
	R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
	R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);

	/* Add the working vars back into state[] */
	state[0] += a;
	state[1] += b;
	state[2] += c;
	state[3] += d;
	state[4] += e;
}

static inline void
sha1_update(uint32_t *state, uint64_t *count, char *buffer,
    const char *buf, size_t length)
{
	size_t i, j;

	j = (size_t)((*count >> 3) & 63);
	*count += (length << 3);

	if ((j + length) > 63) {
		memcpy(&buffer[j], buf, (i = 64 - j));

		sha1_transform(state, buffer);

		for (; i + 63 < length; i += 64)
			sha1_transform(state, &buf[i]);

		j = 0;
	} else
		i = 0;

	memcpy(&buffer[j], &buf[i], length - i);
}

@implementation OFSHA1Hash
+ (size_t)digestSize
{
	return 20;
}

+ (size_t)blockSize
{
	return 64;
}

+ (instancetype)hash
{
	return [[[self alloc] init] autorelease];
}

- init
{
	self = [super init];

	_state[0] = 0x67452301;
	_state[1] = 0xEFCDAB89;
	_state[2] = 0x98BADCFE;
	_state[3] = 0x10325476;
	_state[4] = 0xC3D2E1F0;

	return self;
}

- (void)updateWithBuffer: (const void*)buffer
		  length: (size_t)length
{
	if (length == 0)
		return;

	if (_calculated)
		@throw [OFHashAlreadyCalculatedException
		    exceptionWithHash: self];

	sha1_update(_state, &_count, _buffer, buffer, length);
}

- (const uint8_t*)digest
{
	size_t i;
	char finalcount[8];

	if (_calculated)
		return _digest;

	for (i = 0; i < 8; i++)
		/* Endian independent */
		finalcount[i] = (char)((_count >> ((7 - (i & 7)) * 8)) & 255);
	sha1_update(_state, &_count, _buffer, "\200", 1);

	while ((_count & 504) != 448)
		sha1_update(_state, &_count, _buffer, "\0", 1);
	/* Should cause a sha1_transform() */
	sha1_update(_state, &_count, _buffer, finalcount, 8);

	for (i = 0; i < 20; i++)
		_digest[i] = (char)((_state[i >> 2] >>
		    ((3 - (i & 3)) * 8)) & 255);

	_calculated = true;

	return _digest;
}

- (bool)isCalculated
{
	return _calculated;
}
@end