ESP32 crypto module (#2607)
This commit is contained in:
parent
fa35e02481
commit
746f519c47
|
@ -74,6 +74,38 @@ config LUA_MODULE_CAN
|
|||
help
|
||||
Includes the can module.
|
||||
|
||||
config LUA_MODULE_CRYPTO
|
||||
bool "Crypto module"
|
||||
default "n"
|
||||
help
|
||||
Includes the crypto module.
|
||||
|
||||
menu "Crypto module hashing algorithms"
|
||||
depends on LUA_MODULE_CRYPTO
|
||||
|
||||
config CRYPTO_HASH_SHA1
|
||||
bool "SHA1"
|
||||
default "y"
|
||||
help
|
||||
Includes the SHA1 hashing algorithm
|
||||
config CRYPTO_HASH_SHA256
|
||||
bool "SHA256 and SHA224"
|
||||
default "y"
|
||||
help
|
||||
Includes the SHA256 and SHA224 hashing algorithms
|
||||
config CRYPTO_HASH_SHA512
|
||||
bool "SHA512 and SHA384"
|
||||
default "y"
|
||||
help
|
||||
Includes the SHA256 and SHA384 hashing algorithms
|
||||
config CRYPTO_HASH_MD5
|
||||
bool "MD5"
|
||||
default "n"
|
||||
help
|
||||
Includes the MD5 hashing algorithm
|
||||
endmenu
|
||||
|
||||
|
||||
config LUA_MODULE_DAC
|
||||
bool "DAC module"
|
||||
default "n"
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include "lauxlib.h"
|
||||
#include "lmem.h"
|
||||
#include "mbedtls/md5.h"
|
||||
#include "mbedtls/sha1.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/sha512.h"
|
||||
#include "module.h"
|
||||
#include "platform.h"
|
||||
|
||||
#define HASH_METATABLE "crypto.hasher"
|
||||
|
||||
// The following function typedefs aim to generalize mbedtls functions
|
||||
// so that we can use the same code independent of what hashing algorithm
|
||||
typedef void (*hash_init_t)(void* ctx);
|
||||
typedef int (*hash_starts_ret_t)(void* ctx);
|
||||
typedef int (*hash_update_ret_t)(void* ctx, const unsigned char* input, size_t ilen);
|
||||
typedef int (*hash_finish_ret_t)(void* ctx, unsigned char* output);
|
||||
typedef void (*hash_free_t)(void* ctx);
|
||||
|
||||
// algo_info_t describes a hashing algorithm and the mbedtls functions
|
||||
// for initializing, hashing data, finalizing and freeing resources.
|
||||
typedef struct {
|
||||
const char* name;
|
||||
const size_t size;
|
||||
const size_t context_size;
|
||||
const hash_init_t init;
|
||||
const hash_starts_ret_t starts;
|
||||
const hash_update_ret_t update;
|
||||
const hash_finish_ret_t finish;
|
||||
const hash_free_t free;
|
||||
} algo_info_t;
|
||||
|
||||
// hash_context_t contains information about an ongoing hash operation
|
||||
typedef struct {
|
||||
void* mbedtls_context;
|
||||
const algo_info_t* ainfo;
|
||||
} hash_context_t;
|
||||
|
||||
// if SHA256+SHA224 are enabled, the following two functions
|
||||
// allow to call mbedtls appropriately depending on the algorithm
|
||||
#ifdef CONFIG_CRYPTO_HASH_SHA256
|
||||
static int sha256_starts_ret(mbedtls_sha256_context* ctx) {
|
||||
return mbedtls_sha256_starts_ret(ctx, false); // false=SHA256
|
||||
}
|
||||
static int sha224_starts_ret(mbedtls_sha256_context* ctx) {
|
||||
return mbedtls_sha256_starts_ret(ctx, true); // true=SHA224
|
||||
}
|
||||
#endif
|
||||
|
||||
// if SHA512+SHA384 are enabled, the following two functions
|
||||
// allow to call mbedtls appropriately depending on the algorithm
|
||||
#ifdef CONFIG_CRYPTO_HASH_SHA512
|
||||
static int sha512_starts_ret(mbedtls_sha512_context* ctx) {
|
||||
return mbedtls_sha512_starts_ret(ctx, false); // false=SHA512
|
||||
}
|
||||
static int sha384_starts_ret(mbedtls_sha512_context* ctx) {
|
||||
return mbedtls_sha512_starts_ret(ctx, true); // true=SHA384
|
||||
}
|
||||
#endif
|
||||
|
||||
// the constant algorithms array below contains a table of functions and other
|
||||
// information about each enabled hashing algorithm
|
||||
static const algo_info_t algorithms[] = {
|
||||
#ifdef CONFIG_CRYPTO_HASH_SHA1
|
||||
{
|
||||
"SHA1",
|
||||
20,
|
||||
sizeof(mbedtls_sha1_context),
|
||||
(hash_init_t)mbedtls_sha1_init,
|
||||
(hash_starts_ret_t)mbedtls_sha1_starts_ret,
|
||||
(hash_update_ret_t)mbedtls_sha1_update_ret,
|
||||
(hash_finish_ret_t)mbedtls_sha1_finish_ret,
|
||||
(hash_free_t)mbedtls_sha1_free,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_CRYPTO_HASH_SHA256
|
||||
{
|
||||
"SHA256",
|
||||
32,
|
||||
sizeof(mbedtls_sha256_context),
|
||||
(hash_init_t)mbedtls_sha256_init,
|
||||
(hash_starts_ret_t)sha256_starts_ret,
|
||||
(hash_update_ret_t)mbedtls_sha256_update_ret,
|
||||
(hash_finish_ret_t)mbedtls_sha256_finish_ret,
|
||||
(hash_free_t)mbedtls_sha256_free,
|
||||
},
|
||||
{
|
||||
"SHA224",
|
||||
32,
|
||||
sizeof(mbedtls_sha256_context),
|
||||
(hash_init_t)mbedtls_sha256_init,
|
||||
(hash_starts_ret_t)sha224_starts_ret,
|
||||
(hash_update_ret_t)mbedtls_sha256_update_ret,
|
||||
(hash_finish_ret_t)mbedtls_sha256_finish_ret,
|
||||
(hash_free_t)mbedtls_sha256_free,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_CRYPTO_HASH_SHA512
|
||||
{
|
||||
"SHA512",
|
||||
64,
|
||||
sizeof(mbedtls_sha512_context),
|
||||
(hash_init_t)mbedtls_sha512_init,
|
||||
(hash_starts_ret_t)sha512_starts_ret,
|
||||
(hash_update_ret_t)mbedtls_sha512_update_ret,
|
||||
(hash_finish_ret_t)mbedtls_sha512_finish_ret,
|
||||
(hash_free_t)mbedtls_sha512_free,
|
||||
},
|
||||
{
|
||||
"SHA384",
|
||||
64,
|
||||
sizeof(mbedtls_sha512_context),
|
||||
(hash_init_t)mbedtls_sha512_init,
|
||||
(hash_starts_ret_t)sha384_starts_ret,
|
||||
(hash_update_ret_t)mbedtls_sha512_update_ret,
|
||||
(hash_finish_ret_t)mbedtls_sha512_finish_ret,
|
||||
(hash_free_t)mbedtls_sha512_free,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_CRYPTO_HASH_MD5
|
||||
{
|
||||
"MD5",
|
||||
16,
|
||||
sizeof(mbedtls_md5_context),
|
||||
(hash_init_t)mbedtls_md5_init,
|
||||
(hash_starts_ret_t)mbedtls_md5_starts_ret,
|
||||
(hash_update_ret_t)mbedtls_md5_update_ret,
|
||||
(hash_finish_ret_t)mbedtls_md5_finish_ret,
|
||||
(hash_free_t)mbedtls_md5_free,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
//NUM_ALGORITHMS contains the actual number of enabled algorithms
|
||||
const int NUM_ALGORITHMS = sizeof(algorithms) / sizeof(algo_info_t);
|
||||
|
||||
// crypto_new_hash (LUA: hasher = crypto.new_hash(algo)) allocates
|
||||
// a hashing context for the requested algorithm
|
||||
static int crypto_new_hash(lua_State* L) {
|
||||
const char* algo = luaL_checkstring(L, 1);
|
||||
const algo_info_t* ainfo = NULL;
|
||||
|
||||
for (int i = 0; i < NUM_ALGORITHMS; i++) {
|
||||
if (strcasecmp(algo, algorithms[i].name) == 0) {
|
||||
ainfo = &algorithms[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ainfo == NULL) {
|
||||
luaL_error(L, "Unsupported algorithm: %s", algo); // returns
|
||||
}
|
||||
|
||||
// Instantiate a hasher object as a Lua userdata object
|
||||
// it will contain a pointer to a hash_context_t structure in which
|
||||
// we will store the mbedtls context information and also
|
||||
// what hashing algorithm this context is for.
|
||||
hash_context_t* phctx = (hash_context_t*)lua_newuserdata(L, sizeof(hash_context_t));
|
||||
luaL_getmetatable(L, HASH_METATABLE);
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
phctx->ainfo = ainfo; // save a pointer to the algorithm function table and information
|
||||
phctx->mbedtls_context = luaM_malloc(L, ainfo->context_size); // make some space for the mbedtls context
|
||||
if (phctx->mbedtls_context == NULL) {
|
||||
luaL_error(L, "Out of memory allocating context");
|
||||
}
|
||||
|
||||
ainfo->init(phctx->mbedtls_context); // initialize the hashing function
|
||||
if (ainfo->starts(phctx->mbedtls_context) != 0) {
|
||||
luaL_error(L, "Error starting context");
|
||||
}
|
||||
return 1; // one object returned, the hasher userdata object.
|
||||
}
|
||||
|
||||
// crypto_hash_update (LUA: hasher:update(data)) submits data
|
||||
// to be hashed.
|
||||
static int crypto_hash_update(lua_State* L) {
|
||||
// retrieve the hashing context:
|
||||
hash_context_t* phctx = (hash_context_t*)luaL_checkudata(L, 1, HASH_METATABLE);
|
||||
|
||||
size_t size; // size of the input string
|
||||
// retrieve the input string:
|
||||
const unsigned char* input = (const unsigned char*)luaL_checklstring(L, 2, &size);
|
||||
|
||||
// call the update hashing function:
|
||||
if (phctx->ainfo->update(phctx->mbedtls_context, input, size) != 0) {
|
||||
luaL_error(L, "Error updating hash");
|
||||
}
|
||||
|
||||
return 0; // no return value
|
||||
}
|
||||
|
||||
// crypto_hash_finalize (LUA: hasher:finalize()) returns the hash result
|
||||
// as a binary string.
|
||||
static int crypto_hash_finalize(lua_State* L) {
|
||||
// retrieve the hashing context:
|
||||
hash_context_t* phctx = (hash_context_t*)luaL_checkudata(L, 1, HASH_METATABLE);
|
||||
|
||||
// reserve some space to retrieve the output hash, according to the current algorithm
|
||||
unsigned char output[phctx->ainfo->size];
|
||||
|
||||
// call the hash finish function to retrieve the result
|
||||
if (phctx->ainfo->finish(phctx->mbedtls_context, output) != 0) {
|
||||
luaL_error(L, "Error finalizing hash");
|
||||
}
|
||||
|
||||
// pack the output into a lua string
|
||||
lua_pushlstring(L, (const char*)output, phctx->ainfo->size);
|
||||
|
||||
return 1; // 1 result returned, the hash.
|
||||
}
|
||||
|
||||
// crypto_hash_gc is called automatically by LUA when the hasher object is
|
||||
// dereferenced, in order to free resources associated with the hashing process.
|
||||
static int crypto_hash_gc(lua_State* L) {
|
||||
// retrieve the hashing context:
|
||||
hash_context_t* phctx = (hash_context_t*)luaL_checkudata(L, 1, HASH_METATABLE);
|
||||
|
||||
// if the mbedtls context is NULL, it means allocation failed in new_hash(), so nothing to do.
|
||||
if (phctx->mbedtls_context == NULL)
|
||||
return 0;
|
||||
|
||||
// free mbedtls-related resources for this hash operation:
|
||||
phctx->ainfo->free(phctx->mbedtls_context);
|
||||
|
||||
// free the memory allocated to store the mbedtls context:
|
||||
luaM_freemem(L, phctx->mbedtls_context, phctx->ainfo->context_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The following table defines methods of the hasher object
|
||||
static const LUA_REG_TYPE crypto_hasher_map[] = {
|
||||
{LSTRKEY("update"), LFUNCVAL(crypto_hash_update)},
|
||||
{LSTRKEY("finalize"), LFUNCVAL(crypto_hash_finalize)},
|
||||
{LSTRKEY("__gc"), LFUNCVAL(crypto_hash_gc)},
|
||||
{LSTRKEY("__index"), LROVAL(crypto_hasher_map)},
|
||||
{LNILKEY, LNILVAL}};
|
||||
|
||||
// This table defines the functions of the crypto module:
|
||||
static const LUA_REG_TYPE crypto_map[] = {
|
||||
{LSTRKEY("new_hash"), LFUNCVAL(crypto_new_hash)},
|
||||
{LNILKEY, LNILVAL}};
|
||||
|
||||
// luaopen_crypto is the crypto module initialization function
|
||||
int luaopen_crypto(lua_State* L) {
|
||||
luaL_rometatable(L, HASH_METATABLE, (void*)crypto_hasher_map); // create metatable for crypto.hash
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// define the crypto NodeMCU module
|
||||
NODEMCU_MODULE(CRYPTO, "crypto", crypto_map, luaopen_crypto);
|
|
@ -0,0 +1,39 @@
|
|||
# crypto Module
|
||||
| Since | Origin / Contributor | Maintainer | Source |
|
||||
| :----- | :-------------------- | :---------- | :------ |
|
||||
| 2019-01-13 | [Javier Peletier](https://github.com/jpeletier) | [Javier Peletier](https://github.com/jpeletier) | [crypto.c](../../../components/modules/crypto.c)|
|
||||
|
||||
The crypto module provides various functions for working with cryptographic algorithms.
|
||||
|
||||
This is work in progress, for now only a number of hashing functions are available:
|
||||
|
||||
* SHA1
|
||||
* SHA256
|
||||
* SHA224
|
||||
* SHA512
|
||||
* SHA384
|
||||
* MD5
|
||||
|
||||
All except MD5 are enabled by default. To disable algorithms you don't need, find the "Crypto module hashing algorithms" under the NodeMCU modules section in menuconfig.
|
||||
|
||||
## crypto.new_hash()
|
||||
|
||||
Create a digest/hash object that can have any number of strings added to it. Object has `update` and `finalize` functions.
|
||||
|
||||
#### Syntax
|
||||
`hashobj = crypto.new_hash(algo)`
|
||||
|
||||
#### Parameters
|
||||
`algo` the hash algorithm to use, case insensitive string
|
||||
|
||||
#### Returns
|
||||
Hasher object with `update` and `finalize` functions available.
|
||||
|
||||
#### Example
|
||||
```lua
|
||||
hashobj = crypto.new_hash("SHA1")
|
||||
hashobj:update("FirstString"))
|
||||
hashobj:update("SecondString"))
|
||||
digest = hashobj:finalize()
|
||||
print(encoder.toHex(digest))
|
||||
```
|
|
@ -36,6 +36,7 @@ pages:
|
|||
- 'bit': 'modules/bit.md'
|
||||
- 'bthci': 'modules/bthci.md'
|
||||
- 'can': 'modules/can.md'
|
||||
- 'crypto': 'modules/crypto.md'
|
||||
- 'dac': 'modules/dac.md'
|
||||
- 'dht': 'modules/dht.md'
|
||||
- 'encoder': 'modules/encoder.md'
|
||||
|
|
Loading…
Reference in New Issue