Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions doc/crypt.tex
Original file line number Diff line number Diff line change
Expand Up @@ -2689,6 +2689,113 @@ \subsection{One--Shot Packet}
\end{verbatim}
\end{small}

\mysection{GCM-SIV}
\label{GCM-SIV}

AES--GCM--SIV is a nonce--misuse--resistant authenticated encryption mode defined by \url{https://tools.ietf.org/html/rfc8452}.
Unlike AES--GCM, reusing a nonce with the same key does not break confidentiality or authenticity.

\textbf{There is no streaming API}. The algorithm needs two passes: during encryption, the tag is computed over the whole plaintext
and then used as the AES--CTR starting counter, so ciphertext cannot be produced early. During decryption, plaintext must not be
returned before the tag is verified.

The following parameters are fixed by RFC 8452:
\begin{itemize}
\item \textbf{Cipher}: AES. Any 128--bit block cipher registered with libtomcrypt will work, but only AES is interoperable with the RFC.
\item \textbf{Key length}: 16 bytes (AEAD\_AES\_128\_GCM\_SIV) or 32 bytes (AEAD\_AES\_256\_GCM\_SIV).
\item \textbf{Nonce length}: exactly 12 bytes.
\item \textbf{Tag length}: exactly 16 bytes.
\item \textbf{Plaintext and AAD length}: at most $2^{36}$ bytes each.
\end{itemize}

The implementation reuses the GHASH field multiplier (\textit{gcm\_gf\_mult()}) for POLYVAL via the byte--reversal trick from RFC 8452 Appendix A.
It therefore inherits the same hardware acceleration: Intel PCLMUL, ARMv8 PMULL, or the \texttt{LTC\_FAST} table fallback.

\index{gcm\_siv\_memory()}
\begin{verbatim}
int gcm_siv_memory( int cipher,
const unsigned char *key, unsigned long keylen,
const unsigned char *nonce, unsigned long noncelen,
const unsigned char *aad, unsigned long aadlen,
unsigned char *in, unsigned long inlen,
unsigned char *out,
unsigned char *tag, unsigned long *taglen,
int direction);
\end{verbatim}

This runs a single AES--GCM--SIV operation in the given \textit{direction} (\texttt{LTC\_ENCRYPT} or \texttt{LTC\_DECRYPT}).

\textit{cipher} is the index of a registered 128--bit block cipher; use \texttt{find\_cipher("aes")} for the standard mode.

\textit{key} (of length \textit{keylen} = 16 or 32) is the key from which the message--authentication key and the message--encryption key
are derived, together with the 12--byte \textit{nonce}, as described in RFC 8452 Section 4.

\textit{aad} of length \textit{aadlen} is the optional associated data. Pass \texttt{NULL} and \texttt{0} for an empty AAD.

\textit{in} of length \textit{inlen} is the input buffer:
\begin{itemize}
\item on \texttt{LTC\_ENCRYPT} it holds the plaintext, and \textit{out} (of the same length) receives the ciphertext;
\item on \texttt{LTC\_DECRYPT} it holds the ciphertext, and \textit{out} receives the plaintext.
\end{itemize}

\textit{in} and \textit{out} may point at the same buffer for in--place processing.

\textit{tag} is the 16--byte authentication tag:
\begin{itemize}
\item on \texttt{LTC\_ENCRYPT} the function writes it and sets \textit{taglen} to \texttt{16};
\item on \texttt{LTC\_DECRYPT} the caller must place the expected tag into \textit{tag} before calling. The function recomputes the tag,
compares the two in constant time, and on a mismatch returns \texttt{CRYPT\_ERROR} after zeroing \textit{out}. The decrypted
plaintext is never returned to the caller when authentication fails.
\end{itemize}

\textit{taglen} must be at least \texttt{16} on input.

A short worked example of encryption and decryption with AES--GCM--SIV follows.

\begin{small}
\begin{verbatim}
#include <tomcrypt.h>

int main(void)
{
int err;
unsigned char key[32] = {0}; /* AEAD_AES_256_GCM_SIV */
unsigned char nonce[12] = {0};
unsigned char aad[] = "header";
unsigned char plain[16] = {0};
unsigned char ct[sizeof(plain)] = {0};
unsigned char dec[sizeof(plain)] = {0};
unsigned char tag[16];
unsigned long taglen = sizeof(tag);

register_cipher(&aes_desc);

if ((err = gcm_siv_memory(find_cipher("aes"),
key, sizeof(key),
nonce, sizeof(nonce),
aad, sizeof(aad) - 1,
plain, sizeof(plain), ct,
tag, &taglen,
LTC_ENCRYPT)) != CRYPT_OK) {
whine_and_pout(err);
}

if ((err = gcm_siv_memory(find_cipher("aes"),
key, sizeof(key),
nonce, sizeof(nonce),
aad, sizeof(aad) - 1,
ct, sizeof(ct), dec,
tag, &taglen,
LTC_DECRYPT)) != CRYPT_OK) {
/* CRYPT_ERROR here means the tag did not match -- dec has been zeroed */
whine_and_pout(err);
}

return EXIT_SUCCESS;
}
\end{verbatim}
\end{small}

\chapter{One-Way Cryptographic Hash Functions}
\mysection{Core Functions}
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
Expand Down
12 changes: 12 additions & 0 deletions libtomcrypt_VS2008.vcproj
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,18 @@
>
</File>
</Filter>
<Filter
Name="gcm_siv"
>
<File
RelativePath="src\encauth\gcm_siv\gcm_siv.c"
>
</File>
<File
RelativePath="src\encauth\gcm_siv\gcm_siv_test.c"
>
</File>
</Filter>
<Filter
Name="ocb3"
>
Expand Down
3 changes: 2 additions & 1 deletion makefile.mingw
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ src/encauth/eax/eax_init.o src/encauth/eax/eax_test.o src/encauth/gcm/gcm_add_aa
src/encauth/gcm/gcm_add_iv.o src/encauth/gcm/gcm_done.o src/encauth/gcm/gcm_gf_mult.o \
src/encauth/gcm/gcm_init.o src/encauth/gcm/gcm_memory.o src/encauth/gcm/gcm_mult_h.o \
src/encauth/gcm/gcm_process.o src/encauth/gcm/gcm_reset.o src/encauth/gcm/gcm_test.o \
src/encauth/ocb3/ocb3_add_aad.o src/encauth/ocb3/ocb3_decrypt.o src/encauth/ocb3/ocb3_decrypt_last.o \
src/encauth/gcm_siv/gcm_siv.o src/encauth/gcm_siv/gcm_siv_test.o src/encauth/ocb3/ocb3_add_aad.o \
src/encauth/ocb3/ocb3_decrypt.o src/encauth/ocb3/ocb3_decrypt_last.o \
src/encauth/ocb3/ocb3_decrypt_verify_memory.o src/encauth/ocb3/ocb3_done.o \
src/encauth/ocb3/ocb3_encrypt.o src/encauth/ocb3/ocb3_encrypt_authenticate_memory.o \
src/encauth/ocb3/ocb3_encrypt_last.o src/encauth/ocb3/ocb3_init.o src/encauth/ocb3/ocb3_int_ntz.o \
Expand Down
3 changes: 2 additions & 1 deletion makefile.msvc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ src/encauth/eax/eax_init.obj src/encauth/eax/eax_test.obj src/encauth/gcm/gcm_ad
src/encauth/gcm/gcm_add_iv.obj src/encauth/gcm/gcm_done.obj src/encauth/gcm/gcm_gf_mult.obj \
src/encauth/gcm/gcm_init.obj src/encauth/gcm/gcm_memory.obj src/encauth/gcm/gcm_mult_h.obj \
src/encauth/gcm/gcm_process.obj src/encauth/gcm/gcm_reset.obj src/encauth/gcm/gcm_test.obj \
src/encauth/ocb3/ocb3_add_aad.obj src/encauth/ocb3/ocb3_decrypt.obj src/encauth/ocb3/ocb3_decrypt_last.obj \
src/encauth/gcm_siv/gcm_siv.obj src/encauth/gcm_siv/gcm_siv_test.obj src/encauth/ocb3/ocb3_add_aad.obj \
src/encauth/ocb3/ocb3_decrypt.obj src/encauth/ocb3/ocb3_decrypt_last.obj \
src/encauth/ocb3/ocb3_decrypt_verify_memory.obj src/encauth/ocb3/ocb3_done.obj \
src/encauth/ocb3/ocb3_encrypt.obj src/encauth/ocb3/ocb3_encrypt_authenticate_memory.obj \
src/encauth/ocb3/ocb3_encrypt_last.obj src/encauth/ocb3/ocb3_init.obj src/encauth/ocb3/ocb3_int_ntz.obj \
Expand Down
3 changes: 2 additions & 1 deletion makefile.unix
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ src/encauth/eax/eax_init.o src/encauth/eax/eax_test.o src/encauth/gcm/gcm_add_aa
src/encauth/gcm/gcm_add_iv.o src/encauth/gcm/gcm_done.o src/encauth/gcm/gcm_gf_mult.o \
src/encauth/gcm/gcm_init.o src/encauth/gcm/gcm_memory.o src/encauth/gcm/gcm_mult_h.o \
src/encauth/gcm/gcm_process.o src/encauth/gcm/gcm_reset.o src/encauth/gcm/gcm_test.o \
src/encauth/ocb3/ocb3_add_aad.o src/encauth/ocb3/ocb3_decrypt.o src/encauth/ocb3/ocb3_decrypt_last.o \
src/encauth/gcm_siv/gcm_siv.o src/encauth/gcm_siv/gcm_siv_test.o src/encauth/ocb3/ocb3_add_aad.o \
src/encauth/ocb3/ocb3_decrypt.o src/encauth/ocb3/ocb3_decrypt_last.o \
src/encauth/ocb3/ocb3_decrypt_verify_memory.o src/encauth/ocb3/ocb3_done.o \
src/encauth/ocb3/ocb3_encrypt.o src/encauth/ocb3/ocb3_encrypt_authenticate_memory.o \
src/encauth/ocb3/ocb3_encrypt_last.o src/encauth/ocb3/ocb3_init.o src/encauth/ocb3/ocb3_int_ntz.o \
Expand Down
3 changes: 2 additions & 1 deletion makefile_include.mk
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ src/encauth/eax/eax_init.o src/encauth/eax/eax_test.o src/encauth/gcm/gcm_add_aa
src/encauth/gcm/gcm_add_iv.o src/encauth/gcm/gcm_done.o src/encauth/gcm/gcm_gf_mult.o \
src/encauth/gcm/gcm_init.o src/encauth/gcm/gcm_memory.o src/encauth/gcm/gcm_mult_h.o \
src/encauth/gcm/gcm_process.o src/encauth/gcm/gcm_reset.o src/encauth/gcm/gcm_test.o \
src/encauth/ocb3/ocb3_add_aad.o src/encauth/ocb3/ocb3_decrypt.o src/encauth/ocb3/ocb3_decrypt_last.o \
src/encauth/gcm_siv/gcm_siv.o src/encauth/gcm_siv/gcm_siv_test.o src/encauth/ocb3/ocb3_add_aad.o \
src/encauth/ocb3/ocb3_decrypt.o src/encauth/ocb3/ocb3_decrypt_last.o \
src/encauth/ocb3/ocb3_decrypt_verify_memory.o src/encauth/ocb3/ocb3_done.o \
src/encauth/ocb3/ocb3_encrypt.o src/encauth/ocb3/ocb3_encrypt_authenticate_memory.o \
src/encauth/ocb3/ocb3_encrypt_last.o src/encauth/ocb3/ocb3_init.o src/encauth/ocb3/ocb3_int_ntz.o \
Expand Down
2 changes: 2 additions & 0 deletions sources.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ src/encauth/gcm/gcm_mult_h.c
src/encauth/gcm/gcm_process.c
src/encauth/gcm/gcm_reset.c
src/encauth/gcm/gcm_test.c
src/encauth/gcm_siv/gcm_siv.c
src/encauth/gcm_siv/gcm_siv_test.c
src/encauth/ocb3/ocb3_add_aad.c
src/encauth/ocb3/ocb3_decrypt.c
src/encauth/ocb3/ocb3_decrypt_last.c
Expand Down
6 changes: 3 additions & 3 deletions src/encauth/gcm/gcm_gf_mult.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/
#include "tomcrypt_private.h"

#if defined(LTC_GCM_MODE) || defined(LTC_LRW_MODE)
#if defined(LTC_GCM_MODE) || defined(LTC_LRW_MODE) || defined(LTC_GCM_SIV_MODE)
#if defined(LTC_GCM_PCLMUL)

#define LTC_GCM_PCLMUL_TARGET LTC_ATTRIBUTE((__target__("pclmul,ssse3")))
Expand Down Expand Up @@ -260,7 +260,7 @@ static void s_gcm_gf_mult_pmull(const unsigned char *a, const unsigned char *b,
#endif /* defined(LTC_GCM_PMULL) */
#endif /* defined(LTC_GCM_MODE) || defined(LTC_LRW_MODE) */

#if defined(LTC_GCM_TABLES) || defined(LTC_LRW_TABLES) || (defined(LTC_GCM_MODE) && defined(LTC_FAST))
#if defined(LTC_GCM_TABLES) || defined(LTC_LRW_TABLES) || ((defined(LTC_GCM_MODE) || defined(LTC_GCM_SIV_MODE)) && defined(LTC_FAST))

/* this is x*2^128 mod p(x) ... the results are 16 bytes each stored in a packed format. Since only the
* lower 16 bits are not zero'ed I removed the upper 14 bytes */
Expand Down Expand Up @@ -301,7 +301,7 @@ const unsigned char gcm_shift_table[256*2] = {
#endif


#if defined(LTC_GCM_MODE) || defined(LTC_LRW_MODE)
#if defined(LTC_GCM_MODE) || defined(LTC_LRW_MODE) || defined(LTC_GCM_SIV_MODE)


#ifndef LTC_FAST
Expand Down
Loading
Loading