commit f4e59021d2e17e97d06ff3da440a3190294b6d40 Author: cosmin.apreutesei Date: Wed Dec 18 17:38:06 2013 +0200 inuit diff --git a/sha2.lua b/sha2.lua new file mode 100644 index 0000000..3b9dd66 --- /dev/null +++ b/sha2.lua @@ -0,0 +1,72 @@ +--sha256/384/512 hash and digest +local ffi = require'ffi' +local C = ffi.load'sha2' + +ffi.cdef[[ +enum { + SHA256_BLOCK_LENGTH = 64, + SHA256_DIGEST_LENGTH = 32, + SHA384_BLOCK_LENGTH = 128, + SHA384_DIGEST_LENGTH = 48, + SHA512_BLOCK_LENGTH = 128, + SHA512_DIGEST_LENGTH = 64, +}; +typedef struct _SHA256_CTX { + uint32_t state[8]; + uint64_t bitcount; + uint8_t buffer[SHA256_BLOCK_LENGTH]; +} SHA256_CTX; +typedef struct _SHA512_CTX { + uint64_t state[8]; + uint64_t bitcount[2]; + uint8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; +typedef SHA512_CTX SHA384_CTX; + +void SHA256_Init(SHA256_CTX *); +void SHA256_Update(SHA256_CTX*, const uint8_t*, size_t); +void SHA256_Final(uint8_t[SHA256_DIGEST_LENGTH], SHA256_CTX*); + +void SHA384_Init(SHA384_CTX*); +void SHA384_Update(SHA384_CTX*, const uint8_t*, size_t); +void SHA384_Final(uint8_t[SHA384_DIGEST_LENGTH], SHA384_CTX*); + +void SHA512_Init(SHA512_CTX*); +void SHA512_Update(SHA512_CTX*, const uint8_t*, size_t); +void SHA512_Final(uint8_t[SHA512_DIGEST_LENGTH], SHA512_CTX*); +]] + +local function digest_function(Context, Init, Update, Final, DIGEST_LENGTH) + return function() + local ctx = ffi.new(Context) + local result = ffi.new('uint8_t[?]', DIGEST_LENGTH) + Init(ctx) + return function(data, size) + if data then + Update(ctx, data, size or #data) + else + Final(result, ctx) + return ffi.string(result, ffi.sizeof(result)) + end + end + end +end + +local function hash_function(digest_function) + return function(data, size) + local d = digest_function(); d(data, size); return d() + end +end + +local M = {C = C} + +M.sha256_digest = digest_function(ffi.typeof'SHA256_CTX', C.SHA256_Init, C.SHA256_Update, C.SHA256_Final, C.SHA256_DIGEST_LENGTH) +M.sha384_digest = digest_function(ffi.typeof'SHA384_CTX', C.SHA384_Init, C.SHA384_Update, C.SHA384_Final, C.SHA384_DIGEST_LENGTH) +M.sha512_digest = digest_function(ffi.typeof'SHA512_CTX', C.SHA512_Init, C.SHA512_Update, C.SHA512_Final, C.SHA512_DIGEST_LENGTH) +M.sha256 = hash_function(M.sha256_digest) +M.sha384 = hash_function(M.sha384_digest) +M.sha512 = hash_function(M.sha512_digest) + +if not ... then require'sha2_test' end + +return M diff --git a/sha2.md b/sha2.md new file mode 100644 index 0000000..7bbde18 --- /dev/null +++ b/sha2.md @@ -0,0 +1,37 @@ +--- +project: sha2 +tagline: SHA-256, SHA-384 and SHA-512 sum and digest +--- + +v1.0 | sha2-1.0 | LuaJIT 2 + +## `local sha2 = require'sha2'` + +A ffi binding of Aaron Gifford's [SHA-2 implementation](http://www.aarongifford.com/computers/sha.html). + +----------------------------------- ----------------------------------- +`sha2.sha256(s[, size]) -> s` \ Compute the SHA-2 hash of a string or a cdata buffer. +`sha2.sha256(cdata, size) -> s` \ Return the binary representation of the hash. +`sha2.sha384(s[, size]) -> s` \ To get the hex representation, use [glue.tohex]. +`sha2.sha384(cdata, size) -> s` \ +`sha2.sha512(s[, size]) -> s` \ +`sha2.sha512(cdata, size) -> s` + +`sha2.sha256_digest() -> digest` \ Get a SHA-2 digest function that can consume multiple data chunks +`sha2.sha384_digest() -> digest` \ until called with no arguments when it returns the final SHA hash. +`sha2.sha512_digest() -> digest` \ +`digest(s[, size])` \ +`digest(cdata, size)` \ +`digest() -> s` + +----------------------------------- ----------------------------------- + +## Building + +C sources and build scripts included. Binary also included. + +---- +_See also_: [md5](md5.html). + +[glue.tohex]: glue.html#tohex + diff --git a/sha2_test.lua b/sha2_test.lua new file mode 100644 index 0000000..9ecbc8d --- /dev/null +++ b/sha2_test.lua @@ -0,0 +1,42 @@ +local sha2 = require'sha2' +local glue = require'glue' + +sha = { + SHA256 = function(s) return glue.tohex(sha2.sha256(s)) end, + SHA384 = function(s) return glue.tohex(sha2.sha384(s)) end, + SHA512 = function(s) return glue.tohex(sha2.sha512(s)) end, +} + +for file in io.popen('ls media/sha2/*.dat'):lines() do + local name, ext = file:match('^(.-)%.(.*)$') + if ext == 'dat' then + local s = glue.readfile(file, 'rb') + local hashes = {} + do + local f = assert(io.open(name..'.info')) + do + local name, hash + for line in f:lines() do + if line:find'^SHA' then + name = line:match'^(SHA.?.?.?)' + hash = '' + elseif hash then + if #line == 0 then + hashes[name] = hash + hash = nil + elseif hash then + hash = hash .. line:match'^%s*(.-)%s*$' + end + end + end + end + f:close() + end + + for k,v in pairs(hashes) do + local h = sha[k](s) + print(file, k..'x', #s, h == v and 'ok' or h .. ' ~= ' .. v) + end + end +end +