summaryrefslogtreecommitdiff
path: root/test/c/sha1.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/c/sha1.c')
-rw-r--r--test/c/sha1.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/test/c/sha1.c b/test/c/sha1.c
new file mode 100644
index 0000000..024e8ad
--- /dev/null
+++ b/test/c/sha1.c
@@ -0,0 +1,171 @@
+/* SHA-1 cryptographic hash function */
+/* Ref: Handbook of Applied Cryptography, section 9.4.2, algorithm 9.53 */
+
+#include <string.h>
+
+extern void memcpy_static(void *, void *, int),
+ memset_static(void *, int, char);
+
+#define memcpy memcpy_static
+#define memset memset_static
+
+#define ARCH_BIG_ENDIAN
+
+typedef unsigned int u32;
+
+struct SHA1Context {
+ u32 state[5];
+ u32 length[2];
+ int numbytes;
+ unsigned char buffer[64];
+};
+
+#define rol1(x) (((x) << 1) | ((x) >> 31))
+#define rol5(x) (((x) << 5) | ((x) >> 27))
+#define rol30(x) (((x) << 30) | ((x) >> 2))
+
+static void SHA1_copy_and_swap(void * src, void * dst, int numwords)
+{
+#ifdef ARCH_BIG_ENDIAN
+ memcpy(dst, src, numwords * sizeof(u32));
+#else
+ unsigned char * s, * d;
+ unsigned char a, b;
+ for (s = src, d = dst; numwords > 0; s += 4, d += 4, numwords--) {
+ a = s[0];
+ b = s[1];
+ d[0] = s[3];
+ d[1] = s[2];
+ d[2] = b;
+ d[3] = a;
+ }
+#endif
+}
+
+#define F(x,y,z) ( z ^ (x & (y ^ z) ) )
+#define G(x,y,z) ( (x & y) | (z & (x | y) ) )
+#define H(x,y,z) ( x ^ y ^ z )
+
+#define Y1 0x5A827999U
+#define Y2 0x6ED9EBA1U
+#define Y3 0x8F1BBCDCU
+#define Y4 0xCA62C1D6U
+
+static void SHA1_transform(struct SHA1Context * ctx)
+{
+ int i;
+ register u32 a, b, c, d, e, t;
+ u32 data[80];
+
+ /* Convert buffer data to 16 big-endian integers */
+ SHA1_copy_and_swap(ctx->buffer, data, 16);
+
+ /* Expand into 80 integers */
+ for (i = 16; i < 80; i++) {
+ t = data[i-3] ^ data[i-8] ^ data[i-14] ^ data[i-16];
+ data[i] = rol1(t);
+ }
+
+ /* Initialize working variables */
+ a = ctx->state[0];
+ b = ctx->state[1];
+ c = ctx->state[2];
+ d = ctx->state[3];
+ e = ctx->state[4];
+
+ /* Perform rounds */
+ for (i = 0; i < 20; i++) {
+ t = F(b, c, d) + Y1 + rol5(a) + e + data[i];
+ e = d; d = c; c = rol30(b); b = a; a = t;
+ }
+ for (/*nothing*/; i < 40; i++) {
+ t = H(b, c, d) + Y2 + rol5(a) + e + data[i];
+ e = d; d = c; c = rol30(b); b = a; a = t;
+ }
+ for (/*nothing*/; i < 60; i++) {
+ t = G(b, c, d) + Y3 + rol5(a) + e + data[i];
+ e = d; d = c; c = rol30(b); b = a; a = t;
+ }
+ for (/*nothing*/; i < 80; i++) {
+ t = H(b, c, d) + Y4 + rol5(a) + e + data[i];
+ e = d; d = c; c = rol30(b); b = a; a = t;
+ }
+
+ /* Update chaining values */
+ ctx->state[0] += a;
+ ctx->state[1] += b;
+ ctx->state[2] += c;
+ ctx->state[3] += d;
+ ctx->state[4] += e;
+}
+
+void SHA1_init(struct SHA1Context * ctx)
+{
+ ctx->state[0] = 0x67452301U;
+ ctx->state[1] = 0xEFCDAB89U;
+ ctx->state[2] = 0x98BADCFEU;
+ ctx->state[3] = 0x10325476U;
+ ctx->state[4] = 0xC3D2E1F0U;
+ ctx->numbytes = 0;
+ ctx->length[0] = 0;
+ ctx->length[1] = 0;
+}
+
+void SHA1_add_data(struct SHA1Context * ctx, unsigned char * data,
+ unsigned long len)
+{
+ u32 t;
+
+ /* Update length */
+ t = ctx->length[1];
+ if ((ctx->length[1] = t + (u32) (len << 3)) < t)
+ ctx->length[0]++; /* carry from low 32 bits to high 32 bits */
+ ctx->length[0] += (u32) (len >> 29);
+
+ /* If data was left in buffer, pad it with fresh data and munge block */
+ if (ctx->numbytes != 0) {
+ t = 64 - ctx->numbytes;
+ if (len < t) {
+ memcpy(ctx->buffer + ctx->numbytes, data, len);
+ ctx->numbytes += len;
+ return;
+ }
+ memcpy(ctx->buffer + ctx->numbytes, data, t);
+ SHA1_transform(ctx);
+ data += t;
+ len -= t;
+ }
+ /* Munge data in 64-byte chunks */
+ while (len >= 64) {
+ memcpy(ctx->buffer, data, 64);
+ SHA1_transform(ctx);
+ data += 64;
+ len -= 64;
+ }
+ /* Save remaining data */
+ memcpy(ctx->buffer, data, len);
+ ctx->numbytes = len;
+}
+
+void SHA1_finish(struct SHA1Context * ctx, unsigned char output[20])
+{
+ int i = ctx->numbytes;
+
+ /* Set first char of padding to 0x80. There is always room. */
+ ctx->buffer[i++] = 0x80;
+ /* If we do not have room for the length (8 bytes), pad to 64 bytes
+ with zeroes and munge the data block */
+ if (i > 56) {
+ memset(ctx->buffer + i, 0, 64 - i);
+ SHA1_transform(ctx);
+ i = 0;
+ }
+ /* Pad to byte 56 with zeroes */
+ memset(ctx->buffer + i, 0, 56 - i);
+ /* Add length in big-endian */
+ SHA1_copy_and_swap(ctx->length, ctx->buffer + 56, 2);
+ /* Munge the final block */
+ SHA1_transform(ctx);
+ /* Final hash value is in ctx->state modulo big-endian conversion */
+ SHA1_copy_and_swap(ctx->state, output, 5);
+}