Skip to content

Commit 2e9f2b5

Browse files
authored
Merge pull request #319 from libtom/add/SIV
Add SIV
2 parents c900951 + ad2696f commit 2e9f2b5

15 files changed

+1019
-29
lines changed

demos/timing.c

+39-4
Original file line numberDiff line numberDiff line change
@@ -1153,8 +1153,13 @@ static void time_macs(void)
11531153

11541154
static void time_encmacs_(unsigned long MAC_SIZE)
11551155
{
1156-
#if defined(LTC_EAX_MODE) || defined(LTC_OCB_MODE) || defined(LTC_OCB3_MODE) || defined(LTC_CCM_MODE) || defined(LTC_GCM_MODE)
1157-
unsigned char *buf, IV[16], key[16], tag[16];
1156+
#if defined(LTC_EAX_MODE) || defined(LTC_OCB_MODE) || defined(LTC_OCB3_MODE) || \
1157+
defined(LTC_CCM_MODE) || defined(LTC_GCM_MODE) || defined(LTC_SIV_MODE)
1158+
#if defined(LTC_SIV_MODE)
1159+
unsigned char *aad[4];
1160+
unsigned long buflen;
1161+
#endif
1162+
unsigned char *buf, IV[16], key[32], tag[16];
11581163
ulong64 t1, t2;
11591164
unsigned long x, z;
11601165
int err, cipher_idx;
@@ -1171,8 +1176,8 @@ static void time_encmacs_(unsigned long MAC_SIZE)
11711176
cipher_idx = find_cipher("aes");
11721177

11731178
yarrow_read(buf, MAC_SIZE*1024, &yarrow_prng);
1174-
yarrow_read(key, 16, &yarrow_prng);
1175-
yarrow_read(IV, 16, &yarrow_prng);
1179+
yarrow_read(key, sizeof(key), &yarrow_prng);
1180+
yarrow_read(IV, sizeof(IV), &yarrow_prng);
11761181

11771182
#ifdef LTC_EAX_MODE
11781183
t2 = -1;
@@ -1308,8 +1313,38 @@ __attribute__ ((aligned (16)))
13081313
}
13091314
fprintf(stderr, "GCM (precomp)\t\t%9"PRI64"u\n", t2/(ulong64)(MAC_SIZE*1024));
13101315
}
1316+
#endif
13111317

1318+
#ifdef LTC_SIV_MODE
1319+
for(z = 0; z < 4; z++) {
1320+
aad[z] = IV + z * 4;
1321+
}
1322+
for(z = 0; z < 4; z++) {
1323+
t2 = -1;
1324+
for (x = 0; x < 10000; x++) {
1325+
buflen = MAC_SIZE*1024;
1326+
t_start();
1327+
t1 = t_read();
1328+
if ((err = siv_memory(cipher_idx, LTC_ENCRYPT,
1329+
key, 32,
1330+
buf, MAC_SIZE*1024 - 16,
1331+
buf, &buflen,
1332+
aad[0], 16,
1333+
aad[1], 12,
1334+
aad[2], 8,
1335+
aad[3], 4,
1336+
NULL)) != CRYPT_OK) {
1337+
fprintf(stderr, "\nSIV error... %s\n", error_to_string(err));
1338+
exit(EXIT_FAILURE);
1339+
}
1340+
t1 = t_read() - t1;
1341+
if (t1 < t2) t2 = t1;
1342+
}
1343+
aad[3-z] = NULL;
1344+
fprintf(stderr, "SIV (%lu x AAD)\t\t%9"PRI64"u\n", 4-z, t2/(ulong64)(MAC_SIZE*1024));
1345+
}
13121346
#endif
1347+
13131348
XFREE(buf);
13141349
#else
13151350
LTC_UNUSED_PARAM(MAC_SIZE);

doc/crypt.tex

+160
Original file line numberDiff line numberDiff line change
@@ -2576,6 +2576,166 @@ \subsection{One--Shot Packet}
25762576
In order to enable OpenSSH compatibility, the flag \textit{CHACHA20POLY1305\_OPENSSH\_COMPAT} has to be \textbf{OR}'ed into
25772577
the \textit{direction} parameter.
25782578

2579+
2580+
\mysection{SIV}
2581+
\label{SIV}
2582+
2583+
The SIV (Synthetic Initialization Vector) authenticated encryption is a block cipher mode of encryption
2584+
defined by \url{https://tools.ietf.org/html/rfc5297}.
2585+
2586+
In contrast to all the other AEAD modes, SIV provides no iterative API. Instead it only provides one--shot APIs.
2587+
2588+
AEAD algorithm design usually suggests using a separate Nonce (also called IV) and additional authenticated Data (AAD).
2589+
SIV treats this slightly different and does not enforce any of the two, but leaves it up to the user.
2590+
Also SIV allows passing multiple sets of data as AAD, up to a maximum of \texttt{126} elements.
2591+
In case one wants to use a Nonce in a classical style it is suggested to pass it as the last of the AAD elements,
2592+
thereby limiting the number of AAD to \texttt{125}.
2593+
2594+
\subsection{Encryption / Decryption}
2595+
To encrypt and create a tag resp. decrypt and check the tag, the following API functions can be used.
2596+
2597+
\index{siv\_encrypt\_memory()}
2598+
\begin{verbatim}
2599+
int siv_encrypt_memory( int cipher,
2600+
const unsigned char *key, unsigned long keylen,
2601+
const unsigned char *ad[], unsigned long adlen[],
2602+
const unsigned char *pt, unsigned long ptlen,
2603+
unsigned char *ct, unsigned long *ctlen);
2604+
\end{verbatim}
2605+
This encrypts the data where \textit{pt} is the plaintext and \textit{ct} is the ciphertext.
2606+
The length of the plaintext is given in \textit{ptlen} and the length of the ciphertext is given in \textit{ctlen}.
2607+
\textit{ctlen} shall contain the max buffer size allocated at \textit{ct} on input, and will be updated with the
2608+
written length on successful encryption.
2609+
2610+
The buffer of \textit{ct} shall be at least \texttt{ptlen + 16} bytes wide.
2611+
2612+
The key to the encrypt operation is passed in \textit{key} of length \textit{keylen}.
2613+
2614+
The AAD is passed as array of pointers in \textit{ad}. The length of each AAD is passed as array of
2615+
\textit{unsigned long} in \textit{adlen}.
2616+
As soon as an array element of \textit{ad} is hit which equals \texttt{NULL} or an array element of \textit{adlen}
2617+
is hit which equals \texttt{0}, processing of the AAD is stopped.
2618+
2619+
\index{siv\_decrypt\_memory()}
2620+
\begin{verbatim}
2621+
int siv_decrypt_memory( int cipher,
2622+
const unsigned char *key, unsigned long keylen,
2623+
const unsigned char *ad[], unsigned long adlen[],
2624+
const unsigned char *ct, unsigned long ctlen,
2625+
unsigned char *pt, unsigned long *ptlen);
2626+
\end{verbatim}
2627+
This decrypts the data where \textit{ct} is the ciphertext of length \textit{ctlen} and \textit{pt} is the plaintext of length \textit{ptlen}.
2628+
\textit{ptlen} shall contain the max buffer size allocated at \textit{pt} on input, and will be updated with the
2629+
written lenth on successful decryption.
2630+
2631+
The buffer of \textit{pt} shall be at least \texttt{ctlen - 16} bytes wide.
2632+
2633+
The AAD is processed in the same way as in the encrypt function.
2634+
2635+
An example of encryption and decryption with SIV using multiple AAD and a Nonce is given below.
2636+
2637+
\begin{small}
2638+
\begin{verbatim}
2639+
#include <tomcrypt.h>
2640+
2641+
int main(void)
2642+
{
2643+
int err;
2644+
unsigned char plain[16] = {0};
2645+
unsigned char ct[sizeof(plain) + 16] = {0};
2646+
unsigned long plainlen = sizeof(plain), ctlen = sizeof(ct);
2647+
2648+
register_cipher(&aes_desc);
2649+
2650+
/* We need to cast the AAD strings because the API asks for an `unsigned char*`
2651+
* but a string is on most platforms defined as a "signed" `char*`. */
2652+
if ((err = siv_encrypt_memory(find_cipher("aes"),
2653+
((unsigned char[32]) {0x0}), 32,
2654+
((const unsigned char*[]) {(void*)"aad0", (void*)"aad1",
2655+
(void*)"NONCE", NULL}),
2656+
((unsigned long[]) {4, 4, 5, 0}),
2657+
plain, plainlen,
2658+
ct, &ctlen)) != CRYPT_OK) {
2659+
whine_and_pout(err);
2660+
}
2661+
2662+
if ((err = siv_decrypt_memory(find_cipher("aes"),
2663+
((unsigned char[32]) {0x0}), 32,
2664+
((const unsigned char*[]) {(void*)"aad0", (void*)"aad1",
2665+
(void*)"NONCE", NULL}),
2666+
((unsigned long[]) {4, 4, 5, 0}),
2667+
ct, ctlen,
2668+
plain, &plainlen)) != CRYPT_OK) {
2669+
whine_and_pout(err);
2670+
}
2671+
2672+
return EXIT_SUCCESS;
2673+
}
2674+
\end{verbatim}
2675+
\end{small}
2676+
2677+
\subsection{One--Shot Packet}
2678+
To process a single packet under any given key the following helper function can be used.
2679+
2680+
\index{siv\_memory()}
2681+
\begin{verbatim}
2682+
int siv_memory( int cipher, int direction,
2683+
const unsigned char *key, unsigned long keylen,
2684+
const unsigned char *in, unsigned long inlen,
2685+
unsigned char *out, unsigned long *outlen,
2686+
...);
2687+
\end{verbatim}
2688+
2689+
This will execute a SIV operation of the \textit{direction} (\texttt{LTC\_ENCRYPT} resp. \texttt{LTC\_DECRYPT})
2690+
using the \textit{cipher} with the \textit{key} of len \textit{keylen}.
2691+
The AAD is optionally passed as varargs of the form \textit{(const unsigned char*, unsigned long)}, which musst be
2692+
NULL terminated.
2693+
The input is passed via the \textit{in} argument of length \textit{inlen}.
2694+
The output is stored in the buffer pointer to by the \textit{out} argument where the length is passed as \textit{outlen}.
2695+
\textit{outlen} shall contain the initial size of the buffer behind \textit{out} when calling the function and on
2696+
return it will contain the written size.
2697+
2698+
In case the operation is \textit{encryption} the buffer of \textit{out} shall be at least \texttt{inlen + 16} bytes wide.
2699+
In the case of \textit{decryption} the buffer of \textit{out} shall be at least \texttt{inlen - 16} bytes wide.
2700+
2701+
An example of encryption and decryption with the one--shot API of SIV using multiple AAD is given below.
2702+
2703+
\begin{small}
2704+
\begin{verbatim}
2705+
#include <tomcrypt.h>
2706+
2707+
int main(void)
2708+
{
2709+
int err;
2710+
unsigned char plain[16] = {0};
2711+
unsigned char ct[sizeof(plain) + 16] = {0};
2712+
unsigned long plainlen = sizeof(plain), ctlen = sizeof(ct);
2713+
2714+
register_cipher(&aes_desc);
2715+
2716+
/* Note that constant length values must be suffixed by `uL` in order
2717+
* to operate correctly cross-platform. */
2718+
if ((err = siv_memory(find_cipher("aes"), LTC_ENCRYPT,
2719+
((unsigned char[32]) {0x0}), 32,
2720+
plain, plainlen,
2721+
ct, &ctlen,
2722+
"aad0", 4uL, "aad1", 4uL, "NONCE", 5uL, NULL)) != CRYPT_OK) {
2723+
whine_and_pout(err);
2724+
}
2725+
2726+
if ((err = siv_memory(find_cipher("aes"), LTC_DECRYPT,
2727+
((unsigned char[32]) {0x0}), 32,
2728+
ct, ctlen,
2729+
plain, &plainlen,
2730+
"aad0", 4uL, "aad1", 4uL, "NONCE", 5uL, NULL)) != CRYPT_OK) {
2731+
whine_and_pout(err);
2732+
}
2733+
2734+
return EXIT_SUCCESS;
2735+
}
2736+
\end{verbatim}
2737+
\end{small}
2738+
25792739
\chapter{One-Way Cryptographic Hash Functions}
25802740
\mysection{Core Functions}
25812741
Like the ciphers, there are hash core functions and a universal data type to hold the hash state called \textit{hash\_state}. To initialize hash

libtomcrypt_VS2008.vcproj

+8
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,14 @@
835835
>
836836
</File>
837837
</Filter>
838+
<Filter
839+
Name="siv"
840+
>
841+
<File
842+
RelativePath="src\encauth\siv\siv.c"
843+
>
844+
</File>
845+
</Filter>
838846
</Filter>
839847
<Filter
840848
Name="hashes"

makefile.mingw

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ src/encauth/ocb3/ocb3_add_aad.o src/encauth/ocb3/ocb3_decrypt.o src/encauth/ocb3
6464
src/encauth/ocb3/ocb3_decrypt_verify_memory.o src/encauth/ocb3/ocb3_done.o \
6565
src/encauth/ocb3/ocb3_encrypt.o src/encauth/ocb3/ocb3_encrypt_authenticate_memory.o \
6666
src/encauth/ocb3/ocb3_encrypt_last.o src/encauth/ocb3/ocb3_init.o src/encauth/ocb3/ocb3_int_ntz.o \
67-
src/encauth/ocb3/ocb3_int_xor_blocks.o src/encauth/ocb3/ocb3_test.o src/hashes/blake2b.o \
68-
src/hashes/blake2s.o src/hashes/chc/chc.o src/hashes/helper/hash_file.o \
67+
src/encauth/ocb3/ocb3_int_xor_blocks.o src/encauth/ocb3/ocb3_test.o src/encauth/siv/siv.o \
68+
src/hashes/blake2b.o src/hashes/blake2s.o src/hashes/chc/chc.o src/hashes/helper/hash_file.o \
6969
src/hashes/helper/hash_filehandle.o src/hashes/helper/hash_memory.o \
7070
src/hashes/helper/hash_memory_multi.o src/hashes/md2.o src/hashes/md4.o src/hashes/md5.o \
7171
src/hashes/rmd128.o src/hashes/rmd160.o src/hashes/rmd256.o src/hashes/rmd320.o src/hashes/sha1.o \

makefile.msvc

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ src/encauth/ocb3/ocb3_add_aad.obj src/encauth/ocb3/ocb3_decrypt.obj src/encauth/
5757
src/encauth/ocb3/ocb3_decrypt_verify_memory.obj src/encauth/ocb3/ocb3_done.obj \
5858
src/encauth/ocb3/ocb3_encrypt.obj src/encauth/ocb3/ocb3_encrypt_authenticate_memory.obj \
5959
src/encauth/ocb3/ocb3_encrypt_last.obj src/encauth/ocb3/ocb3_init.obj src/encauth/ocb3/ocb3_int_ntz.obj \
60-
src/encauth/ocb3/ocb3_int_xor_blocks.obj src/encauth/ocb3/ocb3_test.obj src/hashes/blake2b.obj \
61-
src/hashes/blake2s.obj src/hashes/chc/chc.obj src/hashes/helper/hash_file.obj \
60+
src/encauth/ocb3/ocb3_int_xor_blocks.obj src/encauth/ocb3/ocb3_test.obj src/encauth/siv/siv.obj \
61+
src/hashes/blake2b.obj src/hashes/blake2s.obj src/hashes/chc/chc.obj src/hashes/helper/hash_file.obj \
6262
src/hashes/helper/hash_filehandle.obj src/hashes/helper/hash_memory.obj \
6363
src/hashes/helper/hash_memory_multi.obj src/hashes/md2.obj src/hashes/md4.obj src/hashes/md5.obj \
6464
src/hashes/rmd128.obj src/hashes/rmd160.obj src/hashes/rmd256.obj src/hashes/rmd320.obj src/hashes/sha1.obj \

makefile.unix

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ src/encauth/ocb3/ocb3_add_aad.o src/encauth/ocb3/ocb3_decrypt.o src/encauth/ocb3
7878
src/encauth/ocb3/ocb3_decrypt_verify_memory.o src/encauth/ocb3/ocb3_done.o \
7979
src/encauth/ocb3/ocb3_encrypt.o src/encauth/ocb3/ocb3_encrypt_authenticate_memory.o \
8080
src/encauth/ocb3/ocb3_encrypt_last.o src/encauth/ocb3/ocb3_init.o src/encauth/ocb3/ocb3_int_ntz.o \
81-
src/encauth/ocb3/ocb3_int_xor_blocks.o src/encauth/ocb3/ocb3_test.o src/hashes/blake2b.o \
82-
src/hashes/blake2s.o src/hashes/chc/chc.o src/hashes/helper/hash_file.o \
81+
src/encauth/ocb3/ocb3_int_xor_blocks.o src/encauth/ocb3/ocb3_test.o src/encauth/siv/siv.o \
82+
src/hashes/blake2b.o src/hashes/blake2s.o src/hashes/chc/chc.o src/hashes/helper/hash_file.o \
8383
src/hashes/helper/hash_filehandle.o src/hashes/helper/hash_memory.o \
8484
src/hashes/helper/hash_memory_multi.o src/hashes/md2.o src/hashes/md4.o src/hashes/md5.o \
8585
src/hashes/rmd128.o src/hashes/rmd160.o src/hashes/rmd256.o src/hashes/rmd320.o src/hashes/sha1.o \

makefile_include.mk

+2-2
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,8 @@ src/encauth/ocb3/ocb3_add_aad.o src/encauth/ocb3/ocb3_decrypt.o src/encauth/ocb3
239239
src/encauth/ocb3/ocb3_decrypt_verify_memory.o src/encauth/ocb3/ocb3_done.o \
240240
src/encauth/ocb3/ocb3_encrypt.o src/encauth/ocb3/ocb3_encrypt_authenticate_memory.o \
241241
src/encauth/ocb3/ocb3_encrypt_last.o src/encauth/ocb3/ocb3_init.o src/encauth/ocb3/ocb3_int_ntz.o \
242-
src/encauth/ocb3/ocb3_int_xor_blocks.o src/encauth/ocb3/ocb3_test.o src/hashes/blake2b.o \
243-
src/hashes/blake2s.o src/hashes/chc/chc.o src/hashes/helper/hash_file.o \
242+
src/encauth/ocb3/ocb3_int_xor_blocks.o src/encauth/ocb3/ocb3_test.o src/encauth/siv/siv.o \
243+
src/hashes/blake2b.o src/hashes/blake2s.o src/hashes/chc/chc.o src/hashes/helper/hash_file.o \
244244
src/hashes/helper/hash_filehandle.o src/hashes/helper/hash_memory.o \
245245
src/hashes/helper/hash_memory_multi.o src/hashes/md2.o src/hashes/md4.o src/hashes/md5.o \
246246
src/hashes/rmd128.o src/hashes/rmd160.o src/hashes/rmd256.o src/hashes/rmd320.o src/hashes/sha1.o \

sources.cmake

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ src/encauth/ocb3/ocb3_init.c
8585
src/encauth/ocb3/ocb3_int_ntz.c
8686
src/encauth/ocb3/ocb3_int_xor_blocks.c
8787
src/encauth/ocb3/ocb3_test.c
88+
src/encauth/siv/siv.c
8889
src/hashes/blake2b.c
8990
src/hashes/blake2s.c
9091
src/hashes/chc/chc.c

0 commit comments

Comments
 (0)