lua-hash is a lightweight, native library providing hash algorithms for Lua.
- On Unix-like distributions, it uses the OpenSSL library;
- On Windows, it uses the WINAPI
bcryptlibrary; - On macOS / iOS, it uses the
CommonCryptolibrary.
Note
lua-hash is implemented in C, and also compiles as C++.
| Algorithm | Description |
|---|---|
| MD5 | An implementation of MD5 hashing with a 128-bit digest |
| SHA1 | An implementation of SHA1 hashing with a 160-bit digest |
| SHA256 | An implementation of Secure Hashing Algorithm 2 (SHA-2) hashing with a 256-bit digest |
| SHA384 | An implementation of Secure Hashing Algorithm 2 (SHA-2) hashing with a 384-bit digest |
| SHA512 | An implementation of Secure Hashing Algorithm 2 (SHA-2) hashing with a 512-bit digest |
Warning
According to Apple (see [1] and [2]), MD5 and SHA1 are considered insecure algorithms, but they are provided for backward compatibility with older services that require it. For new services, prefer SHA512.
Important
On Unix-like operating systems (e.g.: Linux, BSD), lua-hash depends on the OpenSSL library:
-
On Debian-based (e.g.: Ubuntu) distributions:
sudo apt install -y libssl-dev
-
On RedHat-based (e.g.: Fedora) distributions:
sudo dnf install openssl-devel
-
On BSD-based (e.g.: FreeBSD) distributions:
pkg install openssl-devel
Assuming that LuaRocks is properly installed and configured on your system, execute the following command:
luarocks install lua-hashThis manner is suitable for (small) text that fits well in the memory.
-- load the library
local hash = require("lua-hash")
-- the text to be hashed
local text = "lua-hash is a cool hashing library"
-- hash 'text' by different algorithms
local MD5_hash = hash.oneshot("MD5", text)
local SHA1_hash = hash.oneshot("SHA1", text)
local SHA256_hash = hash.oneshot("SHA256", text)
local SHA384_hash = hash.oneshot("SHA384", text)
local SHA512_hash = hash.oneshot("SHA512", text)
-- print the hash of 'text' computed by different algorithms
print("MD5 hash is", MD5_hash)
print("SHA1 hash is", SHA1_hash)
print("SHA256 hash is", SHA256_hash)
print("SHA384 hash is", SHA384_hash)
print("SHA512 hash is", SHA512_hash)By the use of the core API, you can compute a hash of a file of any size (even the huge ones).
-- the file path to compute a SHA512 hash
local filepath = "path/to/some/file"
local file = assert(io.open(filepath, "rb"), "provide the file path as a parameter to this script to compute a SHA512 checksum")
-- load the library
local hash = require("lua-hash")
-- cache the classes
local algorithm = hash.algorithm
local context = hash.context
local digest = hash.digest
-- open the SHA512 algorithm
local algo = algorithm.open("SHA512")
-- create a context for the hash operation
local ctx = context.new(algo)
-- create a message digest
local message = digest.new(ctx)
-- define a size in bytes
-- to read a chunk from
-- disk
local kb = 1024
local size = 16 * kb
local valid = true
-- keep reading the file while
-- it is not finished
while (valid) do
local chunk = file:read(size)
if (chunk == nil) then
valid = false
else
-- hash the chunk read from disk
-- into the context
message:update(chunk)
end
end
-- close the file
file:close()
local output = message:finalize()
print(("%s %s"):format(output, filepath))
-- close the context to free resources
--
-- tip: the context is closed
-- automatically at garbage collection
ctx:close()
-- close the algorithm to free resources
--
-- tip: the algorithm is closed
-- automatically at garbage collection
algo:close()Tip
In the checksums folder, you can find scripts for each available hashing algorithm on this library.
- Description: The oneshot function provides a quick manner to compute the hash of a text held in memory.
- Signature:
oneshot(name, text) - Parameters:
- name (
string): the name of the algorithm. See Supported Algorithms for a list containing the possible values for this parameter. - text (
string): the text to compute a hash.
- name (
- Return (
string): A hex string containing the hash of the text.
In order to compute the hash of content that is not suitable to hold in memory, we have to use a verbose approach through in-depth methods. Such specialized methods, split into three classes, were mirrored directly from the C API of the underlying libraries:
- algorithm;
- context;
- digest.
Implementation of a hash algorithm provided by the underlying library.
-
Description: Opens the implementation of a given hash algorithm and initializes resources.
-
Signature:
open(name) -
Parameters:
- name (
string): the name of the algorithm. See Supported Algorithms for a list of all the possible algorithms.
- name (
-
Return (
userdata): A handle to the hash algorithm. -
Remark: In case of failure, this function throws an error. It might happen if the underlying library does not support the hash algorithm identified by the
nameparameter.
- Description: Closes the algorithm and free resources.
- Signature:
instance:close()- instance (
userdata): an instance of the algorithm class
- instance (
- Return (
void)
A manager to process a digest associated to a given hash algorithm
- Description: Creates a new context to the provided algorithm, and initializes resources.
- Signature:
new(algorithm) - Parameters:
- algorithm (
userdata): an instance to an algorithm previously opened.
- algorithm (
- Return (
userdata): A handle to the newly created context. - Remark: In case of failure, this function throws an error. It might happen if the provided hashing algorithm is closed.
- Description: Closes the context and free resources.
- Signature:
instance:close()- instance (
userdata): an instance of the context class
- instance (
- Return (
void)
Allows a message, even the long ones, to be streamed in chunks to the underlying algorithm for the hash computation.
- Description: Creates a new digest bound to a context, and initializes resources.
- Signature:
new(ctx) - Parameters:
- ctx (
userdata): an instance of acontext.
- ctx (
- Return (
userdata): A handle to the newly created digest. - Remark: In case of failure, this function throws an error. It might happen if the provided context, or algorithm bound to the context, was closed.
- Description: Hashes the data into the context.
- Signature:
message:update(data)- message (
userdata): an instance of the digest class
- message (
- Parameters:
- data (
string | table): the data to be hashed into the context. Ifdatais a string, the only requirement is that it cannot be an empty string. Otherwise, whendatais a table, it is expected to be an array of bytes, i.e., elements are integers in 0 - 255 range.
- data (
- Return (
void) - Remark: In case of failure, this function throws an error. It might happen if the provided context, or algorithm bound to the context, was closed.
- Description: Retrieves the digest value from the context.
- Signature:
message:finalize(options)- message (
userdata): an instance of the digest class
- message (
- Parameters:
- options (
nil | table): whenoptionsis nil or not specified at all, a hex string is returned. Otherwise, whenoptionsis a table, it is mandatory to have a fieldtypedescribing the desired return type ('string' or 'table'). Moreover, whentypeis equal to'string', an optional boolean fieldhexcan be assigned to signal whether the resulting hash should be formatted as hex string or not.- examples:
- output a hex string:
-- output is a hex string local output = message:finalize()
- output a hex string:
-- output is a hex string local output = message:finalize(nil)
- (alternative) output a hex string:
-- output is a hex string local output = message:finalize({ type = 'string', hex = true })
- output a string (not hex-formatted):
-- output is a raw string, -- but not in hex format. -- Usually, this output string -- contains characters that cannot -- be rendered nicely on the screen. local output = message:finalize({ type = 'string', hex = false })
- output a table of bytes:
-- output is a table (array) such that -- each element falls in the 0 - 255 range local output = message:finalize({ type = 'table' })
- output a hex string:
- examples:
- options (
- Return (
string | table): the resulting hash of the whole set of bytes pushed into the context. - Remark:
- After calling this function, no additional usage of both the context and digest can be made, except for closing them and freeing resources.
- In case of failure, this function throws an error. It might happen if the provided context, or algorithm bound to the context, was closed.
- v0.0.3:
- Fixed an invalid error message, which would crash on Lua 5.1 and Lua 5.2, when a table of bytes was provided with numbers out of 0 - 255 range. In-depth explanation:
%I%flag onluaL_erroris only allowed on Lua 5.3 or newer; - Updated malloc calls to account for
sizeof(char)andsizeof(unsigned char); - Through CI, the library is also verified to work correctly on ARM64;
- GitHub actions were pinned by commit id to avoid supply-chain attacks;
- Rockspec upload now lives on its own publish.yml workflow. This has the goal to avoid manual upload in case of intermitent failures (e.g.: connection issues or unavailable services). In the new publish behavior, the repository owner must trigger upload manually on GitHub for the rockspec to be published on LuaRocks website.
- Fixed an invalid error message, which would crash on Lua 5.1 and Lua 5.2, when a table of bytes was provided with numbers out of 0 - 255 range. In-depth explanation:
- v0.0.2:
- Added the possibility for all Unix-like distributions to build and install
lua-hashusing the binding forOpenSSL; - Added a CI job to build and test
lua-hashon Cygwin; - Now, as a Unix-like distribution, Cygwin builds as a Unix distro. Thus, in order to build on Cygwin, you need to install the package
libssl-devel.
- Added the possibility for all Unix-like distributions to build and install
- v0.0.1: Initial release.
- Add CMake as a build system.