Commit 385e578c authored by Geoff Simmons's avatar Geoff Simmons

add SHA1

parent c2a72457
......@@ -12,6 +12,8 @@ libvmod_blobdigest_la_SOURCES = \
byte_order.c \
md5.h \
md5.c \
sha1.h \
sha1.c \
sha256.h \
sha256.c \
sha512.h \
......
......@@ -5,6 +5,7 @@ use warnings;
my @vals = (qw(
MD5
SHA1
SHA224
SHA256
SHA384
......
/* sha1.c - an implementation of Secure Hash Algorithm 1 (SHA1)
* based on RFC 3174.
*
* Copyright: 2008-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
*/
#include <string.h>
#include "byte_order.h"
#include "sha1.h"
/**
* Initialize context before calculaing hash.
*
* @param ctx context to initialize
*/
void rhash_sha1_init(sha1_ctx *ctx)
{
ctx->length = 0;
/* initialize algorithm state */
ctx->hash[0] = 0x67452301;
ctx->hash[1] = 0xefcdab89;
ctx->hash[2] = 0x98badcfe;
ctx->hash[3] = 0x10325476;
ctx->hash[4] = 0xc3d2e1f0;
}
/**
* The core transformation. Process a 512-bit block.
* The function has been taken from RFC 3174 with little changes.
*
* @param hash algorithm state
* @param block the message block to process
*/
static void rhash_sha1_process_block(unsigned* hash, const unsigned* block)
{
int t; /* Loop counter */
uint32_t temp; /* Temporary word value */
uint32_t W[80]; /* Word sequence */
uint32_t A, B, C, D, E; /* Word buffers */
/* initialize the first 16 words in the array W */
for (t = 0; t < 16; t++) {
/* note: it is much faster to apply be2me here, then using be32_copy */
W[t] = be2me_32(block[t]);
}
/* initialize the rest */
for (t = 16; t < 80; t++) {
W[t] = ROTL32(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);
}
A = hash[0];
B = hash[1];
C = hash[2];
D = hash[3];
E = hash[4];
for (t = 0; t < 20; t++) {
/* the following is faster than ((B & C) | ((~B) & D)) */
temp = ROTL32(A, 5) + (((C ^ D) & B) ^ D)
+ E + W[t] + 0x5A827999;
E = D;
D = C;
C = ROTL32(B, 30);
B = A;
A = temp;
}
for (t = 20; t < 40; t++) {
temp = ROTL32(A, 5) + (B ^ C ^ D) + E + W[t] + 0x6ED9EBA1;
E = D;
D = C;
C = ROTL32(B, 30);
B = A;
A = temp;
}
for (t = 40; t < 60; t++) {
temp = ROTL32(A, 5) + ((B & C) | (B & D) | (C & D))
+ E + W[t] + 0x8F1BBCDC;
E = D;
D = C;
C = ROTL32(B, 30);
B = A;
A = temp;
}
for (t = 60; t < 80; t++) {
temp = ROTL32(A, 5) + (B ^ C ^ D) + E + W[t] + 0xCA62C1D6;
E = D;
D = C;
C = ROTL32(B, 30);
B = A;
A = temp;
}
hash[0] += A;
hash[1] += B;
hash[2] += C;
hash[3] += D;
hash[4] += E;
}
/**
* Calculate message hash.
* Can be called repeatedly with chunks of the message to be hashed.
*
* @param ctx the algorithm context containing current hashing state
* @param msg message chunk
* @param size length of the message chunk
*/
void rhash_sha1_update(sha1_ctx *ctx, const unsigned char* msg, size_t size)
{
unsigned index = (unsigned)ctx->length & 63;
ctx->length += size;
/* fill partial block */
if (index) {
unsigned left = sha1_block_size - index;
memcpy(ctx->message + index, msg, (size < left ? size : left));
if (size < left) return;
/* process partial block */
rhash_sha1_process_block(ctx->hash, (unsigned*)ctx->message);
msg += left;
size -= left;
}
while (size >= sha1_block_size) {
unsigned* aligned_message_block;
if (IS_ALIGNED_32(msg)) {
/* the most common case is processing of an already aligned message
without copying it */
aligned_message_block = (unsigned*)msg;
} else {
memcpy(ctx->message, msg, sha1_block_size);
aligned_message_block = (unsigned*)ctx->message;
}
rhash_sha1_process_block(ctx->hash, aligned_message_block);
msg += sha1_block_size;
size -= sha1_block_size;
}
if (size) {
/* save leftovers */
memcpy(ctx->message, msg, size);
}
}
/**
* Store calculated hash into the given array.
*
* @param ctx the algorithm context containing current hashing state
* @param result calculated hash in binary form
*/
void rhash_sha1_final(sha1_ctx *ctx, unsigned char* result)
{
unsigned index = (unsigned)ctx->length & 63;
unsigned* msg32 = (unsigned*)ctx->message;
/* pad message and run for last block */
ctx->message[index++] = 0x80;
while ((index & 3) != 0) {
ctx->message[index++] = 0;
}
index >>= 2;
/* if no room left in the message to store 64-bit message length */
if (index > 14) {
/* then fill the rest with zeros and process it */
while (index < 16) {
msg32[index++] = 0;
}
rhash_sha1_process_block(ctx->hash, msg32);
index = 0;
}
while (index < 14) {
msg32[index++] = 0;
}
msg32[14] = be2me_32( (unsigned)(ctx->length >> 29) );
msg32[15] = be2me_32( (unsigned)(ctx->length << 3) );
rhash_sha1_process_block(ctx->hash, msg32);
if (result) be32_copy(result, 0, &ctx->hash, sha1_hash_size);
}
/* sha1.h */
#ifndef SHA1_H
#define SHA1_H
#include <stdint.h>
#include <unistd.h>
#define sha1_block_size 64
#define sha1_hash_size 20
/* algorithm context */
typedef struct sha1_ctx
{
unsigned char message[sha1_block_size]; /* 512-bit buffer for leftovers */
uint64_t length; /* number of processed bytes */
unsigned hash[5]; /* 160-bit algorithm internal hashing state */
} sha1_ctx;
/* hash functions */
void rhash_sha1_init(sha1_ctx *ctx);
void rhash_sha1_update(sha1_ctx *ctx, const unsigned char* msg, size_t size);
void rhash_sha1_final(sha1_ctx *ctx, unsigned char* result);
#endif /* SHA1_H */
# looks like -*- vcl -*-
varnishtest "SHA1 hash"
# VMOD blobcode must be installed
varnish v1 -vcl {
import blobdigest from "${vmod_topbuild}/src/.libs/libvmod_blobdigest.so";
import blobcode;
backend b { .host = "${bad_ip}"; }
sub vcl_init {
# RFC2202 test cases
new k1 = blobcode.blob(HEX,
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
new rfc2202t1 = blobdigest.hmac(SHA1, k1.get());
new k2 = blobcode.blob(IDENTITY, "Jefe");
new rfc2202t2 = blobdigest.hmac(SHA1, k2.get());
new k3 = blobcode.blob(HEX,
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
new rfc2202t3 = blobdigest.hmac(SHA1, k3.get());
new k4 = blobcode.blob(HEX,
"0102030405060708090a0b0c0d0e0f10111213141516171819");
new rfc2202t4 = blobdigest.hmac(SHA1, k4.get());
new k5 = blobcode.blob(HEX,
"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c");
new rfc2202t5 = blobdigest.hmac(SHA1, k5.get());
new k6 = blobcode.blob(HEX,
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
new rfc2202t6 = blobdigest.hmac(SHA1, k6.get());
}
sub vcl_recv {
return(synth(200));
}
sub vcl_synth {
set resp.http.empty
= blobcode.encode(HEXUC, blobdigest.hash(SHA1,
blobcode.decode(IDENTITY, "")));
set resp.http.emptyb64
= blobcode.encode(BASE64, blobdigest.hash(SHA1,
blobcode.decode(IDENTITY, "")));
set resp.http.a
= blobcode.encode(HEXUC, blobdigest.hash(SHA1,
blobcode.decode(IDENTITY, "a")));
set resp.http.abc
= blobcode.encode(HEXUC, blobdigest.hash(SHA1,
blobcode.decode(IDENTITY, "abc")));
set resp.http.msgdigest
= blobcode.encode(HEXUC, blobdigest.hash(SHA1,
blobcode.decode(IDENTITY,
"message digest")));
set resp.http.alphasoup
= blobcode.encode(HEXUC, blobdigest.hash(SHA1,
blobcode.decode(IDENTITY,
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
set resp.http.alphanum
= blobcode.encode(HEXUC, blobdigest.hash(SHA1,
blobcode.decode(IDENTITY,
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")));
set resp.http.digits
= blobcode.encode(HEXUC, blobdigest.hash(SHA1,
blobcode.decode(IDENTITY,
"12345678901234567890123456789012345678901234567890123456789012345678901234567890")));
set resp.http.pangram
= blobcode.encode(HEXUC, blobdigest.hash(SHA1,
blobcode.decode(IDENTITY,
"The quick brown fox jumps over the lazy dog")));
set resp.http.pangramcog
= blobcode.encode(HEXLC, blobdigest.hash(SHA1,
blobcode.decode(IDENTITY,
"The quick brown fox jumps over the lazy cog")));
set resp.http.pangramb64
= blobcode.encode(BASE64, blobdigest.hash(SHA1,
blobcode.decode(IDENTITY,
"The quick brown fox jumps over the lazy dog")));
set resp.http.pangramcogb64
= blobcode.encode(BASE64, blobdigest.hash(SHA1,
blobcode.decode(IDENTITY,
"The quick brown fox jumps over the lazy cog")));
# all 256 byte values in ascending, big-endian order
set resp.http.allbytes
= blobcode.encode(HEXLC, blobdigest.hash(SHA1,
blobcode.decode(BASE64,
"AQACAQMCBAMFBAYFBwYIBwkICgkLCgwLDQwODQ8OEA8REBIRExIUExUUFhUXFhgXGRgaGRsaHBsdHB4dHx4gHyEgIiEjIiQjJSQmJScmKCcpKCopKyosKy0sLi0vLjAvMTAyMTMyNDM1NDY1NzY4Nzk4Ojk7Ojw7PTw+PT8+QD9BQEJBQ0JEQ0VERkVHRkhHSUhKSUtKTEtNTE5NT05QT1FQUlFTUlRTVVRWVVdWWFdZWFpZW1pcW11cXl1fXmBfYWBiYWNiZGNlZGZlZ2ZoZ2loamlramxrbWxubW9ucG9xcHJxc3J0c3V0dnV3dnh3eXh6eXt6fHt9fH59f36Afw==")));
set resp.http.rfc2202t1 = blobcode.encode(HEXLC,
rfc2202t1.hmac(blobcode.decode(IDENTITY, "Hi There")));
set resp.http.rfc2202t2
= blobcode.encode(HEXLC,
rfc2202t2.hmac(blobcode.decode(IDENTITY,
"what do ya want for nothing?")));
set resp.http.rfc2202t3
= blobcode.encode(HEXLC,
rfc2202t3.hmac(blobcode.decode(HEX,
"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd")));
set resp.http.rfc2202t4
= blobcode.encode(HEXLC,
rfc2202t4.hmac(blobcode.decode(HEX,
"cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd")));
set resp.http.rfc2202t5
= blobcode.encode(HEXLC,
rfc2202t5.hmac(blobcode.decode(IDENTITY,
"Test With Truncation")));
set resp.http.rfc2202t6
= blobcode.encode(HEXLC,
rfc2202t6.hmac(blobcode.decode(IDENTITY,
"Test Using Larger Than Block-Size Key - Hash Key First")));
/*
* Test case 7 uses the same key as 6, so we'll re-use
* object rfc2202t6. This tests repeated use of the same
* internal hash contexts.
*/
set resp.http.rfc2202t7
= blobcode.encode(HEXLC,
rfc2202t6.hmac(blobcode.decode(IDENTITY,
"Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data")));
}
} -start
client c1 {
txreq
rxresp
expect resp.status == 200
# from librhash
expect resp.http.empty == "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"
expect resp.http.a == "86F7E437FAA5A7FCE15D1DDCB9EAEAEA377667B8"
expect resp.http.abc == "A9993E364706816ABA3E25717850C26C9CD0D89D"
expect resp.http.msgdigest == "C12252CEDA8BE8994D5FA0290A47231C1D16AAE3"
expect resp.http.pangram == "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12"
expect resp.http.alphanum == "761C457BF73B14D27E9E9265C46F4B4DDA11F940"
expect resp.http.digits == "50ABF5706A150990A08B2C5EA40FA0E585554732"
# from Wikipedia
expect resp.http.emptyb64 == "2jmj7l5rSw0yVb/vlWAYkK/YBwk="
expect resp.http.pangramcog == "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"
expect resp.http.pangramb64 == "L9ThxnotKPzthJ7hu3bnORuT6xI="
expect resp.http.pangramcogb64 == "3p8sf9JeGzr60+haC9F9mxANtLM="
# verified with: base64 -d | sha1sum
expect resp.http.allbytes == "f70d8ebbcd1f4873eb8ceba93879e8ff60b4e4b3"
# RFC2202 test cases
expect resp.http.rfc2202t1 == "b617318655057264e28bc0b6fb378c8ef146be00"
expect resp.http.rfc2202t2 == "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"
expect resp.http.rfc2202t3 == "125d7342b9ac11cd91a39af48aa17b4f63f175d3"
expect resp.http.rfc2202t4 == "4c9007f4026250c6bc8414f9bf50c86c2d7235da"
expect resp.http.rfc2202t5 == "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"
expect resp.http.rfc2202t6 == "aa4ae5e15272d00e95705637ce8a3b55ed402112"
expect resp.http.rfc2202t7 == "e8e99d0f45237d786d6bbaa7965c7808bbff1a91"
} -run
......@@ -84,6 +84,9 @@ init(const enum algorithm hash, hash_ctx * const hctx)
case MD5:
rhash_md5_init(&hctx->md5);
break;
case SHA1:
rhash_sha1_init(&hctx->sha1);
break;
case SHA224:
rhash_sha224_init(&hctx->sha224);
break;
......@@ -109,6 +112,9 @@ update(const enum algorithm hash, hash_ctx *restrict const hctx,
case MD5:
rhash_md5_update(&hctx->md5, msg, len);
break;
case SHA1:
rhash_sha1_update(&hctx->sha1, msg, len);
break;
case SHA224:
rhash_sha256_update(&hctx->sha224, msg, len);
break;
......@@ -132,6 +138,9 @@ final(const enum algorithm hash, hash_ctx *restrict const hctx,
case MD5:
rhash_md5_final(&hctx->md5, result);
break;
case SHA1:
rhash_sha1_final(&hctx->sha1, result);
break;
case SHA224:
rhash_sha256_final(&hctx->sha224, result);
break;
......
......@@ -29,12 +29,14 @@
#include "parse_algorithm.h"
#include "md5.h"
#include "sha1.h"
#include "vsha256.h"
#include "sha256.h"
#include "sha512.h"
typedef union hash_ctx {
md5_ctx md5;
sha1_ctx sha1;
sha256_ctx sha224;
SHA256_CTX sha256;
sha512_ctx sha512;
......@@ -48,6 +50,10 @@ static const struct hashspec {
md5_hash_size,
md5_block_size,
},
[SHA1] = {
sha1_hash_size,
sha1_block_size,
},
[SHA224] = {
sha224_hash_size,
sha256_block_size,
......
......@@ -9,7 +9,7 @@
$Module blobdigest 3 digests and hmacs for the VCL blob type
$Object hmac(ENUM {MD5, SHA224, SHA256, SHA384, SHA512} hash, BLOB key)
$Object hmac(ENUM {MD5, SHA1, SHA224, SHA256, SHA384, SHA512} hash, BLOB key)
Prototype
new OBJ = blobdigest.hmac(ENUM hash, BLOB key)
......@@ -31,7 +31,8 @@ Description
Example
``set req.http.hmac = hmac.hmac(blobcode.decode(BASE64, "Zm9v"));``
$Function BLOB hash(ENUM {MD5, SHA224, SHA256, SHA384, SHA512} hash, BLOB msg)
$Function BLOB hash(ENUM {MD5, SHA1, SHA224, SHA256, SHA384, SHA512} hash,
BLOB msg)
$Function STRING version()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment