📄 crypt.tex
字号:
/* hash input until blank line */ hash_descriptor[idx].init(&md); while (fgets(buffer, sizeof(buffer), stdin) != NULL) hash_descriptor[idx].process(&md, buffer, strlen(buffer)); hash_descriptor[idx].done(&md, hash); /* dump to screen */ for (x = 0; x < hash_descriptor[idx].hashsize; x++) printf("%02x ", hash[x]); printf("\n"); return 0;}\end{verbatim}\end{small}Note the usage of ``MAXBLOCKSIZE''. In Libtomcrypt no symmetric block, key or hash digest is larger than MAXBLOCKSIZE inlength. This provides a simple size you can set your automatic arrays to that will not get overrun.There are three helper functions as well:\index{hash\_memory()} \index{hash\_file()}\begin{verbatim}int hash_memory(int hash, const unsigned char *data, unsigned long len, unsigned char *dst, unsigned long *outlen);int hash_file(int hash, const char *fname, unsigned char *dst, unsigned long *outlen);int hash_filehandle(int hash, FILE *in, unsigned char *dst, unsigned long *outlen);\end{verbatim}Both functions return {\bf CRYPT\_OK} on success, otherwise they return an error code. The ``hash'' parameter isthe location in the descriptor table of the hash. The ``*outlen'' variable is used to keep track of the output size. Youmust set it to the size of your output buffer before calling the functions. When they complete succesfully they storethe length of the message digest back in it. The functions are otherwise straightforward. The ``hash\_filehandle'' functionassumes that ``in'' is an file handle opened in binary mode. It will not reset the file position after hashing the content.To perform the above hash with md5 the following code could be used:\begin{small}\begin{verbatim}#include <mycrypt.h>int main(void){ int idx, errno; unsigned long len; unsigned char out[MAXBLOCKSIZE]; /* register the hash */ if (register_hash(&md5_desc) == -1) { printf("Error registering MD5.\n"); return -1; } /* get the index of the hash */ idx = find_hash("md5"); /* call the hash */ len = sizeof(out); if ((errno = hash_memory(idx, "hello world", 11, out, &len)) != CRYPT_OK) { printf("Error hashing data: %s\n", error_to_string(errno)); return -1; } return 0;}\end{verbatim}\end{small}The following hashes are provided as of this release:\begin{center}\begin{tabular}{|c|c|c|} \hline Name & Descriptor Name & Size of Message Digest (bytes) \\ \hline SHA-512 & sha512\_desc & 64 \\ \hline SHA-384 & sha384\_desc & 48 \\ \hline SHA-256 & sha256\_desc & 32 \\ \hline TIGER-192 & tiger\_desc & 24 \\ \hline SHA-1 & sha1\_desc & 20 \\ \hline MD5 & md5\_desc & 16 \\ \hline MD4 & md4\_desc & 16 \\ \hline MD2 & md2\_desc & 16 \\ \hline\end{tabular}\end{center}Similar to the cipher descriptor table you must register your hash algorithms before you can use them. These functionswork exactly like those of the cipher registration code. The functions are:\begin{verbatim}int register_hash(const struct _hash_descriptor *hash);int unregister_hash(const struct _hash_descriptor *hash);\end{verbatim}\subsection{Notice}It is highly recommended that you not use the MD4 or MD5 hashes for the purposes of digital signatures or authentication codes. These hashes are provided for completeness and they still can be used for the purposes of password hashing or one-way accumulators(e.g. Yarrow).The other hashes such as the SHA-1, SHA-2 (that includes SHA-512, SHA-384 and SHA-256) and TIGER-192 are still considered securefor all purposes you would normally use a hash for.\section{Hash based Message Authenication Codes}Thanks to Dobes Vandermeer the library now includes support for hash based message authenication codes or HMAC for short. An HMACof a message is a keyed authenication code that only the owner of a private symmetric key will be able to verify. The purpose isto allow an owner of a private symmetric key to produce an HMAC on a message then later verify if it is correct. Any impostor oreavesdropper will not be able to verify the authenticity of a message. The HMAC support works much like the normal hash functions except that the initialization routine requires you to pass a key and its length. The key is much like a key you would pass to a cipher. That is, it is simply an array of octets stored inchars. The initialization routine is:\begin{verbatim}int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen);\end{verbatim}The ``hmac'' parameter is the state for the HMAC code. ``hash'' is the index into the descriptor table of the hash you wantto use to authenticate the message. ``key'' is the pointer to the array of chars that make up the key. ``keylen'' is thelength (in octets) of the key you want to use to authenticate the message. To send octets of a message through the HMAC system you must use the following function:\begin{verbatim}int hmac_process(hmac_state *hmac, const unsigned char *buf, unsigned long len);\end{verbatim}``hmac'' is the HMAC state you are working with. ``buf'' is the array of octets to send into the HMAC process. ``len'' is thenumber of octets to process. Like the hash process routines you can send the data in arbitrarly sized chunks. When you are finished with the HMAC process you must call the following function to get the HMAC code:\begin{verbatim}int hmac_done(hmac_state *hmac, unsigned char *hash);\end{verbatim}``hmac'' is the HMAC state you are working with. ``hash'' is the array of octets where the HMAC code should be stored. Youmust ensure that your destination array is the right size (or just make it of size MAXBLOCKSIZE to be sure). There are two utility functions provided to make using HMACs easier todo.\begin{verbatim}int hmac_memory(int hash, const unsigned char *key, unsigned long keylen, const unsigned char *data, unsigned long len, unsigned char *dst);\end{verbatim}This will produce an HMAC code for the array of octets in ``data'' of length ``len''. The index into the hash descriptor table must be provided in ``hash'' It uses the key from ``key'' with a key length of ``keylen''. The result is stored in the array of octets``dst''. Similarly for files there is the following function:\begin{verbatim}int hmac_file(int hash, const char *fname, const unsigned char *key, unsigned long keylen, unsigned char *dst);\end{verbatim}``hash'' is the index into the hash descriptor table of the hash you want to use. ``fname'' is the filename to process. ``key''is the array of octets to use as the key. ``keylen'' is the length of the key. ``dst'' is the array of octets where the resultshould be stored.To test if the HMAC code is working there is the following function:\begin{verbatim}int hmac_test(void);\end{verbatim}Which returns {\bf CRYPT\_OK} if the code passes otherwise it returns an error code. Some example code for using the HMAC system is given below.\begin{small}\begin{verbatim}#include <mycrypt.h>int main(void){ int idx, errno; hmac_state hmac; unsigned char key[16], dst[MAXBLOCKSIZE]; /* register SHA-1 */ if (register_hash(&sha1_desc) == -1) { printf("Error registering SHA1\n"); return -1; } /* get index of SHA1 in hash descriptor table */ idx = find_hash("sha1"); /* we would make up our symmetric key in "key[]" here */ /* start the HMAC */ if ((errno = hmac_init(&hmac, idx, key, 16)) != CRYPT_OK) { printf("Error setting up hmac: %s\n", error_to_string(errno)); return -1; } /* process a few octets */ if((errno = hmac_process(&hmac, "hello", 5) != CRYPT_OK) { printf("Error processing hmac: %s\n", error_to_string(errno)); return -1; } /* get result (presumably to use it somehow...) */ if ((errno = hmac_done(&hmac, dst)) != CRYPT_OK) { printf("Error finishing hmac: %s\n", error_to_string(errno)); return -1; } /* return */ return 0;}\end{verbatim}\end{small}\chapter{Pseudo-Random Number Generators}\section{Core Functions}The library provides an array of core functions for Pseudo-Random Number Generators (PRNGs) as well. A cryptographic PRNG isused to expand a shorter bit string into a longer bit string. PRNGs are used wherever random data is required such as Public Key (PK)key generation. There is a universal structure called ``prng\_state''. To initialize a PRNG call:\begin{verbatim}int XXX_start(prng_state *prng);\end{verbatim}This will setup the PRNG for future use and not seed it. In order for the PRNG to be cryptographically useful you must give it entropy. Ideally you'd have some OS level source to tap like in UNIX (see section 5.3). To add entropy to the PRNG call:\begin{verbatim}int XXX_add_entropy(const unsigned char *in, unsigned long len, prng_state *prng);\end{verbatim}Which returns {\bf CRYPTO\_OK} if the entropy was accepted. Once you think you have enough entropy you call anotherfunction to put the entropy into action.\begin{verbatim}int XXX_ready(prng_state *prng);\end{verbatim}Which returns {\bf CRYPTO\_OK} if it is ready. Finally to actually read bytes call:\begin{verbatim}unsigned long XXX_read(unsigned char *out, unsigned long len, prng_state *prng);\end{verbatim}Which returns the number of bytes read from the PRNG.\subsection{Remarks}It is possible to be adding entropy and reading from a PRNG at the same time. For example, if you first seed the PRNGand call ready() you can now read from it. You can also keep adding new entropy to it. The new entropy will not be usedin the PRNG until ready() is called again. This allows the PRNG to be used and re-seeded at the same time. No real error checking is guaranteed to see if the entropy is sufficient or if the PRNG is even in a ready state before reading.\subsection{Example}Below is a simple snippet to read 10 bytes from yarrow. Its important to note that this snippet is {\bf NOT} secure sincethe entropy added is not random.\begin{verbatim}#include <mycrypt.h>int main(void){ prng_state prng; unsigned char buf[10]; int errno; /* start it */ if ((errno = yarrow_start(&prng)) != CRYPT_OK) { printf("Start error: %s\n", error_to_string(errno)); } /* add entropy */ if ((errno = yarrow_add_entropy("hello world", 11, &prng)) != CRYPT_OK) { printf("Add_entropy error: %s\n", error_to_string(errno)); } /* ready and read */ if ((errno = yarrow_ready(&prng)) != CRYPT_OK) { printf("Ready error: %s\n", error_to_string(errno)); } printf("Read %lu bytes from yarrow\n", yarrow_read(buf, 10, &prng)); return 0;}\end{verbatim}\section{PRNG Descriptors}\index{PRNG Descriptor}PRNGs have descriptors too (surprised?). Stored in the structure ``prng\_descriptor''. The format of an element is:\begin{verbatim}struct _prng_descriptor { char *name; int (*start) (prng_state *); int (*add_entropy)(const unsigned char *, unsigned long, prng_state *); int (*ready) (prng_state *); unsigned long (*read)(unsigned char *, unsigned long len, prng_state *);};\end{verbatim}There is a ``int find\_prng(char *name)'' function as well. Returns -1 if the PRNG is not found, otherwise it returnsthe position in the prng\_descriptor array.Just like the ciphers and hashes you must register your prng before you can use it. The two functions provided workexactly as those for the cipher registry functions. They are:\begin{verbatim}int register_prng(const struct _prng_descriptor *prng);int unregister_prng(const struct _prng_descriptor *prng);\end{verbatim}\subsubsection{PRNGs Provided}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -