NTRU_IoT/legacy-code/README

256 lines
8.6 KiB
Plaintext
Raw Permalink Normal View History

2022-02-01 11:45:47 -05:00
Some notes on using libntruencrypt.
Providing a source of randomness
================================
libntruencrypt needs a cryptographically secure source of random bits!
The library contains an internal deterministic random bit generator (DRBG)
that can be used to whiten an external random bit source that is of low
entropy. However, if a source of cryptographically random bits is available
(such as /dev/urandom on Linux) it can be used directly without whitening.
The mechanism is selected by calling one of two instantiation functions:
DRBG_HANDLE handle;
ntru_crypto_drbg_instantiate(..., &handle); /* HMAC based DRBG */
--or--
ntru_crypto_drbg_external_instantiate(..., &handle); /* External Source */
The later interface is substantially simpler, and is preferable on most
platforms. The following two sections describe how to use the interfaces.
Regardless of the instantiation method, a DRBG handle is destroyed by calling
ntru_crypto_drbg_uninstantiate(&handle);
Note: If you use NTRU for quantum resistance and use an external DRBG, make sure
it is instantiated with sufficient entropy! For security of k bits you should
instantiate your DRBG with 2*k bits of entropy from the external source. The
internal DRBG does this for you.
HMAC-DRBG
=========
One of the inputs to ntru_crypto_drbg_instantiate is an ENTROPY_FN. If you use
the internal HMAC-DRBG it is imperative that you write your entropy function
correctly. ENTROPY_FN is typedef'd as
typedef uint8_t (*ENTROPY_FN)(ENTROPY_CMD cmd, uint8_t *out);
and an ENTROPY_CMD is one of
INIT,
GET_NUM_BYTES_PER_BYTE_OF_ENTROPY
GET_BYTE_OF_ENTROPY.
On input INIT your entropy function must perform any initialization of your
external source that is necessary and return 1 on success or 0 on failure.
On GET_NUM_BYTES_PER_BYTE_OF_ENTROPY your entropy function must output (by
setting `out') a value between 1 and 8 representing the entropy of your
random source. A value of k indicates that the one cryptographically random
byte can be extracted from k bytes of output from your source. For instance
an output of 1 indicates that the source is perfectly random, and an output
of 8 indicates that you can only extract one bit of randomness from each byte
of your source's output. Your entropy function should return 1 indicating
success.
On GET_BYTE_OF_ENTROPY your function must put one byte of output from your
random source in `out' and return 1 on success, 0 on failure.
Example: Suppose your platform provides a getrandombyte function
int getrandombyte(void *out);
that outputs 1 perfectly random byte at out and returns 0 on success. The
following is a reasonable ENTROPY_FN:
uint8_t
get_entropy(
ENTROPY_CMD cmd,
uint8_t *out)
{
if (cmd == INIT)
return 1;
if (out == NULL)
return 0;
if (cmd == GET_NUM_BYTES_PER_BYTE_OF_ENTROPY)
{
*out = 1;
return 1;
}
if (cmd == GET_BYTE_OF_ENTROPY)
{
if(0 == getrandombyte(out))
return 1;
}
return 0;
}
To use your get_entropy function:
uint32_t rc;
DRBG_HANDLE handle;
uint32_t sec_strength = 256;
rc = ntru_crypto_drbg_instantiate(sec_strength, NULL, 0,
&get_entropy, &handle);
if(rc != DRBG_RESULT(DRBG_OK))
{ ... }
The internal HMAC-DRBG is seeded with 3/2 * sec_strength * k bits of input
from get_entropy where k is the value returned by
get_entropy(GET_NUM_BYTES_PER...).
The maximum value of sec_strength is 256.
The second and third arguments are for specifying an optional
'personalization string' of up to 32 bytes of non-secret data that are to be
used in conjunction with the entropy source to seed the DRBG (see NIST SP
900-80A for details).
External random sources
=======================
If you trust an external random source, for example because you are using
libntruencrypt inside of a larger crypto suite that provides a random source,
then you can use that source directly.
One of the inputs to ntru_crypto_drbg_external_instantiate is a pointer to
a RANDOM_BYTES_FN, typedef'd as
typedef uint32_t (*RANDOM_BYTES_FN)(uint8_t *out, uint32_t num_bytes);
To use an external random source you simply wrap it in an RANDOM_BYTES_FN.
Example: Suppose your platform provides a getrandom function
int getrandom(void *buf, size_t buflen);
that accepts a buflen between 1 and 256 and returns either the number of
bytes output or -1 on failure.
#include "ntru_crypto_drbg.h"
...
uint32_t randombytes(uint8_t *out, uint32_t num_bytes)
{
size_t i;
while(num_bytes > 0)
{
if(num_bytes > 256) {
i = 256;
} else {
i = num_bytes;
}
i = getrandom(out, i);
if(i == -1)
DRBG_RET(DRBG_ENTROPY_FAIL);
num_bytes -= i;
out += i;
}
DRBG_RET(DRBG_OK);
}
Note the use of DRBG_RET. This is required.
To use your randombytes function:
uint32_t rc;
DRBG_HANDLE handle;
rc = ntru_crypto_drbg_external_instantiate(&randombytesfn, &handle);
if(rc != DRBG_RESULT(DRBG_OK))
{ ... }
Parameter sets
==============
libntruencrypt provides all of the NTRUEncrypt parameter sets defined in the
IEEE 1363.1 standard -- a superset of those defined in X9.98. In the table
below the line labeled Product contains the parameter sets that are unique to
1363.1. These parameter sets are also faster and more compact than the other
sets in their respective columns, and these sets are preferable unless X9.98
compatibility is required. The column headers denote estimated bit security.
112 128 192 256
Product NTRU_EES401EP2 NTRU_EES439EP1 NTRU_EES593EP1 NTRU_EES743EP1
Size NTRU_EES401EP1 NTRU_EES449EP1 NTRU_EES677EP1 NTRU_EES1087EP2
Balanced NTRU_EES541EP1 NTRU_EES613EP1 NTRU_EES887EP1 NTRU_EES1171EP1
Speed NTRU_EES659EP1 NTRU_EES761EP1 NTRU_EES1087EP1 NTRU_EES1499EP1
Cryptographic functions
=======================
All of the cryptographic functions support two calling mechanisms. One to
obtain the lengths of any buffers that need to be allocated before performing
the operation, and a second to actually perform the operation
The DRBG inputs to keygen and encrypt are ignored when getting the buffer
lengths, and the DRBG need not be initialized at that time.
Keygen
NULL public_key requests public_key_len, NULL private_key requests
private_key_len. drbg argument is ignored.
Example:
/* Get public/private key buffer sizes */
rc = ntru_crypto_ntru_encrypt_keygen(drbg, NTRU_EES401EP2,
&public_key_len, NULL,
&private_key_len, NULL);
if(rc != NTRU_RESULT(NTRU_OK)) {...}
/* Allocate memory for keys */
...
/* Perform the key generation */
rc = ntru_crypto_ntru_encrypt_keygen(drbg, NTRU_EES401EP2,
&public_key_len, public_key,
&private_key_len, private_key);
if(rc != NTRU_RESULT(NTRU_OK)) {...}
Encrypt
NULL ciphertext requests length, drbg, plaintext_len and plaintext arguments
are ignored.
Example:
/* Get the ciphertext buffer size */
rc = ntru_crypto_ntru_encrypt(drbg, public_key_len, public_key,
0, NULL,
&ciphertext_len, NULL);
if(rc != NTRU_RESULT(NTRU_OK)) {...}
/* Allocate memory for ciphertext */
...
/* Perform the encryption */
rc = ntru_crypto_ntru_encrypt(drbg, public_key_len, public_key,
message_len, message,
&ciphertext_len, ciphertext);
if(rc != NTRU_RESULT(NTRU_OK)) {...}
Decrypt
NULL plaintext requests length, ciphertext_len and ciphertext arguments
are ignored.
Example:
/* Get maximum plaintext length */
rc = ntru_crypto_ntru_decrypt(private_key_len, private_key,
0, NULL,
&max_msg_len, NULL);
/* Allocate memory for plaintext */
...
/* Perform the encryption.
* Note that plaintext_len will contain the actual output length
* on success
*/
rc = ntru_crypto_ntru_decrypt(private_key_len, private_key,
ciphertext_len, ciphertext,
&plaintext_len, plaintext);
if(rc != NTRU_RESULT(NTRU_OK)) {...}