Add doc for CCM Authentication full set of functions
Change-Id: I2830ea3c04fd0410cc12137be41e6c511c4a47fe
This commit is contained in:
parent
699f52418e
commit
1cf965cfcc
241
crypt.tex
241
crypt.tex
@ -1511,9 +1511,91 @@ Similarly, this will OCB decrypt, and compare the internally computed tag agains
|
|||||||
appropriately.
|
appropriately.
|
||||||
|
|
||||||
\subsection{CCM Mode}
|
\subsection{CCM Mode}
|
||||||
CCM is a NIST proposal for encrypt + authenticate that is centered around using AES (or any 16--byte cipher) as a primitive. Unlike EAX and OCB mode,
|
CCM is a NIST proposal for encrypt + authenticate that is centered around using AES (or any 16--byte cipher) as a primitive.
|
||||||
it is only meant for \textit{packet} mode where the length of the input is known in advance. Since it is a packet mode function, CCM only has one
|
|
||||||
function that performs the protocol.
|
\subsubsection{Initialization}
|
||||||
|
To initialize the CCM context with a secret key call the following function.
|
||||||
|
|
||||||
|
\index{ccm\_init()}
|
||||||
|
\begin{verbatim}
|
||||||
|
int ccm_init( ccm_state *ccm,
|
||||||
|
int cipher,
|
||||||
|
const unsigned char *key,
|
||||||
|
int keylen,
|
||||||
|
int ptlen,
|
||||||
|
int taglen,
|
||||||
|
int aadlen);
|
||||||
|
\end{verbatim}
|
||||||
|
This initializes the CCM state \textit{ccm} for the given cipher indexed by \textit{cipher}, with a secret key \textit{key} of length \textit{keylen} octets. The cipher
|
||||||
|
chosen must have a 16--byte block size (e.g., AES).
|
||||||
|
Unlike EAX and OCB mode, CCM is only meant for \textit{packet} mode where the length of the input is known in advance. This is why the length of the stream
|
||||||
|
to authenticate is given as \textit{ptlen}.
|
||||||
|
With CCM, a header is meta--data you want to send with the message but not have encrypted. The header len is given in the init
|
||||||
|
as \textit{aadlen}.
|
||||||
|
|
||||||
|
\subsubsection{Nonce Vector}
|
||||||
|
After the state has been initialized (or reset) the next step is to add the session (or packet) initial vector. It should be unique per packet encrypted.
|
||||||
|
|
||||||
|
\index{ccm\_add\_nonce()}
|
||||||
|
\begin{verbatim}
|
||||||
|
int ccm_add_nonce( ccm_state *ccm,
|
||||||
|
const unsigned char *nonce,
|
||||||
|
unsigned long noncelen);
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
This adds the nonce or salt is \textit{nonce} of length \textit{noncelen} octets to the CCM state \textit{ccm}. Note that this function must be called
|
||||||
|
once and only once.
|
||||||
|
|
||||||
|
\subsubsection{Additional Authentication Data}
|
||||||
|
The header is meta--data you want to send with the message but not have encrypted, it is stored in \textit{adata} of length \textit{adatalen} octets.
|
||||||
|
|
||||||
|
\index{ccm\_add\_aad()}
|
||||||
|
\begin{verbatim}
|
||||||
|
int ccm_add_aad( ccm_state *ccm,
|
||||||
|
const unsigned char *adata,
|
||||||
|
unsigned long adatalen);
|
||||||
|
\end{verbatim}
|
||||||
|
This adds the additional authentication data \textit{adata} of length \textit{adatalen} to the CCM state \textit{ccm}.
|
||||||
|
|
||||||
|
\subsubsection{Plaintext Processing}
|
||||||
|
After the AAD has been processed, the plaintext (or ciphertext depending on the direction) can be processed.
|
||||||
|
|
||||||
|
\index{ccm\_process()}
|
||||||
|
\begin{verbatim}
|
||||||
|
int ccm_process(ccm_state *ccm,
|
||||||
|
unsigned char *pt,
|
||||||
|
unsigned long ptlen,
|
||||||
|
unsigned char *ct,
|
||||||
|
int direction);
|
||||||
|
\end{verbatim}
|
||||||
|
This processes message data where \textit{pt} is the plaintext and \textit{ct} is the ciphertext. The length of both are equal and stored in \textit{ptlen}. Depending on
|
||||||
|
the mode \textit{pt} is the input and \textit{ct} is the output (or vice versa). When \textit{direction} equals \textbf{CCM\_ENCRYPT} the plaintext is read,
|
||||||
|
encrypted and stored in the ciphertext buffer. When \textit{direction} equals \textbf{CCM\_DECRYPT} the opposite occurs.
|
||||||
|
|
||||||
|
\subsubsection{State Termination}
|
||||||
|
To terminate a CCM state and retrieve the message authentication tag call the following function.
|
||||||
|
|
||||||
|
\index{ccm\_done()}
|
||||||
|
\begin{verbatim}
|
||||||
|
int ccm_done( ccm_state *ccm,
|
||||||
|
unsigned char *tag,
|
||||||
|
unsigned long *taglen);
|
||||||
|
\end{verbatim}
|
||||||
|
This terminates the CCM state \textit{ccm} and stores the tag in \textit{tag} of length \textit{taglen} octets.
|
||||||
|
|
||||||
|
\subsubsection{State Reset}
|
||||||
|
The call to ccm\_init() will perform considerable pre--computation and if you're going to be dealing with a lot of packets
|
||||||
|
it is very costly to have to call it repeatedly. To aid in this endeavour, the reset function has been provided.
|
||||||
|
|
||||||
|
\index{ccm\_reset()}
|
||||||
|
\begin{verbatim}
|
||||||
|
int ccm_reset(ccm_state *ccm);
|
||||||
|
\end{verbatim}
|
||||||
|
|
||||||
|
This will reset the CCM state \textit{ccm} to the state that ccm\_init() left it. The user would then call ccm\_add\_nonce(), ccm\_add\_aad(), etc.
|
||||||
|
|
||||||
|
\subsubsection{One--Shot Packet}
|
||||||
|
To process a single packet under any given key the following helper function can be used.
|
||||||
|
|
||||||
\index{ccm\_memory()}
|
\index{ccm\_memory()}
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
@ -1529,86 +1611,107 @@ int ccm_memory(
|
|||||||
int direction);
|
int direction);
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
|
|
||||||
This performs the \textit{CCM} operation on the data. The \textit{cipher} variable indicates which cipher in the descriptor table to use. It must have a
|
This will initialize the CCM state with the given key, nonce and AAD value then proceed to encrypt or decrypt the message text and store the final
|
||||||
16--byte block size for CCM.
|
message tag. The definition of the variables is the same as it is for all the manual functions.
|
||||||
|
|
||||||
The key can be specified in one of two fashions. First, it can be passed as an array of octets in \textit{key} of length \textit{keylen}. Alternatively,
|
If you are processing many packets under the same key you shouldn't use this function as it invokes the pre--computation with each call.
|
||||||
it can be passed in as a previously scheduled key in \textit{uskey}. The latter fashion saves time when the same key is used for multiple packets. If
|
|
||||||
\textit{uskey} is not \textbf{NULL}, then \textit{key} may be \textbf{NULL} (and vice-versa).
|
|
||||||
|
|
||||||
The nonce or salt is \textit{nonce} of length \textit{noncelen} octets. The header is meta--data you want to send with the message but not have
|
\subsubsection{Example Usage}
|
||||||
encrypted, it is stored in \textit{header} of length \textit{headerlen} octets. The header can be zero octets long (if $headerlen = 0$ then
|
The following is an example usage of how to use CCM over multiple packets with a shared secret key.
|
||||||
you can pass \textit{header} as \textbf{NULL}).
|
|
||||||
|
|
||||||
The plaintext is stored in \textit{pt}, and the ciphertext in \textit{ct}. The length of both are expected to be equal and is passed in as \textit{ptlen}. It is
|
|
||||||
allowable that $pt = ct$. The \textit{direction} variable indicates whether encryption (direction $=$ \textbf{CCM\_ENCRYPT}) or
|
|
||||||
decryption (direction $=$ \textbf{CCM\_DECRYPT}) is to be performed.
|
|
||||||
|
|
||||||
As implemented, this version of CCM cannot handle header or plaintext data longer than $2^{32} - 1$ octets long.
|
|
||||||
|
|
||||||
You can test the implementation of CCM with the following function.
|
|
||||||
|
|
||||||
\index{ccm\_test()}
|
|
||||||
\begin{verbatim}
|
|
||||||
int ccm_test(void);
|
|
||||||
\end{verbatim}
|
|
||||||
|
|
||||||
This will return \textbf{CRYPT\_OK} if the CCM routine passes known test vectors. It requires AES or Rijndael to be registered previously, otherwise it will
|
|
||||||
return \textbf{CRYPT\_NOP}.
|
|
||||||
|
|
||||||
\subsubsection{CCM Example}
|
|
||||||
The following is a sample of how to call CCM.
|
|
||||||
|
|
||||||
\begin{small}
|
\begin{small}
|
||||||
\begin{verbatim}
|
\begin{verbatim}
|
||||||
#include <tomcrypt.h>
|
#include <tomcrypt.h>
|
||||||
|
|
||||||
|
int send_packet(const unsigned char *pt, unsigned long ptlen,
|
||||||
|
const unsigned char *nonce, unsigned long noncelen,
|
||||||
|
const unsigned char *aad, unsigned long aadlen,
|
||||||
|
ccm_state *ccm)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
unsigned long taglen;
|
||||||
|
unsigned char tag[16];
|
||||||
|
|
||||||
|
/* reset the state */
|
||||||
|
if ((err = ccm_reset(ccm)) != CRYPT_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the nonce */
|
||||||
|
if ((err = ccm_add_nonce(ccm, nonce, noncelen)) != CRYPT_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the AAD (note: aad can be NULL if aadlen == 0) */
|
||||||
|
if ((err = ccm_add_aad(ccm, aad, aadlen)) != CRYPT_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* process the plaintext */
|
||||||
|
if ((err =
|
||||||
|
ccm_process(ccm, pt, ptlen, pt, CCM_ENCRYPT)) != CRYPT_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finish up and get the MAC tag */
|
||||||
|
taglen = sizeof(tag);
|
||||||
|
if ((err = ccm_done(ccm, tag, &taglen)) != CRYPT_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ... send a header describing the lengths ... */
|
||||||
|
|
||||||
|
/* depending on the protocol and how nonce is
|
||||||
|
* generated you may have to send it too... */
|
||||||
|
send(socket, nonce, noncelen, 0);
|
||||||
|
|
||||||
|
/* send the aad */
|
||||||
|
send(socket, aad, aadlen, 0);
|
||||||
|
|
||||||
|
/* send the ciphertext */
|
||||||
|
send(socket, pt, ptlen, 0);
|
||||||
|
|
||||||
|
/* send the tag */
|
||||||
|
send(socket, tag, taglen, 0);
|
||||||
|
|
||||||
|
return CRYPT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
unsigned char key[16], nonce[12], pt[32], ct[32],
|
ccm_state ccm;
|
||||||
tag[16], tagcp[16];
|
unsigned char key[16], NONCE[12], pt[PACKET_SIZE];
|
||||||
unsigned long taglen;
|
int err, x;
|
||||||
int err;
|
unsigned long ptlen;
|
||||||
|
|
||||||
/* register cipher */
|
/* somehow fill key/NONCE with random values */
|
||||||
|
|
||||||
|
/* register AES */
|
||||||
register_cipher(&aes_desc);
|
register_cipher(&aes_desc);
|
||||||
|
|
||||||
/* somehow fill key, nonce, pt */
|
/* init the CCM state */
|
||||||
|
|
||||||
/* encrypt it */
|
|
||||||
taglen = sizeof(tag);
|
|
||||||
if ((err =
|
if ((err =
|
||||||
ccm_memory(find_cipher("aes"),
|
ccm_init(&ccm, find_cipher("aes"), key, 16, PACKET_SIZE, 16, size(NONCE))) != CRYPT_OK) {
|
||||||
key, 16, /* 128-bit key */
|
whine_and_pout(err);
|
||||||
NULL, /* not prescheduled */
|
|
||||||
nonce, 12, /* 96-bit nonce */
|
|
||||||
NULL, 0, /* no header */
|
|
||||||
pt, 32, /* [in] 32-byte plaintext */
|
|
||||||
ct, /* [out] ciphertext */
|
|
||||||
tag, &taglen,
|
|
||||||
CCM_ENCRYPT)) != CRYPT_OK) {
|
|
||||||
printf("ccm_memory error %s\n", error_to_string(err));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* ct[0..31] and tag[0..15] now hold the output */
|
|
||||||
|
|
||||||
/* decrypt it */
|
|
||||||
taglen = sizeof(tagcp);
|
|
||||||
if ((err =
|
|
||||||
ccm_memory(find_cipher("aes"),
|
|
||||||
key, 16, /* 128-bit key */
|
|
||||||
NULL, /* not prescheduled */
|
|
||||||
nonce, 12, /* 96-bit nonce */
|
|
||||||
NULL, 0, /* no header */
|
|
||||||
pt, 32, /* [out] 32-byte plaintext */
|
|
||||||
ct, /* [in] ciphertext */
|
|
||||||
tagcp, &taglen,
|
|
||||||
CCM_DECRYPT)) != CRYPT_OK) {
|
|
||||||
printf("ccm_memory error %s\n", error_to_string(err));
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* now pt[0..31] should hold the original plaintext,
|
/* handle us some packets */
|
||||||
tagcp[0..15] and tag[0..15] should have the same contents */
|
for (;;) {
|
||||||
|
ptlen = make_packet_we_want_to_send(pt);
|
||||||
|
|
||||||
|
/* use NONCE as counter (12 byte counter) */
|
||||||
|
for (x = 11; x >= 0; x--) {
|
||||||
|
if (++NONCE[x]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((err = send_packet(pt, ptlen, NONCE, 12, NULL, 0, &ccm))
|
||||||
|
!= CRYPT_OK) {
|
||||||
|
whine_and_pout(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
\end{verbatim}
|
\end{verbatim}
|
||||||
\end{small}
|
\end{small}
|
||||||
|
Loading…
Reference in New Issue
Block a user