nts: add support for NTP authenticator field using AES-GCM-SIV
Add support for SIV algorithms which have maximum nonce length shorter than 16 bytes.
This commit is contained in:
parent
ec89739d50
commit
73042494bd
3 changed files with 85 additions and 61 deletions
|
@ -61,23 +61,25 @@ get_padded_length(int length)
|
||||||
|
|
||||||
int
|
int
|
||||||
NNA_GenerateAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
|
NNA_GenerateAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
|
||||||
const unsigned char *nonce, int nonce_length,
|
const unsigned char *nonce, int max_nonce_length,
|
||||||
const unsigned char *plaintext, int plaintext_length,
|
const unsigned char *plaintext, int plaintext_length,
|
||||||
int min_ef_length)
|
int min_ef_length)
|
||||||
{
|
{
|
||||||
int auth_length, ciphertext_length, assoc_length;
|
int auth_length, ciphertext_length, assoc_length, nonce_length, max_siv_nonce_length;
|
||||||
int nonce_padding, ciphertext_padding, additional_padding;
|
int nonce_padding, ciphertext_padding, additional_padding;
|
||||||
unsigned char *ciphertext, *body;
|
unsigned char *ciphertext, *body;
|
||||||
struct AuthHeader *header;
|
struct AuthHeader *header;
|
||||||
|
|
||||||
assert(sizeof (*header) == 4);
|
assert(sizeof (*header) == 4);
|
||||||
|
|
||||||
if (nonce_length <= 0 || plaintext_length < 0) {
|
if (max_nonce_length <= 0 || plaintext_length < 0) {
|
||||||
DEBUG_LOG("Invalid nonce/plaintext length");
|
DEBUG_LOG("Invalid nonce/plaintext length");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
assoc_length = info->length;
|
assoc_length = info->length;
|
||||||
|
max_siv_nonce_length = SIV_GetMaxNonceLength(siv);
|
||||||
|
nonce_length = MIN(max_nonce_length, max_siv_nonce_length);
|
||||||
ciphertext_length = SIV_GetTagLength(siv) + plaintext_length;
|
ciphertext_length = SIV_GetTagLength(siv) + plaintext_length;
|
||||||
nonce_padding = get_padding_length(nonce_length);
|
nonce_padding = get_padding_length(nonce_length);
|
||||||
ciphertext_padding = get_padding_length(ciphertext_length);
|
ciphertext_padding = get_padding_length(ciphertext_length);
|
||||||
|
@ -86,8 +88,8 @@ NNA_GenerateAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
|
||||||
auth_length = sizeof (*header) + nonce_length + nonce_padding +
|
auth_length = sizeof (*header) + nonce_length + nonce_padding +
|
||||||
ciphertext_length + ciphertext_padding;
|
ciphertext_length + ciphertext_padding;
|
||||||
additional_padding = MAX(min_ef_length - auth_length - 4, 0);
|
additional_padding = MAX(min_ef_length - auth_length - 4, 0);
|
||||||
additional_padding = MAX(NTS_MIN_UNPADDED_NONCE_LENGTH - nonce_length - nonce_padding,
|
additional_padding = MAX(MIN(NTS_MIN_UNPADDED_NONCE_LENGTH, max_siv_nonce_length) -
|
||||||
additional_padding);
|
nonce_length - nonce_padding, additional_padding);
|
||||||
auth_length += additional_padding;
|
auth_length += additional_padding;
|
||||||
|
|
||||||
if (!NEF_AddBlankField(packet, info, NTP_EF_NTS_AUTH_AND_EEF, auth_length,
|
if (!NEF_AddBlankField(packet, info, NTP_EF_NTS_AUTH_AND_EEF, auth_length,
|
||||||
|
@ -127,7 +129,7 @@ int
|
||||||
NNA_DecryptAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv, int ef_start,
|
NNA_DecryptAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv, int ef_start,
|
||||||
unsigned char *plaintext, int buffer_length, int *plaintext_length)
|
unsigned char *plaintext, int buffer_length, int *plaintext_length)
|
||||||
{
|
{
|
||||||
int siv_tag_length, nonce_length, ciphertext_length;
|
int siv_tag_length, max_siv_nonce_length, nonce_length, ciphertext_length;
|
||||||
unsigned char *nonce, *ciphertext;
|
unsigned char *nonce, *ciphertext;
|
||||||
int ef_type, ef_body_length;
|
int ef_type, ef_body_length;
|
||||||
void *ef_body;
|
void *ef_body;
|
||||||
|
@ -155,6 +157,7 @@ NNA_DecryptAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv, in
|
||||||
nonce = (unsigned char *)(header + 1);
|
nonce = (unsigned char *)(header + 1);
|
||||||
ciphertext = nonce + get_padded_length(nonce_length);
|
ciphertext = nonce + get_padded_length(nonce_length);
|
||||||
|
|
||||||
|
max_siv_nonce_length = SIV_GetMaxNonceLength(siv);
|
||||||
siv_tag_length = SIV_GetTagLength(siv);
|
siv_tag_length = SIV_GetTagLength(siv);
|
||||||
|
|
||||||
if (nonce_length < 1 ||
|
if (nonce_length < 1 ||
|
||||||
|
@ -164,8 +167,8 @@ NNA_DecryptAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv, in
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ef_body_length < sizeof (*header) +
|
if (sizeof (*header) + MIN(NTS_MIN_UNPADDED_NONCE_LENGTH, max_siv_nonce_length) +
|
||||||
NTS_MIN_UNPADDED_NONCE_LENGTH + get_padded_length(ciphertext_length)) {
|
get_padded_length(ciphertext_length) > ef_body_length) {
|
||||||
DEBUG_LOG("Missing padding");
|
DEBUG_LOG("Missing padding");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#include "siv.h"
|
#include "siv.h"
|
||||||
|
|
||||||
extern int NNA_GenerateAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
|
extern int NNA_GenerateAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
|
||||||
const unsigned char *nonce, int nonce_length,
|
const unsigned char *nonce, int max_nonce_length,
|
||||||
const unsigned char *plaintext, int plaintext_length,
|
const unsigned char *plaintext, int plaintext_length,
|
||||||
int min_ef_length);
|
int min_ef_length);
|
||||||
|
|
||||||
|
|
|
@ -34,74 +34,95 @@ test_unit(void)
|
||||||
unsigned char key[SIV_MAX_KEY_LENGTH], nonce[256], plaintext[256], plaintext2[256];
|
unsigned char key[SIV_MAX_KEY_LENGTH], nonce[256], plaintext[256], plaintext2[256];
|
||||||
NTP_PacketInfo info;
|
NTP_PacketInfo info;
|
||||||
NTP_Packet packet;
|
NTP_Packet packet;
|
||||||
|
SIV_Algorithm algo;
|
||||||
SIV_Instance siv;
|
SIV_Instance siv;
|
||||||
int i, j, r, packet_length, nonce_length, key_length;
|
int i, j, r, packet_length, nonce_length, key_length;
|
||||||
int plaintext_length, plaintext2_length, min_ef_length;
|
int plaintext_length, plaintext2_length, min_ef_length;
|
||||||
|
|
||||||
siv = SIV_CreateInstance(AEAD_AES_SIV_CMAC_256);
|
for (algo = 1; algo < 100; algo++) {
|
||||||
TEST_CHECK(siv);
|
siv = SIV_CreateInstance(algo);
|
||||||
|
if (!siv) {
|
||||||
|
TEST_CHECK(algo != AEAD_AES_SIV_CMAC_256);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < 10000; i++) {
|
DEBUG_LOG("algo=%d", (int)algo);
|
||||||
key_length = SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256);
|
|
||||||
for (j = 0; j < key_length; j++)
|
|
||||||
key[j] = random() % 256;
|
|
||||||
TEST_CHECK(SIV_SetKey(siv, key, key_length));
|
|
||||||
|
|
||||||
nonce_length = random() % sizeof (nonce) + 1;
|
for (i = 0; i < 10000; i++) {
|
||||||
for (j = 0; j < nonce_length; j++)
|
key_length = SIV_GetKeyLength(algo);
|
||||||
nonce[j] = random() % 256;
|
for (j = 0; j < key_length; j++)
|
||||||
|
key[j] = random() % 256;
|
||||||
|
TEST_CHECK(SIV_SetKey(siv, key, key_length));
|
||||||
|
|
||||||
plaintext_length = random() % (sizeof (plaintext) + 1);
|
assert(sizeof (nonce) >= SIV_GetMinNonceLength(siv));
|
||||||
for (j = 0; j < plaintext_length; j++)
|
nonce_length = SIV_GetMinNonceLength(siv) +
|
||||||
plaintext[j] = random() % 256;
|
random() % (MIN(sizeof (nonce), SIV_GetMaxNonceLength(siv)) -
|
||||||
|
SIV_GetMinNonceLength(siv) + 1);
|
||||||
|
for (j = 0; j < nonce_length; j++)
|
||||||
|
nonce[j] = random() % 256;
|
||||||
|
|
||||||
packet_length = NTP_HEADER_LENGTH + random() % 100 * 4;
|
plaintext_length = random() % (sizeof (plaintext) + 1);
|
||||||
min_ef_length = random() % (sizeof (packet) - packet_length);
|
for (j = 0; j < plaintext_length; j++)
|
||||||
|
plaintext[j] = random() % 256;
|
||||||
|
|
||||||
memset(&packet, 0, sizeof (packet));
|
packet_length = NTP_HEADER_LENGTH + random() % 100 * 4;
|
||||||
packet.lvm = NTP_LVM(0, 4, 0);
|
min_ef_length = random() % (sizeof (packet) - packet_length);
|
||||||
memset(&info, 0, sizeof (info));
|
|
||||||
info.version = 4;
|
|
||||||
info.length = packet_length;
|
|
||||||
|
|
||||||
DEBUG_LOG("packet_length=%d nonce_length=%d plaintext_length=%d min_ef_length=%d",
|
memset(&packet, 0, sizeof (packet));
|
||||||
packet_length, nonce_length, plaintext_length, min_ef_length);
|
packet.lvm = NTP_LVM(0, 4, 0);
|
||||||
|
memset(&info, 0, sizeof (info));
|
||||||
|
info.version = 4;
|
||||||
|
info.length = packet_length;
|
||||||
|
|
||||||
r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, nonce_length, plaintext,
|
DEBUG_LOG("packet_length=%d nonce_length=%d plaintext_length=%d min_ef_length=%d",
|
||||||
-1, 0);
|
packet_length, nonce_length, plaintext_length, min_ef_length);
|
||||||
TEST_CHECK(!r);
|
|
||||||
r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, 0, plaintext,
|
|
||||||
plaintext_length, 0);
|
|
||||||
TEST_CHECK(!r);
|
|
||||||
r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, nonce_length, plaintext,
|
|
||||||
plaintext_length, sizeof (packet) - info.length + 1);
|
|
||||||
TEST_CHECK(!r);
|
|
||||||
|
|
||||||
r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, nonce_length, plaintext,
|
r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, nonce_length, plaintext,
|
||||||
plaintext_length, min_ef_length);
|
-1, 0);
|
||||||
TEST_CHECK(r);
|
TEST_CHECK(!r);
|
||||||
TEST_CHECK(info.length - packet_length >= min_ef_length);
|
r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, 0, plaintext,
|
||||||
|
plaintext_length, 0);
|
||||||
|
TEST_CHECK(!r);
|
||||||
|
if (SIV_GetMinNonceLength(siv) > 1) {
|
||||||
|
r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, SIV_GetMinNonceLength(siv) - 1,
|
||||||
|
plaintext, plaintext_length, 0);
|
||||||
|
TEST_CHECK(!r);
|
||||||
|
}
|
||||||
|
if (SIV_GetMaxNonceLength(siv) <= sizeof (nonce)) {
|
||||||
|
r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, SIV_GetMaxNonceLength(siv) - 1,
|
||||||
|
plaintext, plaintext_length, 0);
|
||||||
|
TEST_CHECK(!r);
|
||||||
|
}
|
||||||
|
r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, nonce_length, plaintext,
|
||||||
|
plaintext_length, sizeof (packet) - info.length + 1);
|
||||||
|
TEST_CHECK(!r);
|
||||||
|
|
||||||
r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
|
r = NNA_GenerateAuthEF(&packet, &info, siv, nonce, nonce_length, plaintext,
|
||||||
-1, &plaintext2_length);
|
plaintext_length, min_ef_length);
|
||||||
TEST_CHECK(!r);
|
TEST_CHECK(r);
|
||||||
|
TEST_CHECK(info.length - packet_length >= min_ef_length);
|
||||||
|
|
||||||
r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
|
r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
|
||||||
sizeof (plaintext2), &plaintext2_length);
|
-1, &plaintext2_length);
|
||||||
TEST_CHECK(r);
|
TEST_CHECK(!r);
|
||||||
TEST_CHECK(plaintext_length == plaintext2_length);
|
|
||||||
TEST_CHECK(memcmp(plaintext, plaintext2, plaintext_length) == 0);
|
|
||||||
|
|
||||||
j = random() % (packet_length + plaintext_length +
|
r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
|
||||||
nonce_length + SIV_GetTagLength(siv) + 8) / 4 * 4;
|
sizeof (plaintext2), &plaintext2_length);
|
||||||
((unsigned char *)&packet)[j]++;
|
TEST_CHECK(r);
|
||||||
r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
|
TEST_CHECK(plaintext_length == plaintext2_length);
|
||||||
sizeof (plaintext2), &plaintext2_length);
|
TEST_CHECK(memcmp(plaintext, plaintext2, plaintext_length) == 0);
|
||||||
TEST_CHECK(!r);
|
|
||||||
((unsigned char *)&packet)[j]--;
|
j = random() % (packet_length + plaintext_length +
|
||||||
|
nonce_length + SIV_GetTagLength(siv) + 8) / 4 * 4;
|
||||||
|
((unsigned char *)&packet)[j]++;
|
||||||
|
r = NNA_DecryptAuthEF(&packet, &info, siv, packet_length, plaintext2,
|
||||||
|
sizeof (plaintext2), &plaintext2_length);
|
||||||
|
TEST_CHECK(!r);
|
||||||
|
((unsigned char *)&packet)[j]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
SIV_DestroyInstance(siv);
|
||||||
}
|
}
|
||||||
|
|
||||||
SIV_DestroyInstance(siv);
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
void
|
void
|
||||||
|
|
Loading…
Reference in a new issue