Browse Source

Add doc for CCM Authentication full set of functions

Change-Id: I2830ea3c04fd0410cc12137be41e6c511c4a47fe
Pascal Brand 11 years ago
parent
commit
1cf965cfcc
1 changed files with 168 additions and 65 deletions
  1. 168 65
      crypt.tex

+ 168 - 65
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,
-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.
+CCM is a NIST proposal for encrypt + authenticate that is centered around using AES (or any 16--byte cipher) as a primitive.  
+
+\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
-16--byte block size for CCM.
+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
+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,
-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).
+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.
 
 
-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
-encrypted, it is stored in \textit{header} of length \textit{headerlen} octets.  The header can be zero octets long (if $headerlen = 0$ then
-you can pass \textit{header} as \textbf{NULL}).
+\subsubsection{Example Usage}
+The following is an example usage of how to use CCM over multiple packets with a shared secret key.
 
 
-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.
+\begin{small}
+\begin{verbatim}
+#include <tomcrypt.h>
 
 
-As implemented, this version of CCM cannot handle header or plaintext data longer than $2^{32} - 1$ octets long.
+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];
 
 
-You can test the implementation of CCM with the following function.
+   /* reset the state */
+   if ((err = ccm_reset(ccm)) != CRYPT_OK) {
+      return err;
+   }
 
 
-\index{ccm\_test()}
-\begin{verbatim}
-int ccm_test(void);
-\end{verbatim}
+   /* Add the nonce */
+   if ((err = ccm_add_nonce(ccm, nonce, noncelen)) != CRYPT_OK) {
+      return err;
+   }
 
 
-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}.
+   /* Add the AAD (note: aad can be NULL if aadlen == 0) */
+   if ((err = ccm_add_aad(ccm, aad, aadlen)) != CRYPT_OK) {
+      return err;
+   }
 
 
-\subsubsection{CCM Example}
-The following is a sample of how to call CCM.
+   /* 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;
+}
 
 
-\begin{small}
-\begin{verbatim}
-#include <tomcrypt.h>
 int main(void)
 int main(void)
 {
 {
-   unsigned char key[16], nonce[12], pt[32], ct[32],
-                 tag[16], tagcp[16];
-   unsigned long taglen;
-   int           err;
+   ccm_state     ccm;
+   unsigned char key[16], NONCE[12], pt[PACKET_SIZE];
+   int           err, x;
+   unsigned long ptlen;
 
 
-   /* register cipher */
-   register_cipher(&aes_desc);
+   /* somehow fill key/NONCE with random values */
 
 
-   /* somehow fill key, nonce, pt */
+   /* register AES */
+   register_cipher(&aes_desc);
 
 
-   /* encrypt it */
-   taglen = sizeof(tag);
+   /* init the CCM state */
    if ((err =
    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,     /* [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;
+        ccm_init(&ccm, find_cipher("aes"), key, 16, PACKET_SIZE, 16, size(NONCE))) != CRYPT_OK) {
+      whine_and_pout(err);
    }
    }
-   /* 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;
-   }
+   /* handle us some packets */
+   for (;;) {
+       ptlen = make_packet_we_want_to_send(pt);
 
 
-   /* now pt[0..31] should hold the original plaintext,
-      tagcp[0..15] and tag[0..15] should have the same contents */
+       /* 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}