From 8423236dbb065deed7270200c0e5c0c42966229f Mon Sep 17 00:00:00 2001 From: Gordon Hecker Date: Mon, 9 Nov 2009 14:39:10 +0100 Subject: [PATCH] sha1: use sha1 module instead of sha1sum tool testcase for the sha1 module is included in test_sha1.lua Signed-off-by: Gordon Hecker --- Changelog | 1 + generic/Makefile | 14 +++- generic/hash.lua | 27 ++----- generic/lsha1.c | 134 ++++++++++++++++++++++++++++++++ generic/sha1.c | 176 ++++++++++++++++++++++++++++++++++++++++++ generic/sha1.h | 12 +++ generic/test_sha1.lua | 29 +++++++ 7 files changed, 368 insertions(+), 25 deletions(-) create mode 100644 generic/lsha1.c create mode 100644 generic/sha1.c create mode 100644 generic/sha1.h create mode 100644 generic/test_sha1.lua diff --git a/Changelog b/Changelog index d62097a..5f9117f 100644 --- a/Changelog +++ b/Changelog @@ -1,4 +1,5 @@ NEXT: + * use sha1 module instead of calling the sha1sum tool e2factory-2.3.2 * temporary build directories are located in a version specific directory diff --git a/generic/Makefile b/generic/Makefile index 40086b0..eac84cb 100644 --- a/generic/Makefile +++ b/generic/Makefile @@ -32,15 +32,16 @@ TOPLEVEL = .. include $(TOPLEVEL)/make.vars -CLEAN_FILES = *~ *.lc *.so lua-version-map.lua e2-su-2.2 +CLEAN_FILES = *~ *.lc *.o *.so lua-version-map.lua e2-su-2.2 .PHONY: all install uninstall local install-local clean -all: e2generic_global.lc luafile_ll_global.so e2util_global.so e2-su-2.2 +all: e2generic_global.lc luafile_ll_global.so e2util_global.so e2-su-2.2 sha1.so install: all install -m 644 e2generic_global.lc $(DESTDIR)$(LIBDIR) + install -m 755 sha1.so $(DESTDIR)$(LIBDIR) install -m 755 luafile_ll_global.so $(DESTDIR)$(LIBDIR) install -m 755 e2util_global.so $(DESTDIR)$(LIBDIR) install -m 4754 -o root -g $(E2_GROUP) e2-su-2.2 $(DESTDIR)$(BINDIR)/ @@ -51,11 +52,12 @@ uninstall: rm -f $(DESTDIR)$(LIBDIR)/luafile_ll_global.so rm -f $(DESTDIR)$(LIBDIR)/e2util_global.so -local: e2generic_local.lc luafile_ll_local.so e2util_local.so +local: e2generic_local.lc luafile_ll_local.so e2util_local.so sha1.so install-local: local mkdir -p $(LOCALLIBDIR) $(LOCALMAKDIR) install -m 644 e2generic_local.lc $(LOCALLIBDIR) + install -m 755 sha1.so $(LOCALLIBDIR) install -m 755 luafile_ll_local.so $(LOCALLIBDIR) install -m 755 e2util_local.so $(LOCALLIBDIR) install -m 644 e2-su-2.2.c $(LOCALMAKDIR) @@ -103,3 +105,9 @@ luafile_ll_local.so: luafile_ll.c e2util_local.so: e2util.c $(CC) -DLOCAL $(CFLAGS) $(LUA_CPPFLAGS) $(LDFLAGS) -shared -fPIC $< -o $@ + +%.o: %.c + $(CC) $(CFLAGS) $(LUA_CPPFLAGS) $(LDFLAGS) -fPIC -o $@ -c $< + +sha1.so: sha1.o lsha1.o + $(CC) -o $@ -shared sha1.o lsha1.o diff --git a/generic/hash.lua b/generic/hash.lua index 71d2a92..deb8d56 100644 --- a/generic/hash.lua +++ b/generic/hash.lua @@ -25,6 +25,8 @@ along with this program. If not, see . ]] +require("sha1") + --- create a hash context -- @return a hash context object, or nil on error -- @return nil, an error string on error @@ -54,28 +56,9 @@ end -- @return the hash value, or nil on error -- @return an error string on error local function hash_finish(hc) - -- write hash data to a temporary file - hc.tmpdir = e2lib.mktempdir() - hc.tmpfile = string.format("%s/hashdata", hc.tmpdir) - hc.f = io.open(hc.tmpfile, "w") - hc.f:write(hc.data) - hc.f:close() - - -- hash data and read the hash value - local cmd = string.format("sha1sum %s", hc.tmpfile) - hc.p = io.popen(cmd, "r") - local s = hc.p:read() - if not s then - return nil, "calculating hash value failed" - end - hc.p:close() - - -- parse the output from sha1sum - hc.sha1 = s:match("(%S+)") - if not hc.sha1 then - return nil, "calculating hash value failed" - end - e2lib.rmtempdir(hc.tmpdir) + local ctx = sha1.sha1_init() + ctx:update(hc.data) + hc.sha1 = string.lower(ctx:final()) return hc.sha1 end diff --git a/generic/lsha1.c b/generic/lsha1.c new file mode 100644 index 0000000..885f8a0 --- /dev/null +++ b/generic/lsha1.c @@ -0,0 +1,134 @@ +/* + e2factory, the emlix embedded build system + + Copyright (C) 2009 Gordon Hecker , emlix GmbH + + For more information have a look at http://www.e2factory.org + + e2factory is a registered trademark by emlix GmbH. + + This file is part of e2factory, the emlix embedded build system. + + e2factory is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + 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. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include + +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" + +#include "sha1.h" + +#define MODULE_NAME "sha1" +#define MODULE_VERSION "1" +#define LUA_OBJECT_ID "sha1_ctx" + +/* + * __tostring(sha1_ctx) generate a string representation + * returns a string + */ +static int sha1_tostring(lua_State *L) +{ + SHA1_CTX *ctx; + ctx = luaL_checkudata(L, 1, LUA_OBJECT_ID); + lua_pushfstring(L, "%s (%p)", LUA_OBJECT_ID, ctx); + return 1; +} + +/* + * update(sha1_ctx, string) update a sha1 context with data from string + * returns bool + */ +static int sha1_update(lua_State *L) +{ + const char *s; + size_t len; + SHA1_CTX *ctx; + ctx = luaL_checkudata(L, 1, LUA_OBJECT_ID); + s = luaL_checklstring(L, 2, &len); + SHA1Update(ctx, (unsigned char *)s, len); + return 0; +} + +/* + * final(sha1_ctx) finalizes the sha1 context + * returns string: the digest + */ +static int sha1_final(lua_State *L) +{ + SHA1_CTX *ctx; + unsigned char digest[20]; + char s[41]; + int i; + ctx = luaL_checkudata(L, 1, LUA_OBJECT_ID); + memset(digest, 0, sizeof(digest)); + SHA1Final(digest, ctx); + for(i=0; i<20; i++) { + sprintf(&s[2*i], "%02X", digest[i]); + } + lua_pushstring(L, s); + return 1; +} + +static const luaL_reg sha1_methods[] = +{ + {"update", sha1_update}, + {"final", sha1_final}, + {NULL, NULL} +}; + +static const luaL_reg sha1_meta[] = +{ + {"__tostring", sha1_tostring}, + {NULL, NULL} +}; + +/* + * init() initialize a sha1 context + * returns sha1_ctx + */ +static int sha1_init(lua_State *L) +{ + SHA1_CTX *ctx = (SHA1_CTX *)lua_newuserdata(L, sizeof(SHA1_CTX)); + memset(ctx, 0, sizeof(ctx)); /* really needed? */ + SHA1Init(ctx); + + if(luaL_newmetatable(L, LUA_OBJECT_ID)) { + luaL_register(L, 0, sha1_meta); + lua_pushliteral(L, "__index"); + lua_newtable(L); + luaL_register(L, 0, sha1_methods); + lua_rawset(L, -3); + } + lua_setmetatable(L, -2); + return 1; +} + +static const luaL_reg R[] = +{ + {"sha1_init", sha1_init}, + {NULL, NULL} +}; + +LUALIB_API int luaopen_sha1(lua_State *L) +{ + luaL_register(L, MODULE_NAME, R); + lua_pushliteral(L, "version"); + lua_pushliteral(L, MODULE_VERSION); + lua_settable(L,-3); + return 1; +} diff --git a/generic/sha1.c b/generic/sha1.c new file mode 100644 index 0000000..55c0313 --- /dev/null +++ b/generic/sha1.c @@ -0,0 +1,176 @@ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Modified by Gordon Hecker + - compile correctly on architectures where long int is not 32bit + - define SHA1HANDSOFF + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd if true. */ +#if __LITTLE_ENDIAN__ +#define LITTLE_ENDIAN +#endif +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#define SHA1HANDSOFF 1 + +#include +#include +#include + +#include "sha1.h" + +void SHA1Transform(u_int32_t state[5], unsigned char buffer[64]); + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifdef LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i&15] = 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+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(u_int32_t state[5], unsigned char buffer[64]) +{ +u_int32_t a, b, c, d, e; +typedef union { + unsigned char c[64]; + u_int32_t l[16]; +} CHAR64LONG16; +CHAR64LONG16* block; +#ifdef SHA1HANDSOFF +static unsigned char workspace[64]; + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16*)buffer; +#endif + /* Copy context->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 context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update(SHA1_CTX* context, unsigned char* data, u_int32_t len) +{ +u_int32_t i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ +u_int32_t i, j; +unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1Update(context, (unsigned char *)"\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1Update(context, (unsigned char *)"\0", 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + /* Wipe variables */ + i = j = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(&finalcount, 0, 8); +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ + SHA1Transform(context->state, context->buffer); +#endif +} diff --git a/generic/sha1.h b/generic/sha1.h new file mode 100644 index 0000000..4d0dd93 --- /dev/null +++ b/generic/sha1.h @@ -0,0 +1,12 @@ + +// From http://www.mirrors.wiretapped.net/security/cryptography/hashes/sha1/sha1.c + +typedef struct { + unsigned int state[5]; + unsigned int count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +extern void SHA1Init(SHA1_CTX* context); +extern void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len); +extern void SHA1Final(unsigned char digest[20], SHA1_CTX* context); diff --git a/generic/test_sha1.lua b/generic/test_sha1.lua new file mode 100644 index 0000000..f69aa75 --- /dev/null +++ b/generic/test_sha1.lua @@ -0,0 +1,29 @@ +require("sha1") + +--[[ +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +--]] + +local c, r +c = sha1.sha1_init() +c:update("abc") +r = c:final() +assert(r == "A9993E364706816ABA3E25717850C26C9CD0D89D") + +c = sha1.sha1_init() +c:update("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") +r = c:final() +assert(r == "84983E441C3BD26EBAAE4AA1F95129E5E54670F1") + +c = sha1.sha1_init() +for i=1, 1000000, 1 do + c:update("a") +end +r = c:final(c) +assert(r == "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F") -- 2.39.5