Added crypto.new_hmac() feature. (#1499)
Docs for crypto module refactored for easier maintenance.
This commit is contained in:
parent
19f80abb32
commit
a112296850
|
@ -156,31 +156,22 @@ int ICACHE_FLASH_ATTR crypto_fhash (const digest_mech_info_t *mi,
|
|||
}
|
||||
|
||||
|
||||
int ICACHE_FLASH_ATTR crypto_hmac (const digest_mech_info_t *mi,
|
||||
const char *data, size_t data_len,
|
||||
const char *key, size_t key_len,
|
||||
uint8_t *digest)
|
||||
void crypto_hmac_begin (void *ctx, const digest_mech_info_t *mi,
|
||||
const char *key, size_t key_len, uint8_t *k_opad)
|
||||
{
|
||||
if (!mi)
|
||||
return EINVAL;
|
||||
|
||||
void *ctx = (void *)os_malloc (mi->ctx_size);
|
||||
if (!ctx)
|
||||
return ENOMEM;
|
||||
|
||||
// If key too long, it needs to be hashed before use
|
||||
char tmp[mi->digest_size];
|
||||
if (key_len > mi->block_size)
|
||||
{
|
||||
mi->create (ctx);
|
||||
mi->update (ctx, key, key_len);
|
||||
mi->finalize (digest, ctx);
|
||||
key = digest;
|
||||
mi->finalize (tmp, ctx);
|
||||
key = tmp;
|
||||
key_len = mi->digest_size;
|
||||
mi->create (ctx); // refresh
|
||||
}
|
||||
|
||||
const size_t bs = mi->block_size;
|
||||
uint8_t k_ipad[bs];
|
||||
uint8_t k_opad[bs];
|
||||
|
||||
os_memset (k_ipad, 0x36, bs);
|
||||
os_memset (k_opad, 0x5c, bs);
|
||||
|
@ -191,16 +182,42 @@ int ICACHE_FLASH_ATTR crypto_hmac (const digest_mech_info_t *mi,
|
|||
k_opad[i] ^= key[i];
|
||||
}
|
||||
|
||||
mi->create (ctx);
|
||||
mi->update (ctx, k_ipad, bs);
|
||||
mi->update (ctx, data, data_len);
|
||||
}
|
||||
|
||||
|
||||
void crypto_hmac_finalize (void *ctx, const digest_mech_info_t *mi,
|
||||
const uint8_t *k_opad, uint8_t *digest)
|
||||
{
|
||||
mi->finalize (digest, ctx);
|
||||
|
||||
mi->create (ctx);
|
||||
mi->update (ctx, k_opad, bs);
|
||||
mi->update (ctx, k_opad, mi->block_size);
|
||||
mi->update (ctx, digest, mi->digest_size);
|
||||
mi->finalize (digest, ctx);
|
||||
}
|
||||
|
||||
os_free (ctx);
|
||||
|
||||
int crypto_hmac (const digest_mech_info_t *mi,
|
||||
const char *data, size_t data_len,
|
||||
const char *key, size_t key_len,
|
||||
uint8_t *digest)
|
||||
{
|
||||
if (!mi)
|
||||
return EINVAL;
|
||||
|
||||
struct {
|
||||
uint8_t ctx[mi->ctx_size];
|
||||
uint8_t k_opad[mi->block_size];
|
||||
} *tmp = os_malloc (sizeof (*tmp));
|
||||
if (!tmp)
|
||||
return ENOMEM;
|
||||
|
||||
mi->create (tmp->ctx);
|
||||
crypto_hmac_begin (tmp->ctx, mi, key, key_len, tmp->k_opad);
|
||||
mi->update (tmp->ctx, data, data_len);
|
||||
crypto_hmac_finalize (tmp->ctx, mi, tmp->k_opad, digest);
|
||||
|
||||
os_free (tmp);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -66,7 +66,35 @@ int crypto_hash (const digest_mech_info_t *mi, const char *data, size_t data_len
|
|||
int crypto_fhash (const digest_mech_info_t *mi, read_fn read, int readarg, uint8_t *digest);
|
||||
|
||||
/**
|
||||
* Generate a HMAC signature.
|
||||
* Commence calculating a HMAC signature.
|
||||
*
|
||||
* Once this fuction returns successfully, the @c ctx may be updated with
|
||||
* data in multiple passes uses @c mi->update(), before being finalized via
|
||||
* @c crypto_hmac_finalize().
|
||||
*
|
||||
* @param ctx A created context for the given mech @c mi.
|
||||
* @param mi A mech from @c crypto_digest_mech().
|
||||
* @param key The key bytes to use.
|
||||
* @param key_len Number of bytes the @c key comprises.
|
||||
* @param k_opad Buffer of size @c mi->block_size bytes to store the second
|
||||
* round of key material in.
|
||||
* Must be passed to @c crypto_hmac_finalize().
|
||||
*/
|
||||
void crypto_hmac_begin (void *ctx, const digest_mech_info_t *mi, const char *key, size_t key_len, uint8_t *k_opad);
|
||||
|
||||
/**
|
||||
* Finalizes calculating a HMAC signature.
|
||||
* @param ctx The created context used with @c crypto_hmac_begin().
|
||||
* @param mi The mech used with @c crypto_hmac_begin().
|
||||
* @param k_opad Second round of keying material, obtained
|
||||
* from @c crypto_hmac_begin().
|
||||
* @param digest Output buffer, must be at least @c mi->digest_size in size.
|
||||
*/
|
||||
void crypto_hmac_finalize (void *ctx, const digest_mech_info_t *mi, const uint8_t *k_opad, uint8_t *digest);
|
||||
|
||||
/**
|
||||
* Generate a HMAC signature in one pass.
|
||||
* Implemented in terms of @c crypto_hmac_begin() / @c crypto_hmac_end().
|
||||
* @param mi A mech from @c crypto_digest_mech(). A null pointer @c mi
|
||||
* is harmless, but will of course result in an error return.
|
||||
* @param data The data to generate a signature for.
|
||||
|
|
|
@ -9,11 +9,18 @@
|
|||
#include "vfs.h"
|
||||
#include "../crypto/digests.h"
|
||||
#include "../crypto/mech.h"
|
||||
#include "lmem.h"
|
||||
|
||||
#include "user_interface.h"
|
||||
|
||||
#include "rom.h"
|
||||
|
||||
typedef struct {
|
||||
const digest_mech_info_t *mech_info;
|
||||
void *ctx;
|
||||
uint8_t *k_opad;
|
||||
} digest_user_datum_t;
|
||||
|
||||
/**
|
||||
* hash = crypto.sha1(input)
|
||||
*
|
||||
|
@ -150,11 +157,6 @@ static int crypto_lhash (lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
typedef struct digest_user_datum_t {
|
||||
const digest_mech_info_t *mech_info;
|
||||
void *ctx;
|
||||
} digest_user_datum_t;
|
||||
|
||||
/* General Usage for extensible hash functions:
|
||||
* sha = crypto.new_hash("MD5")
|
||||
* sha.update("Data")
|
||||
|
@ -162,19 +164,30 @@ typedef struct digest_user_datum_t {
|
|||
* strdigest = crypto.toHex(sha.finalize())
|
||||
*/
|
||||
|
||||
/* crypto.new_hash("MECHTYPE") */
|
||||
static int crypto_new_hash (lua_State *L)
|
||||
#define WANT_HASH 0
|
||||
#define WANT_HMAC 1
|
||||
|
||||
static int crypto_new_hash_hmac (lua_State *L, int what)
|
||||
{
|
||||
const digest_mech_info_t *mi = crypto_digest_mech (luaL_checkstring (L, 1));
|
||||
if (!mi)
|
||||
return bad_mech (L);
|
||||
|
||||
void *ctx = os_malloc (mi->ctx_size);
|
||||
if (ctx==NULL)
|
||||
return bad_mem (L);
|
||||
size_t len = 0;
|
||||
const char *key = 0;
|
||||
uint8_t *k_opad = 0;
|
||||
if (what == WANT_HMAC)
|
||||
{
|
||||
key = luaL_checklstring (L, 2, &len);
|
||||
k_opad = luaM_malloc (L, mi->block_size);
|
||||
}
|
||||
void *ctx = luaM_malloc (L, mi->ctx_size);
|
||||
|
||||
mi->create (ctx);
|
||||
|
||||
if (what == WANT_HMAC)
|
||||
crypto_hmac_begin (ctx, mi, key, len, k_opad);
|
||||
|
||||
// create a userdataum with specific metatable
|
||||
digest_user_datum_t *dudat = (digest_user_datum_t *)lua_newuserdata(L, sizeof(digest_user_datum_t));
|
||||
luaL_getmetatable(L, "crypto.hash");
|
||||
|
@ -183,10 +196,24 @@ static int crypto_new_hash (lua_State *L)
|
|||
// Set pointers to the mechanics and CTX
|
||||
dudat->mech_info = mi;
|
||||
dudat->ctx = ctx;
|
||||
dudat->k_opad = k_opad;
|
||||
|
||||
return 1; // Pass userdata object back
|
||||
}
|
||||
|
||||
/* crypto.new_hash("MECHTYPE") */
|
||||
static int crypto_new_hash (lua_State *L)
|
||||
{
|
||||
return crypto_new_hash_hmac (L, WANT_HASH);
|
||||
}
|
||||
|
||||
/* crypto.new_hmac("MECHTYPE", "KEY") */
|
||||
static int crypto_new_hmac (lua_State *L)
|
||||
{
|
||||
return crypto_new_hash_hmac (L, WANT_HMAC);
|
||||
}
|
||||
|
||||
|
||||
/* Called as object, params:
|
||||
1 - userdata "this"
|
||||
2 - new string to add to the hash state */
|
||||
|
@ -197,7 +224,6 @@ static int crypto_hash_update (lua_State *L)
|
|||
size_t sl;
|
||||
|
||||
dudat = (digest_user_datum_t *)luaL_checkudata(L, 1, "crypto.hash");
|
||||
luaL_argcheck(L, dudat, 1, "crypto.hash expected");
|
||||
|
||||
const digest_mech_info_t *mi = dudat->mech_info;
|
||||
|
||||
|
@ -217,12 +243,14 @@ static int crypto_hash_finalize (lua_State *L)
|
|||
size_t sl;
|
||||
|
||||
dudat = (digest_user_datum_t *)luaL_checkudata(L, 1, "crypto.hash");
|
||||
luaL_argcheck(L, dudat, 1, "crypto.hash expected");
|
||||
|
||||
const digest_mech_info_t *mi = dudat->mech_info;
|
||||
|
||||
uint8_t digest[mi->digest_size]; // Allocate as local
|
||||
mi->finalize (digest, dudat->ctx);
|
||||
if (dudat->k_opad)
|
||||
crypto_hmac_finalize (dudat->ctx, mi, dudat->k_opad, digest);
|
||||
else
|
||||
mi->finalize (digest, dudat->ctx);
|
||||
|
||||
lua_pushlstring (L, digest, sizeof (digest));
|
||||
return 1;
|
||||
|
@ -235,9 +263,11 @@ static int crypto_hash_gcdelete (lua_State *L)
|
|||
digest_user_datum_t *dudat;
|
||||
|
||||
dudat = (digest_user_datum_t *)luaL_checkudata(L, 1, "crypto.hash");
|
||||
luaL_argcheck(L, dudat, 1, "crypto.hash expected");
|
||||
|
||||
os_free(dudat->ctx);
|
||||
// luaM_free() uses type info to obtain original size, so have to delve
|
||||
// one level deeper and explicitly pass the size due to void*
|
||||
luaM_realloc_ (L, dudat->ctx, dudat->mech_info->ctx_size, 0);
|
||||
luaM_free (L, dudat->k_opad);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -386,6 +416,7 @@ static const LUA_REG_TYPE crypto_map[] = {
|
|||
{ LSTRKEY( "fhash" ), LFUNCVAL( crypto_flhash ) },
|
||||
{ LSTRKEY( "new_hash" ), LFUNCVAL( crypto_new_hash ) },
|
||||
{ LSTRKEY( "hmac" ), LFUNCVAL( crypto_lhmac ) },
|
||||
{ LSTRKEY( "new_hmac" ), LFUNCVAL( crypto_new_hmac ) },
|
||||
{ LSTRKEY( "encrypt" ), LFUNCVAL( lcrypto_encrypt ) },
|
||||
{ LSTRKEY( "decrypt" ), LFUNCVAL( lcrypto_decrypt ) },
|
||||
{ LNILKEY, LNILVAL }
|
||||
|
|
|
@ -5,6 +5,16 @@
|
|||
|
||||
The crypto modules provides various functions for working with cryptographic algorithms.
|
||||
|
||||
The following encryption/decryption algorithms/modes are supported:
|
||||
- `"AES-ECB"` for 128-bit AES in ECB mode (NOT recommended)
|
||||
- `"AES-CBC"` for 128-bit AES in CBC mode
|
||||
|
||||
The following hash algorithms are supported:
|
||||
- MD2 (not available by default, has to be explicitly enabled in `app/include/user_config.h`)
|
||||
- MD5
|
||||
- SHA1
|
||||
- SHA256, SHA384, SHA512 (unless disabled in `app/include/user_config.h`)
|
||||
|
||||
## crypto.encrypt()
|
||||
|
||||
Encrypts Lua strings.
|
||||
|
@ -13,9 +23,7 @@ Encrypts Lua strings.
|
|||
`crypto.encrypt(algo, key, plain [, iv])`
|
||||
|
||||
#### Parameters
|
||||
- `algo` the name of the encryption algorithm to use, one of
|
||||
- `"AES-ECB"` for 128-bit AES in ECB mode
|
||||
- `"AES-CBC"` for 128-bit AES in CBC mode
|
||||
- `algo` the name of a supported encryption algorithm to use
|
||||
- `key` the encryption key as a string; for AES encryption this *MUST* be 16 bytes long
|
||||
- `plain` the string to encrypt; it will be automatically zero-padded to a 16-byte boundary if necessary
|
||||
- `iv` the initilization vector, if using AES-CBC; defaults to all-zero if not given
|
||||
|
@ -40,9 +48,7 @@ Decrypts previously encrypted data.
|
|||
`crypto.decrypt(algo, key, cipher [, iv])`
|
||||
|
||||
#### Parameters
|
||||
- `algo` the name of the encryption algorithm to use, one of
|
||||
- `"AES-ECB"` for 128-bit AES in ECB mode
|
||||
- `"AES-CBC"` for 128-bit AES in CBC mode
|
||||
- `algo` the name of a supported encryption algorithm to use
|
||||
- `key` the encryption key as a string; for AES encryption this *MUST* be 16 bytes long
|
||||
- `cipher` the cipher text to decrypt (as obtained from `crypto.encrypt()`)
|
||||
- `iv` the initilization vector, if using AES-CBC; defaults to all-zero if not given
|
||||
|
@ -75,13 +81,6 @@ Compute a cryptographic hash of a a file.
|
|||
- `algo` the hash algorithm to use, case insensitive string
|
||||
- `filename` the path to the file to hash
|
||||
|
||||
Supported hash algorithms are:
|
||||
|
||||
- MD2 (not available by default, has to be explicitly enabled in `app/include/user_config.h`)
|
||||
- MD5
|
||||
- SHA1
|
||||
- SHA256, SHA384, SHA512 (unless disabled in `app/include/user_config.h`)
|
||||
|
||||
#### Returns
|
||||
A binary string containing the message digest. To obtain the textual version (ASCII hex characters), please use [`crypto.toHex()`](#cryptotohex ).
|
||||
|
||||
|
@ -101,13 +100,6 @@ Compute a cryptographic hash of a Lua string.
|
|||
`algo` the hash algorithm to use, case insensitive string
|
||||
`str` string to hash contents of
|
||||
|
||||
Supported hash algorithms are:
|
||||
|
||||
- MD2 (not available by default, has to be explicitly enabled in `app/include/user_config.h`)
|
||||
- MD5
|
||||
- SHA1
|
||||
- SHA256, SHA384, SHA512 (unless disabled in `app/include/user_config.h`)
|
||||
|
||||
#### Returns
|
||||
A binary string containing the message digest. To obtain the textual version (ASCII hex characters), please use [`crypto.toHex()`](#cryptotohex ).
|
||||
|
||||
|
@ -126,13 +118,6 @@ Create a digest/hash object that can have any number of strings added to it. Obj
|
|||
#### Parameters
|
||||
`algo` the hash algorithm to use, case insensitive string
|
||||
|
||||
Supported hash algorithms are:
|
||||
|
||||
- MD2 (not available by default, has to be explicitly enabled in `app/include/user_config.h`)
|
||||
- MD5
|
||||
- SHA1
|
||||
- SHA256, SHA384, SHA512 (unless disabled in `app/include/user_config.h`)
|
||||
|
||||
#### Returns
|
||||
Userdata object with `update` and `finalize` functions available.
|
||||
|
||||
|
@ -157,13 +142,6 @@ Compute a [HMAC](https://en.wikipedia.org/wiki/Hash-based_message_authentication
|
|||
- `str` data to calculate the hash for
|
||||
- `key` key to use for signing, may be a binary string
|
||||
|
||||
Supported hash algorithms are:
|
||||
|
||||
- MD2 (not available by default, has to be explicitly enabled in `app/include/user_config.h`)
|
||||
- MD5
|
||||
- SHA1
|
||||
- SHA256, SHA384, SHA512 (unless disabled in `app/include/user_config.h`)
|
||||
|
||||
#### Returns
|
||||
A binary string containing the HMAC signature. Use [`crypto.toHex()`](#cryptotohex ) to obtain the textual version.
|
||||
|
||||
|
@ -172,6 +150,30 @@ A binary string containing the HMAC signature. Use [`crypto.toHex()`](#cryptotoh
|
|||
print(crypto.toHex(crypto.hmac("sha1","abc","mysecret")))
|
||||
```
|
||||
|
||||
## crypto.new_hmac()
|
||||
|
||||
Create a hmac object that can have any number of strings added to it. Object has `update` and `finalize` functions.
|
||||
|
||||
#### Syntax
|
||||
`hmacobj = crypto.new_hmac(algo, key)`
|
||||
|
||||
#### Parameters
|
||||
- `algo` the hash algorithm to use, case insensitive string
|
||||
- `key` the key to use (may be a binary string)
|
||||
|
||||
#### Returns
|
||||
Userdata object with `update` and `finalize` functions available.
|
||||
|
||||
#### Example
|
||||
```lua
|
||||
hmacobj = crypto.new_hmac("SHA1", "s3kr3t")
|
||||
hmacobj:update("FirstString"))
|
||||
hmacobj:update("SecondString"))
|
||||
digest = hmacobj:finalize()
|
||||
print(crypto.toHex(digest))
|
||||
```
|
||||
|
||||
|
||||
## crypto.mask()
|
||||
|
||||
Applies an XOR mask to a Lua string. Note that this is not a proper cryptographic mechanism, but some protocols may use it nevertheless.
|
||||
|
|
Loading…
Reference in New Issue