📄 crypt.tex
字号:
if ((err = ctr_setiv( IV, /* the initial IV we gave to ctr_start */ 16, /* the IV is 16 bytes long */ &ctr) /* the ctr state we wish to modify */ ) != CRYPT_OK) { printf("ctr_setiv error: %s\n", error_to_string(err)); return -1; } if ((err = ctr_decrypt( buffer, /* ciphertext */ buffer, /* plaintext */ sizeof(buffer), /* length of data to encrypt */ &ctr) /* previously initialized CTR state */ ) != CRYPT_OK) { printf("ctr_decrypt error: %s\n", error_to_string(err)); return -1; } /* clear up and return */ zeromem(key, sizeof(key)); zeromem(&ctr, sizeof(ctr)); return 0;}\end{verbatim}\end{small}\section{Encrypt and Authenticate Modes}\subsection{EAX Mode}LibTomCrypt provides support for a mode called EAX\footnote{See M. Bellare, P. Rogaway, D. Wagner, A Conventional Authenticated-Encryption Mode.} in a manner similar to theway it was intended to be used by the designers. First a short description of what EAX mode is before I explain how to use it. EAX is a mode that requires a cipher, CTR and OMAC support and provides encryption and authentication\footnote{Note that since EAX only requires OMAC and CTR you may use ``encrypt only'' cipher descriptors with this mode.}. It is initialized with a random ``nonce'' that can be shared publicly as well as a ``header'' which can be fixed and public as well as a random secret symmetric key.The ``header'' data is meant to be meta-data associated with a stream that isn't private (e.g. protocol messages). It canbe added at anytime during an EAX stream and is part of the authentication tag. That is, changes in the meta-data canbe detected by changes in the output tag.The mode can then process plaintext producing ciphertext as well as compute a partial checksum. The actual checksumcalled a ``tag'' is only emitted when the message is finished. In the interim though the user can process any arbitrarysized message block to send to the recipient as ciphertext. This makes the EAX mode especially suited for streaming modesof operation.The mode is initialized with the following function.\index{eax\_init()}\begin{verbatim}int eax_init(eax_state *eax, int cipher, const unsigned char *key, unsigned long keylen, const unsigned char *nonce, unsigned long noncelen, const unsigned char *header, unsigned long headerlen);\end{verbatim}Where ``eax'' is the EAX state. ``cipher'' is the index of the desired cipher in the descriptor table. ``key'' is the shared secret symmetric key of length ``keylen''. ``nonce'' is the random public string oflength ``noncelen''. ``header'' is the random (or fixed or \textbf{NULL}) header for the message of length``headerlen''.When this function completes ``eax'' will be initialized such that you can now either have data decrypted or encrypted in EAX mode. Note that if ``headerlen'' is zero you may pass ``header'' as \textbf{NULL} to indicatethere is no initial header data.To encrypt or decrypt data in a streaming mode use the following.\index{eax\_encrypt()} \index{eax\_decrypt()}\begin{verbatim}int eax_encrypt(eax_state *eax, const unsigned char *pt, unsigned char *ct, unsigned long length);int eax_decrypt(eax_state *eax, const unsigned char *ct, unsigned char *pt, unsigned long length);\end{verbatim}The function ``eax\_encrypt'' will encrypt the bytes in ``pt'' of ``length'' bytes and store the ciphertext in``ct''. Note that ``ct'' and ``pt'' may be the same region in memory. This function will also send the ciphertextthrough the OMAC function. The function ``eax\_decrypt'' decrypts ``ct'' and stores it in ``pt''. This also allows ``pt'' and ``ct'' to be the same region in memory. You cannot both encrypt or decrypt with the same ``eax'' context. For bi-directional communication youwill need to initialize two EAX contexts (preferably with different headers and nonces). Note that both of these functions allow you to send the data in any granularity but the order is important. Whilethe eax\_init() function allows you to add initial header data to the stream you can also add header data during theEAX stream with the following.\index{eax\_addheader()}\begin{verbatim}int eax_addheader(eax_state *eax, const unsigned char *header, unsigned long length);\end{verbatim}This will add the ``length'' bytes from ``header'' to the given ``eax'' stream. Once the message is finished the ``tag'' (checksum) may be computed with the following function.\index{eax\_done()}\begin{verbatim}int eax_done(eax_state *eax, unsigned char *tag, unsigned long *taglen);\end{verbatim}This will terminate the EAX state ``eax'' and store upto ``taglen'' bytes of the message tag in ``tag''. The functionthen stores how many bytes of the tag were written out back into ``taglen''.The EAX mode code can be tested to ensure it matches the test vectors by calling the following function.\index{eax\_test()}\begin{verbatim}int eax_test(void);\end{verbatim}This requires that the AES (or Rijndael) block cipher be registered with the cipher\_descriptor table first.\begin{verbatim}#include <mycrypt.h>int main(void){ int err; eax_state eax; unsigned char pt[64], ct[64], nonce[16], key[16], tag[16]; unsigned long taglen; if (register_cipher(&rijndael_desc) == -1) { printf("Error registering Rijndael"); return EXIT_FAILURE; } /* ... make up random nonce and key ... */ /* initialize context */ if ((err = eax_init( &eax, /* the context */ find_cipher("rijndael"), /* cipher we want to use */ nonce, /* our state nonce */ 16, /* none is 16 bytes */ "TestApp", /* example header, identifies this program */ 7) /* length of the header */ ) != CRYPT_OK) { printf("Error eax_init: %s", error_to_string(err)); return EXIT_FAILURE; } /* now encrypt data, say in a loop or whatever */ if ((err = eax_encrypt( &eax, /* eax context */ pt, /* plaintext (source) */ ct, /* ciphertext (destination) */ sizeof(pt) /* size of plaintext */ ) != CRYPT_OK) { printf("Error eax_encrypt: %s", error_to_string(err)); return EXIT_FAILURE; } /* finish message and get authentication tag */ taglen = sizeof(tag); if ((err = eax_done( &eax, /* eax context */ tag, /* where to put tag */ &taglen /* length of tag space */ ) != CRYPT_OK) { printf("Error eax_done: %s", error_to_string(err)); return EXIT_FAILURE; } /* now we have the authentication tag in "tag" and it's taglen bytes long */}\end{verbatim} You can also perform an entire EAX state on a block of memory in a single function call with the following functions.\index{eax\_encrypt\_authenticate\_memory} \index{eax\_decrypt\_verify\_memory}\begin{verbatim}int eax_encrypt_authenticate_memory(int cipher, const unsigned char *key, unsigned long keylen, const unsigned char *nonce, unsigned long noncelen, const unsigned char *header, unsigned long headerlen, const unsigned char *pt, unsigned long ptlen, unsigned char *ct, unsigned char *tag, unsigned long *taglen);int eax_decrypt_verify_memory(int cipher, const unsigned char *key, unsigned long keylen, const unsigned char *nonce, unsigned long noncelen, const unsigned char *header, unsigned long headerlen, const unsigned char *ct, unsigned long ctlen, unsigned char *pt, unsigned char *tag, unsigned long taglen, int *res);\end{verbatim}Both essentially just call eax\_init() followed by eax\_encrypt() (or eax\_decrypt() respectively) and eax\_done(). The parametershave the same meaning as with those respective functions. The only difference is eax\_decrypt\_verify\_memory() does not emit a tag. Instead you pass it a tag as input and it compares it againstthe tag it computed while decrypting the message. If the tags match then it stores a $1$ in ``res'', otherwise it stores a $0$.\subsection{OCB Mode}LibTomCrypt provides support for a mode called OCB\footnote{See P. Rogaway, M. Bellare, J. Black, T. Krovetz, ``OCB: A Block Cipher Mode of Operation for Efficient Authenticated Encryption''.}. OCB is an encryption protocol that simultaneously provides authentication. It is slightly faster to use than EAX modebut is less flexible. Let's review how to initialize an OCB context.\index{ocb\_init()}\begin{verbatim}int ocb_init(ocb_state *ocb, int cipher, const unsigned char *key, unsigned long keylen, const unsigned char *nonce);\end{verbatim}This will initialize the ``ocb'' context using cipher descriptor ``cipher''. It will use a ``key'' of length ``keylen''and the random ``nonce''. Note that ``nonce'' must be a random (public) string the same length as the block ciphersblock size (e.g. 16 bytes for AES).This mode has no ``Associated Data'' like EAX mode does which means you cannot authenticate metadata along with the stream.To encrypt or decrypt data use the following.\index{ocb\_encrypt()} \index{ocb\_decrypt()}\begin{verbatim}int ocb_encrypt(ocb_state *ocb, const unsigned char *pt, unsigned char *ct);int ocb_decrypt(ocb_state *ocb, const unsigned char *ct, unsigned char *pt);\end{verbatim}This will encrypt (or decrypt for the latter) a fixed length of data from ``pt'' to ``ct'' (vice versa for the latter). They assume that ``pt'' and ``ct'' are the same size as the block cipher's block size. Note that you cannot call both functions given a single ``ocb'' state. For bi-directional communication you will have to initialize two ``ocb''states (with different nonces). Also ``pt'' and ``ct'' may point to the same location in memory.When you are finished encrypting the message you call the following function to compute the tag.\index{ocb\_done\_encrypt()}\begin{verbatim}int ocb_done_encrypt(ocb_state *ocb, const unsigned char *pt, unsigned long ptlen, unsigned char *ct, unsigned char *tag, unsigned long *taglen);\end{verbatim}This will terminate an encrypt stream ``ocb''. If you have trailing bytes of plaintext that will not complete a block you can pass them here. This will also encrypt the ``ptlen'' bytes in ``pt'' and store them in ``ct''. It will alsostore upto ``taglen'' bytes of the tag into ``tag''.Note that ``ptlen'' must be less than or equal to the block size of block cipher chosen. Also note that if you have an input message equal to the length of the block size then you pass the data here (not to ocb\_encrypt()) only. To terminate a decrypt stream and compared the tag you call the following.\index{ocb\_done\_decrypt()}\begin{verbatim}int ocb_done_decrypt(ocb_state *ocb, const unsigned char *ct, unsigned long ctlen, unsigned char *pt, const unsigned char *tag, unsigned long taglen, int *res);\end{verbatim}Similarly to the previous function you can pass trailing message bytes into this function. This will compute the tag of the message (internally) and then compare it against the ``taglen'' bytes of ``tag'' provided. By default``res'' is set to zero. If all ``taglen'' bytes of ``tag'' can be verified then ``res'' is set to one (authenticatedmessage).To make life simpler the following two functions are provided for memory bound OCB.\index{ocb\_encrypt\_authenticate\_memory()}\begin{verbatim}int ocb_encrypt_authenticate_memory(int cipher, const unsigned char *key, unsigned long keylen, const unsigned char *nonce, const unsigned char *pt, unsigned long ptlen, unsigned char *ct, unsigned char *tag, unsigned long *taglen);\end{verbatim}This will OCB encrypt the message ``pt'' of length ``ptlen'' and store the ciphertext in ``ct''. The length ``ptlen''can be any arbitrary length. \index{ocb\_decrypt\_verify\_memory()}\begin{verbatim}int ocb_decrypt_verify_memory(int cipher, const unsigned char *key, unsigned long keylen, const unsigned char *nonce, const unsigned char *ct, unsigned long ctlen, unsigned char *pt, const unsigned char *tag, unsigned long taglen, int *res);\end{verbatim}Similarly this will OCB decrypt and compare the internally computed tag against the tag provided. ``res'' is set
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -