diff --git a/Doxyfile b/Doxyfile index c2b7cce..b4a01c7 100644 --- a/Doxyfile +++ b/Doxyfile @@ -23,7 +23,7 @@ PROJECT_NAME = LibTomCrypt # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 1.15 +PROJECT_NUMBER = 1.16 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. @@ -1028,14 +1028,14 @@ CLASS_DIAGRAMS = YES # inheritance and usage relations if the target is undocumented # or is not a class. -HIDE_UNDOC_RELATIONS = YES +HIDE_UNDOC_RELATIONS = NO # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) -HAVE_DOT = YES +HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and diff --git a/README b/README new file mode 100644 index 0000000..1e1bd85 --- /dev/null +++ b/README @@ -0,0 +1,3 @@ +See doc/crypt.pdf + + diff --git a/TODO b/TODO index 6967f5c..226ec8a 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,11 @@ -- document makefile flags [INSTALL_* for instance] -- document PK build flags -- merge PKCS #1 v1.5 back in, document changes to rsa_encrypt and rsa_sign +stopped at ch12 +-- needs examples for ecc/dsa!!! (and for asn.1) -for v1.16 -- Add ECC double-mult-add to plugin and make optional accelerator for baseline and MECC_FP [two goals] +must have for v1.16 +- document PK build flags +- document makefile flags [INSTALL_* for instance] +- prepare manual for printing (both soft and hard cover) + +Nice to have [in order of precedence] - add X9.63 IES - add CPP macros like OpenSSL has for ASN1 (e.g. encode/decode functions, etc) shameless ripoff :-) diff --git a/changes b/changes index 434a10a..b2c7014 100644 --- a/changes +++ b/changes @@ -1,3 +1,29 @@ +December 16th, 2006 +v1.16 -- Brian Gladman pointed out that a recent change to GCM broke how the IV was handled. Currently the code complies against his test vectors + so the code should be considered frozen now. + -- Trevor from Cryptography Research Inc. submitted patches to convert the ECC code to be generic allowing curve parameters to be submitted + at runtime. + -- Fixed various doxygen comments + -- Added UTF8 support to the ASN1 code + -- Fixed STOREXXH macros for x86 platforms (Fix found at Elliptic Inc.) + -- Added makefile.unix which is BSD compatible, you have to manually tweak it since well I don't use it normally + -- removed a few lingering memcpy's + -- Fixed memory free errors in ecc_sign_hash() that can arise if the mp_init_multi() fails + -- Fixed incorrect return value in pkcs_1_pss_decode() which would correctly set res to 0 (indicating an incorrect signature) but + would return CRYPT_OK to the caller + -- ltc_ecc_mulmod() could leak memory if mp_init(&mu) failed, fixed. Would you believe that ltc_ecc_mulmod_timing() had the same + bug? Also fixed. :-) + -- Added Shamir's trick to the ECC side (defined as LTC_ECC_SHAMIR, enabled by default), gets ~1.34x to ~1.40x faster ECC verifications + -- Added Brian's vector #46 to the GCM code. It catches the ctr counter error from v1.15. Originally I was going to add all of his vectors, + but they're not as easy to parse and I got a lot of other things to do. Regression! + -- Various other small fixes to the ECC code to clean up error handling (I think most of that was from the move in 1.06 to the plugins) + All of the errors were in cleaning up from heap failures. So they were not likely to be triggered in normal usage + Made similar fixes to the RSA and DSA code (my bad) + -- Cryptography Research Inc. contributed a bunch of fixes to silence warnings (with MSVC) w.r.t. assigned data to unsigned char types. + -- Martin Marko suggested some fixes to make the RNG build with WinCE. + -- Updates to the manual for print (some fixes thanks to Martin Marko) + + November 17th, 2006 v1.15 -- Andreas Lange found that if sha256_init DID fail in fortuna it wouldn't clean up the state correctly. Thanks. Fortunately sha256_init cannot fail (as of v1.14) :-) @@ -1525,6 +1551,6 @@ v0.02 -- Changed RC5 to only allow 12 to 24 rounds v0.01 -- We will call this the first version. /* $Source: /cvs/libtom/libtomcrypt/changes,v $ */ -/* $Revision: 1.257 $ */ -/* $Date: 2006/11/17 15:18:44 $ */ +/* $Revision: 1.274 $ */ +/* $Date: 2006/12/16 19:08:17 $ */ diff --git a/crypt.lof b/crypt.lof index d3e95ad..0f1a2fb 100644 --- a/crypt.lof +++ b/crypt.lof @@ -3,20 +3,22 @@ \contentsline {figure}{\numberline {2.1}{\ignorespaces Load And Store Macros}}{9}{figure.2.1} \contentsline {figure}{\numberline {2.2}{\ignorespaces Rotate Macros}}{9}{figure.2.2} \addvspace {10\p@ } -\contentsline {figure}{\numberline {3.1}{\ignorespaces Built--In Software Ciphers}}{25}{figure.3.1} -\contentsline {figure}{\numberline {3.2}{\ignorespaces Twofish Build Options}}{27}{figure.3.2} +\contentsline {figure}{\numberline {3.1}{\ignorespaces Built--In Software Ciphers}}{19}{figure.3.1} +\contentsline {figure}{\numberline {3.2}{\ignorespaces Twofish Build Options}}{21}{figure.3.2} \addvspace {10\p@ } -\contentsline {figure}{\numberline {4.1}{\ignorespaces Built--In Software Hashes}}{63}{figure.4.1} +\contentsline {figure}{\numberline {4.1}{\ignorespaces Built--In Software Hashes}}{57}{figure.4.1} \addvspace {10\p@ } \addvspace {10\p@ } -\contentsline {figure}{\numberline {6.1}{\ignorespaces List of Provided PRNGs}}{83}{figure.6.1} +\contentsline {figure}{\numberline {6.1}{\ignorespaces List of Provided PRNGs}}{82}{figure.6.1} \addvspace {10\p@ } \addvspace {10\p@ } \addvspace {10\p@ } -\contentsline {figure}{\numberline {9.1}{\ignorespaces DSA Key Sizes}}{111}{figure.9.1} +\contentsline {figure}{\numberline {9.1}{\ignorespaces DSA Key Sizes}}{119}{figure.9.1} \addvspace {10\p@ } -\contentsline {figure}{\numberline {10.1}{\ignorespaces List of ASN.1 Supported Types}}{119}{figure.10.1} +\contentsline {figure}{\numberline {10.1}{\ignorespaces List of ASN.1 Supported Types}}{127}{figure.10.1} \addvspace {10\p@ } \addvspace {10\p@ } +\contentsline {figure}{\numberline {12.1}{\ignorespaces RSA/DH Key Strength}}{149}{figure.12.1} +\contentsline {figure}{\numberline {12.2}{\ignorespaces ECC Key Strength}}{149}{figure.12.2} \addvspace {10\p@ } \addvspace {10\p@ } diff --git a/crypt.tex b/crypt.tex index ed457e7..0d374f7 100644 --- a/crypt.tex +++ b/crypt.tex @@ -51,13 +51,13 @@ \newcommand{\mysection}[1] % Re-define the chaptering command to use { % THESE headers. \section{#1} - \markboth{\textsf{www.libtomcrypt.com}}{\thesection ~ {#1}} + \markboth{\textsf{www.libtom.org}}{\thesection ~ {#1}} } \newcommand{\mystarsection}[1] % Re-define the chaptering command to use { % THESE headers. \section*{#1} - \markboth{\textsf{www.libtomcrypt.com}}{{#1}} + \markboth{\textsf{www.libtom.org}}{{#1}} } \pagestyle{empty} \begin{document} @@ -88,8 +88,28 @@ LibTom Projects \end{tabular} \end{center} \vfil +\newpage +This document is part of the LibTomCrypt package and is hereby released into the public domain. + +~ + +Open Source. Open Academia. Open Minds. + +~ + +\begin{flushright} +Tom St Denis +~ + +Ottawa, Ontario +~ + +Canada +~ +\vfil +\end{flushright} +\newpage -%\pagestyle{plain} \tableofcontents \listoffigures \pagestyle{myheadings} @@ -108,7 +128,7 @@ also performs extensive parameter error checking to prevent any number of run-ti \subsection{What the library IS for?} The library serves as a toolkit for developers who have to solve cryptographic problems. Out of the box LibTomCrypt -does not process SSL or OpenPGP messages, it doesn't read X.591 certificates, or write PEM encoded data. It does, however, +does not process SSL or OpenPGP messages, it doesn't read X.509 certificates, or write PEM encoded data. It does, however, provide all of the tools required to build such functionality. LibTomCrypt was designed to be a flexible library that was not tied to any particular cryptographic problem. @@ -298,9 +318,7 @@ There are 32 and 64-bit cyclic rotations as well: \mysection{Functions with Variable Length Output} Certain functions such as (for example) \textit{rsa\_export()} give an output that is variable length. To prevent buffer overflows you must pass it the length of the buffer where the output will be stored. For example: -\index{rsa\_export()} -\index{error\_to\_string()} -\index{variable length output} +\index{rsa\_export()} \index{error\_to\_string()} \index{variable length output} \begin{small} \begin{verbatim} #include @@ -345,8 +363,7 @@ the PRNG themselves so it is the responsibility of the calling function to initi Certain PRNG algorithms do not require a \textit{prng\_state} argument (sprng for example). The \textit{prng\_state} argument may be passed as \textbf{NULL} in such situations. -\index{register\_prng()} -\index{rsa\_make\_key()} +\index{register\_prng()} \index{rsa\_make\_key()} \begin{small} \begin{verbatim} #include @@ -381,10 +398,6 @@ special care to work properly on platforms where an \textit{unsigned char} is no For the purposes of this library, the term \textit{byte} will refer to an octet or eight bit word. Typically an array of type \textit{byte} will be synonymous with an array of type \textit{unsigned char.} - - - - \chapter{Symmetric Block Ciphers} \mysection{Core Functions} LibTomCrypt provides several block ciphers with an ECB block mode interface. It is important to first note that you @@ -399,8 +412,10 @@ allocation, and allows you to allocate a fixed sized buffer for storing schedule functions which are (given that XXX is the name of the cipher) the following: \index{Cipher Setup} \begin{verbatim} -int XXX_setup(const unsigned char *key, int keylen, int rounds, - symmetric_key *skey); +int XXX_setup(const unsigned char *key, + int keylen, + int rounds, + symmetric_key *skey); \end{verbatim} The XXX\_setup() routine will setup the cipher to be used with a given number of rounds and a given key length (in bytes). @@ -417,11 +432,13 @@ externally supplied plugins. To encrypt or decrypt a block in ECB mode there are these two functions per cipher: \index{Cipher Encrypt} \index{Cipher Decrypt} \begin{verbatim} -int XXX_ecb_encrypt(const unsigned char *pt, unsigned char *ct, - symmetric_key *skey); +int XXX_ecb_encrypt(const unsigned char *pt, + unsigned char *ct, + symmetric_key *skey); -int XXX_ecb_decrypt(const unsigned char *ct, unsigned char *pt, - symmetric_key *skey); +int XXX_ecb_decrypt(const unsigned char *ct, + unsigned char *pt, + symmetric_key *skey); \end{verbatim} These two functions will encrypt or decrypt (respectively) a single block of text\footnote{The size of which depends on which cipher you are using.}, storing the result in the \textit{ct} buffer (\textit{pt} resp.). It is possible that the input and output buffer are @@ -440,6 +457,7 @@ based upon. \subsection{Key Sizing} For each cipher there is a function which will help find a desired key size. It is specified as follows: +\index{Key Sizing} \begin{verbatim} int XXX_keysize(int *keysize); \end{verbatim} @@ -477,6 +495,7 @@ setup function must also call the respective cipher done function when finished. \subsection{Simple Encryption Demonstration} An example snippet that encodes a block with Blowfish in ECB mode. +\index{blowfish\_setup()} \index{blowfish\_ecb\_encrypt()} \index{blowfish\_ecb\_decrypt()} \index{blowfish\_done()} \begin{small} \begin{verbatim} #include @@ -539,7 +558,7 @@ size. \mysection{The Cipher Descriptors} \index{Cipher Descriptor} To facilitate automatic routines an array of cipher descriptors is provided in the array \textit{cipher\_descriptor}. An element -of this array has the following format: +of this array has the following (partial) format (See Section \ref{sec:cipherdesc}): \begin{small} \begin{verbatim} @@ -561,249 +580,7 @@ struct _cipher_descriptor { /** default number of rounds */ default_rounds; - - /** Setup the cipher - @param key The input symmetric key - @param keylen The length of the input key (octets) - @param num_rounds The requested number of rounds (0==default) - @param skey [out] The destination of the scheduled key - @return CRYPT_OK if successful - */ - int (*setup)(const unsigned char *key, - int keylen, - int num_rounds, - symmetric_key *skey); - - /** Encrypt a block - @param pt The plaintext - @param ct [out] The ciphertext - @param skey The scheduled key - @return CRYPT_OK if successful - */ - int (*ecb_encrypt)(const unsigned char *pt, - unsigned char *ct, - symmetric_key *skey); - - /** Decrypt a block - @param ct The ciphertext - @param pt [out] The plaintext - @param skey The scheduled key - @return CRYPT_OK if successful - */ - int (*ecb_decrypt)(const unsigned char *ct, - unsigned char *pt, - symmetric_key *skey); - - /** Test the block cipher - @return CRYPT_OK if successful - CRYPT_NOP if self-testing has been disabled - */ - int (*test)(void); - - /** Terminate the context - @param skey The scheduled key - */ - void (*done)(symmetric_key *skey); - - /** Determine a key size - @param keysize [in/out] The size of the key desired - @return CRYPT_OK if successful - */ - int (*keysize)(int *keysize); - -/** Accelerators **/ - /** Accelerated ECB encryption - @param pt Plaintext - @param ct Ciphertext - @param blocks The number of complete blocks to process - @param skey The scheduled key context - @return CRYPT_OK if successful - */ - int (*accel_ecb_encrypt)(const unsigned char *pt, - unsigned char *ct, - unsigned long blocks, - symmetric_key *skey); - - /** Accelerated ECB decryption - @param pt Plaintext - @param ct Ciphertext - @param blocks The number of complete blocks to process - @param skey The scheduled key context - @return CRYPT_OK if successful - */ - int (*accel_ecb_decrypt)(const unsigned char *ct, - unsigned char *pt, - unsigned long blocks, - symmetric_key *skey); - - /** Accelerated CBC encryption - @param pt Plaintext - @param ct Ciphertext - @param blocks The number of complete blocks to process - @param IV The initial value (input/output) - @param skey The scheduled key context - @return CRYPT_OK if successful - */ - int (*accel_cbc_encrypt)(const unsigned char *pt, - unsigned char *ct, - unsigned long blocks, - unsigned char *IV, - symmetric_key *skey); - - /** Accelerated CBC decryption - @param pt Plaintext - @param ct Ciphertext - @param blocks The number of complete blocks to process - @param IV The initial value (input/output) - @param skey The scheduled key context - @return CRYPT_OK if successful - */ - int (*accel_cbc_decrypt)(const unsigned char *ct, - unsigned char *pt, - unsigned long blocks, - unsigned char *IV, - symmetric_key *skey); - - /** Accelerated CTR encryption - @param pt Plaintext - @param ct Ciphertext - @param blocks The number of complete blocks to process - @param IV The initial value (input/output) - @param mode little or big endian counter (mode=0 or mode=1) - @param skey The scheduled key context - @return CRYPT_OK if successful - */ - int (*accel_ctr_encrypt)(const unsigned char *pt, - unsigned char *ct, - unsigned long blocks, - unsigned char *IV, - int mode, - symmetric_key *skey); - - /** Accelerated LRW - @param pt Plaintext - @param ct Ciphertext - @param blocks The number of complete blocks to process - @param IV The initial value (input/output) - @param tweak The LRW tweak - @param skey The scheduled key context - @return CRYPT_OK if successful - */ - int (*accel_lrw_encrypt)(const unsigned char *pt, - unsigned char *ct, - unsigned long blocks, - unsigned char *IV, - const unsigned char *tweak, - symmetric_key *skey); - - /** Accelerated LRW - @param ct Ciphertext - @param pt Plaintext - @param blocks The number of complete blocks to process - @param IV The initial value (input/output) - @param tweak The LRW tweak - @param skey The scheduled key context - @return CRYPT_OK if successful - */ - int (*accel_lrw_decrypt)(const unsigned char *ct, - unsigned char *pt, - unsigned long blocks, - unsigned char *IV, - const unsigned char *tweak, - symmetric_key *skey); - - /** Accelerated CCM packet (one-shot) - @param key The secret key to use - @param keylen The length of the secret key (octets) - @param uskey A previously scheduled key [optional can be NULL] - @param nonce The session nonce [use once] - @param noncelen The length of the nonce - @param header The header for the session - @param headerlen The length of the header (octets) - @param pt [out] The plaintext - @param ptlen The length of the plaintext (octets) - @param ct [out] The ciphertext - @param tag [out] The destination tag - @param taglen [in/out] Initial and final size of the tag - @param direction CCM_ENCRYPT or CCM_DECRYPT - @return CRYPT_OK if successful - */ - int (*accel_ccm_memory)( - const unsigned char *key, unsigned long keylen, - symmetric_key *uskey, - const unsigned char *nonce, unsigned long noncelen, - const unsigned char *header, unsigned long headerlen, - unsigned char *pt, unsigned long ptlen, - unsigned char *ct, - unsigned char *tag, unsigned long *taglen, - int direction); - - /** Accelerated GCM packet (one shot) - @param key The secret key - @param keylen The length of the secret key - @param IV The initial vector - @param IVlen The length of the initial vector - @param adata The additional authentication data (header) - @param adatalen The length of the adata - @param pt The plaintext - @param ptlen The length of the plaintext - @param ct The ciphertext - @param tag [out] The MAC tag - @param taglen [in/out] The MAC tag length - @param direction GCM_ENCRYPT or GCM_DECRYPT - @return CRYPT_OK on success - */ - int (*accel_gcm_memory)( - const unsigned char *key, unsigned long keylen, - const unsigned char *IV, unsigned long IVlen, - const unsigned char *adata, unsigned long adatalen, - unsigned char *pt, unsigned long ptlen, - unsigned char *ct, - unsigned char *tag, unsigned long *taglen, - int direction); - - /** Accelerated one shot OMAC - @param key The secret key - @param keylen The key length (octets) - @param in The message - @param inlen Length of message (octets) - @param out [out] Destination for tag - @param outlen [in/out] Initial and final size of out - @return CRYPT_OK on success - */ - int (*omac_memory)( - const unsigned char *key, unsigned long keylen, - const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen); - - /** Accelerated one shot XCBC - @param key The secret key - @param keylen The key length (octets) - @param in The message - @param inlen Length of message (octets) - @param out [out] Destination for tag - @param outlen [in/out] Initial and final size of out - @return CRYPT_OK on success - */ - int (*xcbc_memory)( - const unsigned char *key, unsigned long keylen, - const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen); - - /** Accelerated one shot F9 - @param key The secret key - @param keylen The key length (octets) - @param in The message - @param inlen Length of message (octets) - @param out [out] Destination for tag - @param outlen [in/out] Initial and final size of out - @return CRYPT_OK on success - @remark Requires manual padding - */ - int (*f9_memory)( - const unsigned char *key, unsigned long keylen, - const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen); +...... }; \end{verbatim} \end{small} @@ -823,6 +600,8 @@ marked when \textit{name} equals {\bf NULL}. As of this release the current cipher\_descriptors elements are the following: \vfil \index{Cipher descriptor table} +\index{blowfish\_desc} \index{xtea\_desc} \index{rc2\_desc} \index{rc5\_desc} \index{rc6\_desc} \index{saferp\_desc} \index{aes\_desc} \index{twofish\_desc} +\index{des\_desc} \index{des3\_desc} \index{noekeon\_desc} \index{skipjack\_desc} \index{anubis\_desc} \index{khazad\_desc} \index{kseed\_desc} \index{kasumi\_desc} \begin{figure}[hpbt] \begin{small} \begin{center} @@ -884,8 +663,8 @@ by the polynomials 5B and EF used in the MDS multiplication. As a result the co speed increase is useful when \textit{TWOFISH\_SMALL} is defined since the s-boxes and MDS multiply form the heart of the Twofish round function. -\index{Twofish build options} \begin{figure}[hpbt] +\index{Twofish build options} \index{TWOFISH\_SMALL} \index{TWOFISH\_TABLES} \begin{small} \begin{center} \begin{tabular}{|l|l|l|} @@ -912,7 +691,7 @@ int find_cipher(char *name) Which will search for a given name in the array. It returns $-1$ if the cipher is not found, otherwise it returns the location in the array where the cipher was found. For example, to indirectly setup Blowfish you can also use: \begin{small} -\index{register\_cipher()} +\index{register\_cipher()} \index{find\_cipher()} \index{error\_to\_string()} \begin{verbatim} #include int main(void) @@ -1141,10 +920,12 @@ To change or read the IV of a previously initialized chaining mode use the follo \index{cbc\_setiv()} \index{cbc\_getiv()} \index{ofb\_setiv()} \index{ofb\_getiv()} \index{cfb\_setiv()} \index{cfb\_getiv()} \index{ctr\_setiv()} \index{ctr\_getiv()} \begin{verbatim} -int XXX_getiv(unsigned char *IV, unsigned long *len, +int XXX_getiv(unsigned char *IV, + unsigned long *len, symmetric_XXX *XXX); -int XXX_setiv(const unsigned char *IV, unsigned long len, +int XXX_setiv(const unsigned char *IV, + unsigned long len, symmetric_XXX *XXX); \end{verbatim} @@ -1625,7 +1406,7 @@ message). \subsubsection{Packet Functions} To make life simpler the following two functions are provided for memory bound OCB. -\index{ocb\_encrypt\_authenticate\_memory()} +%\index{ocb\_encrypt\_authenticate\_memory()} \begin{verbatim} int ocb_encrypt_authenticate_memory( int cipher, @@ -1688,7 +1469,7 @@ The plaintext is stored in \textit{pt}, and the ciphertext in \textit{ct}. The 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 copy of CCM cannot handle a header or plaintext longer than $2^{32} - 1$ octets long. +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. @@ -1697,7 +1478,8 @@ You can test the implementation of CCM with the following function. int ccm_test(void); \end{verbatim} -This will return \textbf{CRYPT\_OK} if the CCM routine passes known test vectors. +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. @@ -1707,7 +1489,8 @@ The following is a sample of how to call CCM. #include int main(void) { - unsigned char key[16], nonce[12], pt[32], ct[32], tag[16], tagcp[16]; + unsigned char key[16], nonce[12], pt[32], ct[32], + tag[16], tagcp[16]; unsigned long taglen; int err; @@ -1895,7 +1678,8 @@ int send_packet(const unsigned char *pt, unsigned long ptlen, } /* process the plaintext */ - if ((err = gcm_process(gcm, pt, ptlen, pt, GCM_ENCRYPT)) != CRYPT_OK) { + if ((err = + gcm_process(gcm, pt, ptlen, pt, GCM_ENCRYPT)) != CRYPT_OK) { return err; } @@ -1936,7 +1720,8 @@ int main(void) register_cipher(&aes_desc); /* init the GCM state */ - if ((err = gcm_init(&gcm, find_cipher("aes"), key, 16)) != CRYPT_OK) { + if ((err = + gcm_init(&gcm, find_cipher("aes"), key, 16)) != CRYPT_OK) { whine_and_pout(err); } @@ -2004,7 +1789,7 @@ To test a hash function call: int XXX_test(void); \end{verbatim} -This will return {\bf CRYPTO\_OK} if the hash matches the test vectors, otherwise it returns an error code. An +This will return {\bf CRYPT\_OK} if the hash matches the test vectors, otherwise it returns an error code. An example snippet that hashes a message with md5 is given below. \begin{small} \begin{verbatim} @@ -2115,31 +1900,45 @@ int main(void) Note the usage of \textbf{MAXBLOCKSIZE}. In LibTomCrypt, no symmetric block, key or hash digest is larger than \textbf{MAXBLOCKSIZE} in length. 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()} +There are three helper functions to make working with hashes easier. The first is a function to hash a buffer, and produce the digest in a single +function call. + +\index{hash\_memory()} \begin{verbatim} int hash_memory( int hash, const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen); +\end{verbatim} +This will hash the data pointed to by \textit{in} of length \textit{inlen}. The hash used is indexed by the \textit{hash} parameter. The message +digest is stored in \textit{out}, and the \textit{outlen} parameter is updated to hold the message digest size. + +The next helper function allows for the hashing of a file based on a file name. +\index{hash\_file()} +\begin{verbatim} int hash_file( int hash, const char *fname, unsigned char *out, unsigned long *outlen); +\end{verbatim} +This will hash the file named by \textit{fname} using the hash indexed by \textit{hash}. The file named in this function call must be readable by the +user owning the process performing the request. This function can be omitted by the \textbf{LTC\_NO\_FILE} define, which forces it to return \textbf{CRYPT\_NOP} +when it is called. The message digest is stored in \textit{out}, and the \textit{outlen} parameter is updated to hold the message digest size. + +\index{hash\_filehandle()} +\begin{verbatim} int hash_filehandle( int hash, FILE *in, unsigned char *out, unsigned long *outlen); \end{verbatim} -The \textit{hash} parameter is the location in the descriptor table of the hash (\textit{e.g. the return of find\_hash()}). -The \textit{*outlen} variable is used to keep track of the output size. You must set it to the size of your output buffer before -calling the functions. When they complete successfully, they store the length of the message digest back in it. The functions -are otherwise straightforward. The \textit{hash\_filehandle} function assumes that \textit{in} is an file handle opened in binary mode. -It will hash to the end of file and not reset the file position when finished. +This will hash the file identified by the handle \textit{in} using the hash indexed by \textit{hash}. This will begin hashing from the current file pointer position, and +will not rewind the file pointer when finished. This function can be omitted by the \textbf{LTC\_NO\_FILE} define, which forces it to return \textbf{CRYPT\_NOP} +when it is called. The message digest is stored in \textit{out}, and the \textit{outlen} parameter is updated to hold the message digest size. To perform the above hash with md5 the following code could be used: \begin{small} @@ -2455,10 +2254,11 @@ following function. \index{omac\_memory()} \begin{verbatim} -int omac_memory(int cipher, - const unsigned char *key, unsigned long keylen, - const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen); +int omac_memory( + int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen); \end{verbatim} This will compute the OMAC of \textit{inlen} bytes of \textit{in} using the key \textit{key} of length \textit{keylen} bytes and the cipher specified by the \textit{cipher}'th entry in the cipher\_descriptor table. It will store the MAC in \textit{out} with the same @@ -2467,10 +2267,11 @@ rules as omac\_done. To OMAC a file use \index{omac\_file()} \begin{verbatim} -int omac_file(int cipher, - const unsigned char *key, unsigned long keylen, - const char *filename, - unsigned char *out, unsigned long *outlen); +int omac_file( + int cipher, + const unsigned char *key, unsigned long keylen, + const char *filename, + unsigned char *out, unsigned long *outlen); \end{verbatim} Which will OMAC the entire contents of the file specified by \textit{filename} using the key \textit{key} of length \textit{keylen} bytes @@ -2541,8 +2342,10 @@ A PMAC state is initialized with the following. \index{pmac\_init()} \begin{verbatim} -int pmac_init(pmac_state *pmac, int cipher, - const unsigned char *key, unsigned long keylen); +int pmac_init( pmac_state *pmac, + int cipher, + const unsigned char *key, + unsigned long keylen); \end{verbatim} Which initializes the \textit{pmac} state with the given \textit{cipher} and \textit{key} of length \textit{keylen} bytes. The chosen cipher must have a 64 or 128 bit block size (e.x. AES). @@ -2551,8 +2354,9 @@ To MAC data simply send it through the process function. \index{pmac\_process()} \begin{verbatim} -int pmac_process(pmac_state *state, - const unsigned char *in, unsigned long inlen); +int pmac_process( pmac_state *state, + const unsigned char *in, + unsigned long inlen); \end{verbatim} This will process \textit{inlen} bytes of \textit{in} in the given \textit{state}. The function is not sensitive to the granularity of the data. For example, @@ -2572,38 +2376,41 @@ When a complete message has been processed the following function can be called \index{pmac\_done()} \begin{verbatim} -int pmac_done(pmac_state *state, - unsigned char *out, unsigned long *outlen); +int pmac_done( pmac_state *state, + unsigned char *out, + unsigned long *outlen); \end{verbatim} -This will store upto \textit{outlen} bytes of the tag for the given \textit{state} into \textit{out}. Note that if \textit{outlen} is larger +This will store up to \textit{outlen} bytes of the tag for the given \textit{state} into \textit{out}. Note that if \textit{outlen} is larger than the size of the tag it is set to the amount of bytes stored in \textit{out}. -Similar to the PMAC code the file and memory functions are also provided. To PMAC a buffer of memory in one shot use the +Similar to the OMAC code the file and memory functions are also provided. To PMAC a buffer of memory in one shot use the following function. \index{pmac\_memory()} \begin{verbatim} -int pmac_memory(int cipher, - const unsigned char *key, unsigned long keylen, - const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen); +int pmac_memory( + int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen); \end{verbatim} -This will compute the PMAC of \textit{msglen} bytes of \textit{msg} using the key \textit{key} of length \textit{keylen} bytes and the cipher +This will compute the PMAC of \textit{msglen} bytes of \textit{msg} using the key \textit{key} of length \textit{keylen} bytes, and the cipher specified by the \textit{cipher}'th entry in the cipher\_descriptor table. It will store the MAC in \textit{out} with the same -rules as omac\_done. +rules as pmac\_done(). To PMAC a file use \index{pmac\_file()} \begin{verbatim} -int pmac_file(int cipher, - const unsigned char *key, unsigned long keylen, - const char *filename, - unsigned char *out, unsigned long *outlen); +int pmac_file( + int cipher, + const unsigned char *key, unsigned long keylen, + const char *filename, + unsigned char *out, unsigned long *outlen); \end{verbatim} -Which will PMAC the entire contents of the file specified by \textit{filename} using the key \textit{key} of length \textit{keylen} bytes +Which will PMAC the entire contents of the file specified by \textit{filename} using the key \textit{key} of length \textit{keylen} bytes, and the cipher specified by the \textit{cipher}'th entry in the cipher\_descriptor table. It will store the MAC in \textit{out} with -the same rules as omac\_done. +the same rules as pmac\_done(). To test if the PMAC code is working there is the following function: \index{pmac\_test()} @@ -2688,6 +2495,168 @@ int main(void) } \end{verbatim} +\mysection{XCBC-MAC} +As of LibTomCrypt v1.15, XCBC-MAC (RFC 3566) has been provided to support TLS encryption suites. Like OMAC, it computes a message authentication code +by using a cipher in CBC mode. It also uses a single key which it expands into the requisite three keys for the MAC function. A XCBC--MAC state is +initialized with the following function: + +\index{xcbc\_init()} +\begin{verbatim} +int xcbc_init( xcbc_state *xcbc, + int cipher, + const unsigned char *key, + unsigned long keylen); +\end{verbatim} + +This will initialize the XCBC--MAC state \textit{xcbc}, with the key specified in \textit{key} of length \textit{keylen} octets. The cipher indicated +by the \textit{cipher} index can be either a 64 or 128--bit block cipher. This will return \textbf{CRYPT\_OK} on success. + +To process data through XCBC--MAC use the following function: + +\index{xcbc\_process()} +\begin{verbatim} +int xcbc_process( xcbc_state *state, + const unsigned char *in, + unsigned long inlen); +\end{verbatim} + +This will add the message octets pointed to by \textit{in} of length \textit{inlen} to the XCBC--MAC state pointed to by \textit{state}. Like the other MAC functions, +the granularity of the input is not important but the order is. This will return \textbf{CRYPT\_OK} on success. + +To compute the MAC tag value use the following function: + +\index{xcbc\_done()} +\begin{verbatim} +int xcbc_done( xcbc_state *state, + unsigned char *out, + unsigned long *outlen); +\end{verbatim} + +This will retrieve the XCBC--MAC tag from the state pointed to by \textit{state}, and store it in the array pointed to by \textit{out}. The \textit{outlen} parameter +specifies the maximum size of the destination buffer, and is updated to hold the final size of the tag when the function returns. This will return \textbf{CRYPT\_OK} on success. + +Helper functions are provided to make parsing memory buffers and files easier. The following functions are provided: + +\index{xcbc\_memory()} +\begin{verbatim} +int xcbc_memory( + int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen); +\end{verbatim} +This will compute the XCBC--MAC of \textit{msglen} bytes of \textit{msg}, using the key \textit{key} of length \textit{keylen} bytes, and the cipher +specified by the \textit{cipher}'th entry in the cipher\_descriptor table. It will store the MAC in \textit{out} with the same rules as xcbc\_done(). + +To xcbc a file use +\index{xcbc\_file()} +\begin{verbatim} +int xcbc_file( + int cipher, + const unsigned char *key, unsigned long keylen, + const char *filename, + unsigned char *out, unsigned long *outlen); +\end{verbatim} + +Which will XCBC--MAC the entire contents of the file specified by \textit{filename} using the key \textit{key} of length \textit{keylen} bytes, and the cipher +specified by the \textit{cipher}'th entry in the cipher\_descriptor table. It will store the MAC in \textit{out} with the same rules as xcbc\_done(). + + +To test XCBC--MAC for RFC 3566 compliance use the following function: + +\index{xcbc\_test()} +\begin{verbatim} +int xcbc_test(void); +\end{verbatim} + +This will return \textbf{CRYPT\_OK} on success. This requires the AES or Rijndael descriptor be previously registered, otherwise, it will return +\textbf{CRYPT\_NOP}. + +\mysection{F9--MAC} +The F9--MAC is yet another CBC--MAC variant proposed for the 3GPP standard. Originally specified to be used with the KASUMI block cipher, it can also be used +with other ciphers. For LibTomCrypt, the F9--MAC code can use any cipher. + +\subsection{Usage Notice} +F9--MAC differs slightly from the other MAC functions in that it requires the caller to perform the final message padding. The padding quite simply is a direction +bit followed by a 1 bit and enough zeros to make the message a multiple of the cipher block size. If the message is byte aligned, the padding takes on the form of +a single 0x40 or 0xC0 byte followed by enough 0x00 bytes to make the message proper multiple. + +If the user simply wants a MAC function (hint: use OMAC) padding with a single 0x40 byte should be sufficient for security purposes and still be reasonably compatible +with F9--MAC. + +\subsection{F9--MAC Functions} +A F9--MAC state is initialized with the following function: +\index{f9\_init()} +\begin{verbatim} +int f9_init( f9_state *f9, + int cipher, + const unsigned char *key, + unsigned long keylen); +\end{verbatim} + +This will initialize the F9--MAC state \textit{f9}, with the key specified in \textit{key} of length \textit{keylen} octets. The cipher indicated +by the \textit{cipher} index can be either a 64 or 128--bit block cipher. This will return \textbf{CRYPT\_OK} on success. + +To process data through F9--MAC use the following function: +\index{f9\_process()} +\begin{verbatim} +int f9_process( f9_state *state, + const unsigned char *in, + unsigned long inlen); +\end{verbatim} + +This will add the message octets pointed to by \textit{in} of length \textit{inlen} to the F9--MAC state pointed to by \textit{state}. Like the other MAC functions, +the granularity of the input is not important but the order is. This will return \textbf{CRYPT\_OK} on success. + +To compute the MAC tag value use the following function: + +\index{f9\_done()} +\begin{verbatim} +int f9_done( f9_state *state, + unsigned char *out, + unsigned long *outlen); +\end{verbatim} + +This will retrieve the F9--MAC tag from the state pointed to by \textit{state}, and store it in the array pointed to by \textit{out}. The \textit{outlen} parameter +specifies the maximum size of the destination buffer, and is updated to hold the final size of the tag when the function returns. This will return +\textbf{CRYPT\_OK} on success. + +Helper functions are provided to make parsing memory buffers and files easier. The following functions are provided: + +\index{f9\_memory()} +\begin{verbatim} +int f9_memory( + int cipher, + const unsigned char *key, unsigned long keylen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen); +\end{verbatim} +This will compute the F9--MAC of \textit{msglen} bytes of \textit{msg}, using the key \textit{key} of length \textit{keylen} bytes, and the cipher +specified by the \textit{cipher}'th entry in the cipher\_descriptor table. It will store the MAC in \textit{out} with the same rules as f9\_done(). + +To F9--MAC a file use +\index{f9\_file()} +\begin{verbatim} +int f9_file( + int cipher, + const unsigned char *key, unsigned long keylen, + const char *filename, + unsigned char *out, unsigned long *outlen); +\end{verbatim} + +Which will F9--MAC the entire contents of the file specified by \textit{filename} using the key \textit{key} of length \textit{keylen} bytes, and the cipher +specified by the \textit{cipher}'th entry in the cipher\_descriptor table. It will store the MAC in \textit{out} with the same rules as f9\_done(). + + +To test f9--MAC for RFC 3566 compliance use the following function: + +\index{f9\_test()} +\begin{verbatim} +int f9_test(void); +\end{verbatim} + +This will return \textbf{CRYPT\_OK} on success. This requires the AES or Rijndael descriptor be previously registered, otherwise, it will return +\textbf{CRYPT\_NOP}. \chapter{Pseudo-Random Number Generators} \mysection{Core Functions} @@ -2703,22 +2672,23 @@ This will setup the PRNG for future use and not seed it. In order for the PRNG entropy. Ideally you'd have some OS level source to tap like in UNIX. To add entropy to the PRNG call: \index{PRNG add\_entropy} \begin{verbatim} -int XXX_add_entropy(const unsigned char *in, unsigned long inlen, - prng_state *prng); +int XXX_add_entropy(const unsigned char *in, + unsigned long inlen, + prng_state *prng); \end{verbatim} - -Which returns {\bf CRYPTO\_OK} if the entropy was accepted. Once you think you have enough entropy you call another +Which returns {\bf CRYPT\_OK} if the entropy was accepted. Once you think you have enough entropy you call another function to put the entropy into action. \index{PRNG ready} \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: +Which returns {\bf CRYPT\_OK} if it is ready. Finally to actually read bytes call: \index{PRNG read} \begin{verbatim} -unsigned long XXX_read(unsigned char *out, unsigned long outlen, - prng_state *prng); +unsigned long XXX_read(unsigned char *out, + unsigned long outlen, + prng_state *prng); \end{verbatim} Which returns the number of bytes read from the PRNG. When you are finished with a PRNG state you call @@ -2734,8 +2704,9 @@ so that you can later resume the PRNG call the following. \index{PRNG export} \begin{verbatim} -int XXX_export(unsigned char *out, unsigned long *outlen, - prng_state *prng); +int XXX_export(unsigned char *out, + unsigned long *outlen, + prng_state *prng); \end{verbatim} This will write a \textit{PRNG state} to the buffer \textit{out} of length \textit{outlen} bytes. The idea of @@ -2744,8 +2715,9 @@ be that much entropy available. To import a state to seed a PRNG call the foll \index{PRNG import} \begin{verbatim} -int XXX_import(const unsigned char *in, unsigned long inlen, - prng_state *prng); +int XXX_import(const unsigned char *in, + unsigned long inlen, + prng_state *prng); \end{verbatim} This will call the start and add\_entropy functions of the given PRNG. It will use the state in @@ -2756,7 +2728,7 @@ Note that importing a state will not \textit{resume} the PRNG from where it left a state, emit (say) 8 bytes and then import the previously exported state the next 8 bytes will not specifically equal the 8 bytes you generated previously. -When a program is first executed the normal course of operation is +When a program is first executed the normal course of operation is: \begin{enumerate} \item Gather entropy from your sources for a given period of time or number of events. @@ -2765,7 +2737,7 @@ When a program is first executed the normal course of operation is When your program is finished you simply call the export function and save the state to a medium (disk, flash memory, etc). The next time your application starts up you can detect the state, feed it to the -import function and go on your way. It is ideal that (as soon as possible) after startup you export a +import function and go on your way. It is ideal that (as soon as possible) after start up you export a fresh state. This helps in the case that the program aborts or the machine is powered down without being given a chance to exit properly. @@ -2786,12 +2758,11 @@ This will return \textbf{CRYPT\_OK} if PRNG is operating properly. It is possible to be adding entropy and reading from a PRNG at the same time. For example, if you first seed the PRNG and call ready() you can now read from it. You can also keep adding new entropy to it. The new entropy will not be used in 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. +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 since the entropy added is not random. +Below is a simple snippet to read 10 bytes from Yarrow. It is important to note that this snippet is {\bf NOT} secure since +the entropy added is not random. \begin{verbatim} #include @@ -2815,14 +2786,15 @@ int main(void) printf("Ready error: %s\n", error_to_string(err)); } printf("Read %lu bytes from yarrow\n", - yarrow_read(buf, 10, &prng)); + yarrow_read(buf, sizeof(buf), &prng)); return 0; } \end{verbatim} \mysection{PRNG Descriptors} \index{PRNG Descriptor} -PRNGs have descriptors too (surprised?). Stored in the structure \textit{prng\_descriptor}. The format of an element is: +PRNGs have descriptors that allow plugin driven functions to be created using PRNGs. The plugin descriptors are stored in the structure \textit{prng\_descriptor}. The +format of an element is: \begin{verbatim} struct _prng_descriptor { char *name; @@ -2848,17 +2820,26 @@ struct _prng_descriptor { }; \end{verbatim} +To find a PRNG in the descriptor table the following function can be used: \index{find\_prng()} -There is a \textit{int find\_prng(char *name)} function as well. Returns -1 if the PRNG is not found, otherwise it returns -the position in the prng\_descriptor array. +\begin{verbatim} +int find_prng(const char *name); +\end{verbatim} +This will search the PRNG descriptor table for the PRNG named \textit{name}. It will return -1 if the PRNG is not found, otherwise, it returns +the index into the descriptor table. -Just like the ciphers and hashes you must register your prng before you can use it. The two functions provided work -exactly as those for the cipher registry functions. They are: +Just like the ciphers and hashes, you must register your prng before you can use it. The two functions provided work exactly as those for the cipher registry functions. +They are the following: +\index{register\_prng()} \index{unregister\_prng()} \begin{verbatim} int register_prng(const struct _prng_descriptor *prng); int unregister_prng(const struct _prng_descriptor *prng); \end{verbatim} +The register function will register the PRNG, and return the index into the table where it was placed (or -1 for error). It will avoid registering the same +descriptor twice, and will return the index of the current placement in the table if the caller attempts to register it more than once. The unregister function +will return \textbf{CRYPT\_OK} if the PRNG was found and removed. Otherwise, it returns \textbf{CRYPT\_ERROR}. + \subsection{PRNGs Provided} \begin{figure}[here] \begin{center} @@ -2878,9 +2859,9 @@ int unregister_prng(const struct _prng_descriptor *prng); \subsubsection{Yarrow} Yarrow is fast PRNG meant to collect an unspecified amount of entropy from sources -(keyboard, mouse, interrupts, etc) and produce an unbounded string of random bytes. +(keyboard, mouse, interrupts, etc), and produce an unbounded string of random bytes. -\textit{Note:} This PRNG is still secure for most taskings but is no longer recommended. Users +\textit{Note:} This PRNG is still secure for most tasks but is no longer recommended. Users should use Fortuna instead. \subsubsection{Fortuna} @@ -2891,47 +2872,46 @@ to work with most cipher and hash combos based on which you have chosen to build providing more security. Fortuna is slightly less flexible than Yarrow in the sense that it only works with the AES block cipher -and SHA--256 hash function. Technically Fortuna will work with any block cipher that accepts a 256--bit -key and any hash that produces at least a 256--bit output. However, to make the implementation simpler +and SHA--256 hash function. Technically, Fortuna will work with any block cipher that accepts a 256--bit +key, and any hash that produces at least a 256--bit output. However, to make the implementation simpler it has been fixed to those choices. Fortuna is more secure than Yarrow in the sense that attackers who learn parts of the entropy being added to the PRNG learn far less about the state than that of Yarrow. Without getting into to many details Fortuna has the ability to recover from state determination attacks where the attacker starts -to learn information from the PRNGs output about the internal state. Yarrow on the other hand cannot +to learn information from the PRNGs output about the internal state. Yarrow on the other hand, cannot recover from that problem until new entropy is added to the pool and put to use through the ready() function. \subsubsection{RC4} -RC4 is an old stream cipher that can also double duty as a PRNG in a pinch. You \textit{key} it by -calling add\_entropy() and setup the key by calling ready(). You can only add upto 256 bytes via +RC4 is an old stream cipher that can also double duty as a PRNG in a pinch. You key RC4 by +calling add\_entropy(), and setup the key by calling ready(). You can only add up to 256 bytes via add\_entropy(). -When you read from RC4 the output of the RC4 algorithm is XOR'd against your buffer you provide. In this -manner you can use rc4\_read() as an encrypt (and decrypt) function. +When you read from RC4, the output is XOR'ed against your buffer you provide. In this manner, you can use rc4\_read() +as an encrypt (and decrypt) function. -You really shouldn't use RC4 anymore. This isn't because RC4 is weak (though biases are known to exist) just -simply that faster alternatives exist. +You really should not use RC4. This is not because RC4 is weak, (though biases are known to exist) but simply due to +the fact that faster alternatives exist. \subsubsection{SOBER-128} -SOBER-128 is a stream cipher designed by the QUALCOMM Australia team. Like RC4 you \textit{key} it by +SOBER--128 is a stream cipher designed by the QUALCOMM Australia team. Like RC4, you key it by calling add\_entropy(). There is no need to call ready() for this PRNG as it does not do anything. -Note that this cipher has several oddities about how it operates. The first time you call -add\_entropy() that sets the cipher's key. Every other time you call the same function it sets -the cipher's IV variable. The IV mechanism allows you to encrypt several messages with the same -key and not re--use the same key material. +Note: this cipher has several oddities about how it operates. The first call to add\_entropy() sets the cipher's key. +Every other time call to the add\_entropy() function sets the cipher's IV variable. The IV mechanism allows you to +encrypt several messages with the same key, and not re--use the same key material. -Unlike Yarrow and Fortuna all of the entropy (and hence security) of this algorithm rests in the data -you pass it on the first call to add\_entropy(). All buffers sent to add\_entropy() must have a length +Unlike Yarrow and Fortuna, all of the entropy (and hence security) of this algorithm rests in the data +you pass it on the \textbf{first} call to add\_entropy(). All buffers sent to add\_entropy() must have a length that is a multiple of four bytes. -Like RC4 the output of SOBER--128 is XOR'ed against the buffer you provide it. In this manner you can use +Like RC4, the output of SOBER--128 is XOR'ed against the buffer you provide it. In this manner, you can use sober128\_read() as an encrypt (and decrypt) function. -Since SOBER-128 has a fixed keying scheme and is very fast (faster than RC4) the ideal usage of SOBER-128 is to -key it from the output of Fortuna (or Yarrow) and use it to encrypt messages. It is also ideal for +Since SOBER-128 has a fixed keying scheme, and is very fast (faster than RC4) the ideal usage of SOBER-128 is to +key it from the output of Fortuna (or Yarrow), and use it to encrypt messages. It is also ideal for simulations which need a high quality (and fast) stream of bytes. \subsubsection{Example Usage} @@ -2949,7 +2929,7 @@ int main(void) exit(-1); } - /* use \textit{key} as the key */ + /* use "key" as the key */ if ((err = rc4_add_entropy("key", 3, &prng)) != CRYPT_OK) { printf("RC4 add entropy error: %s\n", error_to_string(err)); exit(-1); @@ -2975,33 +2955,37 @@ To decrypt you have to do the exact same steps. \mysection{The Secure RNG} \index{Secure RNG} -An RNG is related to a PRNG except that it doesn't expand a smaller seed to get the data. They generate their random bits +An RNG is related to a PRNG in many ways, except that it does not expand a smaller seed to get the data. They generate their random bits by performing some computation on fresh input bits. Possibly the hardest thing to get correctly in a cryptosystem is the -PRNG. Computers are deterministic beasts that try hard not to stray from pre-determined paths. That makes gathering -entropy needed to seed the PRNG a hard task. +PRNG. Computers are deterministic that try hard not to stray from pre--determined paths. This makes gathering entropy needed to seed a PRNG +a hard task. There is one small function that may help on certain platforms: \index{rng\_get\_bytes()} \begin{verbatim} -unsigned long rng_get_bytes(unsigned char *buf, unsigned long len, - void (*callback)(void)); +unsigned long rng_get_bytes( + unsigned char *buf, + unsigned long len, + void (*callback)(void)); \end{verbatim} Which will try one of three methods of getting random data. The first is to open the popular \textit{/dev/random} device which on most *NIX platforms provides cryptographic random bits\footnote{This device is available in Windows through the Cygwin compiler suite. It emulates \textit{/dev/random} via the Microsoft CSP.}. -The second method is to try the Microsoft Cryptographic Service Provider and read the RNG. The third method is an ANSI C -clock drift method that is also somewhat popular but gives bits of lower entropy. The \textit{callback} parameter is a pointer to a function that returns void. Its used when the slower ANSI C RNG must be -used so the calling application can still work. This is useful since the ANSI C RNG has a throughput of three -bytes a second. The callback pointer may be set to {\bf NULL} to avoid using it if you don't want to. The function -returns the number of bytes actually read from any RNG source. There is a function to help setup a PRNG as well: +The second method is to try the Microsoft Cryptographic Service Provider, and read the RNG. The third method is an ANSI C +clock drift method that is also somewhat popular but gives bits of lower entropy. The \textit{callback} parameter is a pointer to a function that returns void. It is +used when the slower ANSI C RNG must be used so the calling application can still work. This is useful since the ANSI C RNG has a throughput of roughly three +bytes a second. The callback pointer may be set to {\bf NULL} to avoid using it if you do not want to. The function returns the number of bytes actually read from +any RNG source. There is a function to help setup a PRNG as well: \index{rng\_make\_prng()} \begin{verbatim} -int rng_make_prng(int bits, int wprng, prng_state *prng, - void (*callback)(void)); +int rng_make_prng( int bits, + int wprng, + prng_state *prng, + void (*callback)(void)); \end{verbatim} -This will try to setup the prng with a state of at least \textit{bits} of entropy. The \textit{callback} parameter works much like +This will try to initialize the prng with a state of at least \textit{bits} of entropy. The \textit{callback} parameter works much like the callback in \textit{rng\_get\_bytes()}. It is highly recommended that you use this function to setup your PRNGs unless you have a -platform where the RNG doesn't work well. Example usage of this function is given below. +platform where the RNG does not work well. Example usage of this function is given below: \begin{small} \begin{verbatim} @@ -3037,9 +3021,9 @@ int main(void) \end{small} \subsection{The Secure PRNG Interface} -It is possible to access the secure RNG through the PRNG interface and in turn use it within dependent functions such +It is possible to access the secure RNG through the PRNG interface, and in turn use it within dependent functions such as the PK API. This simplifies the cryptosystem on platforms where the secure RNG is fast. The secure PRNG never -requires to be started, that is you need not call the start, add\_entropy or ready functions. For example, consider +requires to be started, that is you need not call the start, add\_entropy, or ready functions. For example, consider the previous example using this PRNG. \begin{small} @@ -3067,35 +3051,79 @@ int main(void) \end{verbatim} \end{small} - - \chapter{RSA Public Key Cryptography} \mysection{Introduction} RSA wrote the PKCS \#1 specifications which detail RSA Public Key Cryptography. In the specifications are -padding algorithms for encryption and signatures. The standard includes the \textit{v2.1} algorithms. -To simplify matters a little the v2.1 encryption and signature padding algorithms are called OAEP and PSS -respectively. +padding algorithms for encryption and signatures. The standard includes the \textit{v1.5} and \textit{v2.1} algorithms. +To simplify matters a little the v2.1 encryption and signature padding algorithms are called OAEP and PSS respectively. -\mysection{PKCS \#1 Encryption} +\mysection{PKCS \#1 Padding} +PKCS \#1 v1.5 padding is so simple that both signature and encryption padding are performed by the same function. Note: the +signature padding does \textbf{not} include the ASN.1 padding required. That is performed by the rsa\_sign\_hash\_ex() function +documented later on in this chapter. +\subsection{PKCS \#1 v1.5 Encoding} +The following function performs PKCS \#1 v1.5 padding: +\index{pkcs\_1\_v1\_5\_encode()} +\begin{verbatim} +int pkcs_1_v1_5_encode( + const unsigned char *msg, + unsigned long msglen, + int block_type, + unsigned long modulus_bitlen, + prng_state *prng, + int prng_idx, + unsigned char *out, + unsigned long *outlen); +\end{verbatim} + +This will encode the message pointed to by \textit{msg} of length \textit{msglen} octets. The \textit{block\_type} parameter must be set to +\textbf{LTC\_PKCS\_1\_EME} to perform encryption padding. It must be set to \textbf{LTC\_PKCS\_1\_EMSA} to perform signature padding. The \textit{modulus\_bitlen} +parameter indicates the length of the modulus in bits. The padded data is stored in \textit{out} with a length of \textit{outlen} octets. The output will not be +longer than the modulus which helps allocate the correct output buffer size. + +Only encryption padding requires a PRNG. When performing signature padding the \textit{prng\_idx} parameter may be left to zero as it is not checked for validity. + +\subsection{PKCS \#1 v1.5 Decoding} +The following function performs PKCS \#1 v1.5 de--padding: +\index{pkcs\_1\_v1\_5\_decode()} +\begin{verbatim} +int pkcs_1_v1_5_decode( + const unsigned char *msg, + unsigned long msglen, + int block_type, + unsigned long modulus_bitlen, + unsigned char *out, + unsigned long *outlen, + int *is_valid); +\end{verbatim} +\index{LTC\_PKCS\_1\_EME} \index{LTC\_PKCS\_1\_EMSA} +This will remove the PKCS padding data pointed to by \textit{msg} of length \textit{msglen}. The decoded data is stored in \textit{out} of length +\textit{outlen}. If the padding is valid, a 1 is stored in \textit{is\_valid}, otherwise, a 0 is stored. The \textit{block\_type} parameter must be set to either +\textbf{LTC\_PKCS\_1\_EME} or \textbf{LTC\_PKCS\_1\_EMSA} depending on whether encryption or signature padding is being removed. + +\mysection{PKCS \#1 v2.1 Encryption} PKCS \#1 RSA Encryption amounts to OAEP padding of the input message followed by the modular exponentiation. As far as this portion of the library is concerned we are only dealing with th OAEP padding of the message. \subsection{OAEP Encoding} +The following function performs PKCS \#1 v2.1 encryption padding: + \index{pkcs\_1\_oaep\_encode()} \begin{alltt} -int pkcs_1_oaep_encode(const unsigned char *msg, - unsigned long msglen, - const unsigned char *lparam, - unsigned long lparamlen, - unsigned long modulus_bitlen, - prng_state *prng, - int prng_idx, - int hash_idx, - unsigned char *out, - unsigned long *outlen); +int pkcs_1_oaep_encode( + const unsigned char *msg, + unsigned long msglen, + const unsigned char *lparam, + unsigned long lparamlen, + unsigned long modulus_bitlen, + prng_state *prng, + int prng_idx, + int hash_idx, + unsigned char *out, + unsigned long *outlen); \end{alltt} This accepts \textit{msg} as input of length \textit{msglen} which will be OAEP padded. The \textit{lparam} variable is an additional system specific @@ -3118,15 +3146,16 @@ rsa\_exptmod() to encrypt it. \index{pkcs\_1\_oaep\_decode()} \begin{alltt} -int pkcs_1_oaep_decode(const unsigned char *msg, - unsigned long msglen, - const unsigned char *lparam, - unsigned long lparamlen, - unsigned long modulus_bitlen, - int hash_idx, - unsigned char *out, - unsigned long *outlen, - int *res); +int pkcs_1_oaep_decode( + const unsigned char *msg, + unsigned long msglen, + const unsigned char *lparam, + unsigned long lparamlen, + unsigned long modulus_bitlen, + int hash_idx, + unsigned char *out, + unsigned long *outlen, + int *res); \end{alltt} This function decodes an OAEP encoded message and outputs the original message that was passed to the OAEP encoder. \textit{msg} is the @@ -3146,15 +3175,16 @@ PSS encoding is the second half of the PKCS \#1 standard which is padding to be \index{pkcs\_1\_pss\_encode()} \begin{alltt} -int pkcs_1_pss_encode(const unsigned char *msghash, - unsigned long msghashlen, - unsigned long saltlen, - prng_state *prng, - int prng_idx, - int hash_idx, - unsigned long modulus_bitlen, - unsigned char *out, - unsigned long *outlen); +int pkcs_1_pss_encode( + const unsigned char *msghash, + unsigned long msghashlen, + unsigned long saltlen, + prng_state *prng, + int prng_idx, + int hash_idx, + unsigned long modulus_bitlen, + unsigned char *out, + unsigned long *outlen); \end{alltt} This function assumes the message to be PSS encoded has previously been hashed. The input hash \textit{msghash} is of length @@ -3173,14 +3203,15 @@ To decode a PSS encoded signature block you have to use the following. \index{pkcs\_1\_pss\_decode()} \begin{alltt} -int pkcs_1_pss_decode(const unsigned char *msghash, - unsigned long msghashlen, - const unsigned char *sig, - unsigned long siglen, - unsigned long saltlen, - int hash_idx, - unsigned long modulus_bitlen, - int *res); +int pkcs_1_pss_decode( + const unsigned char *msghash, + unsigned long msghashlen, + const unsigned char *sig, + unsigned long siglen, + unsigned long saltlen, + int hash_idx, + unsigned long modulus_bitlen, + int *res); \end{alltt} This will decode the PSS encoded message in \textit{sig} of length \textit{siglen} and compare it to values in \textit{msghash} of length \textit{msghashlen}. If the block is a valid PSS block and the decoded hash equals the hash supplied \textit{res} is set to non--zero. Otherwise, @@ -3188,7 +3219,7 @@ it is set to zero. The rest of the parameters are as in the PSS encode call. It's important to use the same \textit{saltlen} and hash for both encoding and decoding as otherwise the procedure will not work. -\mysection{RSA Operations} +\mysection{RSA Key Operations} \subsection{Background} RSA is a public key algorithm that is based on the inability to find the \textit{e-th} root modulo a composite of unknown @@ -3225,81 +3256,139 @@ For RSA routines a single \textit{rsa\_key} structure is used. To make a new RS \index{rsa\_make\_key()} \begin{verbatim} int rsa_make_key(prng_state *prng, - int wprng, int size, - long e, rsa_key *key); + int wprng, + int size, + long e, + rsa_key *key); \end{verbatim} -Where \textit{wprng} is the index into the PRNG descriptor array. \textit{size} is the size in bytes of the RSA modulus desired. -\textit{e} is the encryption exponent desired, typical values are 3, 17, 257 and 65537. I suggest you stick with 65537 since its big -enough to prevent trivial math attacks and not super slow. \textit{key} is where the key is placed. All keys must be at -least 128 bytes and no more than 512 bytes in size (\textit{that is from 1024 to 4096 bits}). +Where \textit{wprng} is the index into the PRNG descriptor array. The \textit{size} parameter is the size in bytes of the RSA modulus desired. +The \textit{e} parameter is the encryption exponent desired, typical values are 3, 17, 257 and 65537. Stick with 65537 since it is big enough to prevent +trivial math attacks, and not super slow. The \textit{key} parameter is where the constructed key is placed. All keys must be at +least 128 bytes, and no more than 512 bytes in size (\textit{that is from 1024 to 4096 bits}). -Note that the \textit{rsa\_make\_key()} function allocates memory at run-time when you make the key. Make sure to call +\index{rsa\_free()} +Note: the \textit{rsa\_make\_key()} function allocates memory at run--time when you make the key. Make sure to call \textit{rsa\_free()} (see below) when you are finished with the key. If \textit{rsa\_make\_key()} fails it will automatically -free the ram allocated itself. +free the memory allocated. \index{PK\_PRIVATE} \index{PK\_PUBLIC} There are two types of RSA keys. The types are {\bf PK\_PRIVATE} and {\bf PK\_PUBLIC}. The first type is a private -RSA key which includes the CRT parameters\footnote{As of v0.99 the PK\_PRIVATE\_OPTIMIZED type has been deprecated -and has been replaced by the PK\_PRIVATE type.} in the form of a RSAPrivateKey. The second type is a public RSA key -which only includes the modulus and public exponent. It takes the form of a RSAPublicKey. +RSA key which includes the CRT parameters\footnote{As of v0.99 the PK\_PRIVATE\_OPTIMIZED type has been deprecated, and has been replaced by the +PK\_PRIVATE type.} in the form of a RSAPrivateKey (PKCS \#1 compliant). The second type, is a public RSA key which only includes the modulus and public exponent. +It takes the form of a RSAPublicKey (PKCS \#1 compliant). \subsection{RSA Exponentiation} - -To do raw work with the RSA function call: +To do raw work with the RSA function, that is without padding, use the following function: \index{rsa\_exptmod()} \begin{verbatim} -int rsa_exptmod(const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen, - int which, rsa_key *key); +int rsa_exptmod(const unsigned char *in, + unsigned long inlen, + unsigned char *out, + unsigned long *outlen, + int which, + rsa_key *key); \end{verbatim} -This loads the bignum from \textit{in} as a big endian word in the format PKCS specifies, raises it to either \textit{e} or \textit{d} and stores the result +This will load the bignum from \textit{in} as a big endian integer in the format PKCS \#1 specifies, raises it to either \textit{e} or \textit{d} and stores the result in \textit{out} and the size of the result in \textit{outlen}. \textit{which} is set to {\bf PK\_PUBLIC} to use \textit{e} (i.e. for encryption/verifying) and set to {\bf PK\_PRIVATE} to use \textit{d} as the exponent (i.e. for decrypting/signing). -Note that the output of his function is zero-padded as per PKCS \#1 specifications. This allows this routine to -interoprate with PKCS \#1 padding functions properly. +Note: the output of this function is zero--padded as per PKCS \#1 specification. This allows this routine to work with PKCS \#1 padding functions properly. -\subsection{RSA Key Encryption} +\mysection{RSA Key Encryption} Normally RSA is used to encrypt short symmetric keys which are then used in block ciphers to encrypt a message. To facilitate encrypting short keys the following functions have been provided. \index{rsa\_encrypt\_key()} \begin{verbatim} -int rsa_encrypt_key(const unsigned char *in, - unsigned long inlen, - unsigned char *out, - unsigned long *outlen, - const unsigned char *lparam, - unsigned long lparamlen, - prng_state *prng, - int prng_idx, - int hash_idx, - rsa_key *key); +int rsa_encrypt_key( + const unsigned char *in, + unsigned long inlen, + unsigned char *out, + unsigned long *outlen, + const unsigned char *lparam, + unsigned long lparamlen, + prng_state *prng, + int prng_idx, + int hash_idx, + rsa_key *key); \end{verbatim} -This function will OAEP pad \textit{in} of length inlen bytes then RSA encrypt it and store the ciphertext -in \textit{out} of length \textit{outlen}. The \textit{lparam} and \textit{lparamlen} are the same parameters you would pass -to pkcs\_1\_oaep\_encode(). +This function will OAEP pad \textit{in} of length \textit{inlen} bytes, RSA encrypt it, and store the ciphertext +in \textit{out} of length \textit{outlen} octets. The \textit{lparam} and \textit{lparamlen} are the same parameters you would pass +to \index{pkcs\_1\_oaep\_encode()} pkcs\_1\_oaep\_encode(). +\subsection{Extended Encryption} +As of v1.15, the library supports both v1.5 and v2.1 PKCS \#1 style paddings in these higher level functions. The following is the extended +encryption function: + +\index{rsa\_encrypt\_key\_ex()} +\begin{verbatim} +int rsa_encrypt_key_ex( + const unsigned char *in, + unsigned long inlen, + unsigned char *out, + unsigned long *outlen, + const unsigned char *lparam, + unsigned long lparamlen, + prng_state *prng, + int prng_idx, + int hash_idx, + int padding, + rsa_key *key); +\end{verbatim} + +\index{LTC\_PKCS\_1\_OAEP} \index{LTC\_PKCS\_1\_V1\_5} +The parameters are all the same as for rsa\_encrypt\_key() except for the addition of the \textit{padding} parameter. It must be set to +\textbf{LTC\_PKCS\_1\_V1\_5} to perform v1.5 encryption, or set to \textbf{LTC\_PKCS\_1\_OAEP} to perform v2.1 encryption. + +When performing v1.5 encryption, the hash and lparam parameters are totally ignored and can be set to \textbf{NULL} or zero (respectively). + +\mysection{RSA Key Decryption} \index{rsa\_decrypt\_key()} \begin{verbatim} -int rsa_decrypt_key(const unsigned char *in, - unsigned long inlen, - unsigned char *out, - unsigned long *outlen, - const unsigned char *lparam, - unsigned long lparamlen, - int hash_idx, - int *stat, - rsa_key *key); +int rsa_decrypt_key( + const unsigned char *in, + unsigned long inlen, + unsigned char *out, + unsigned long *outlen, + const unsigned char *lparam, + unsigned long lparamlen, + int hash_idx, + int *stat, + rsa_key *key); \end{verbatim} -This function will RSA decrypt \textit{in} of length \textit{inlen} then OAEP depad the resulting data and store it in +This function will RSA decrypt \textit{in} of length \textit{inlen} then OAEP de-pad the resulting data and store it in \textit{out} of length \textit{outlen}. The \textit{lparam} and \textit{lparamlen} are the same parameters you would pass to pkcs\_1\_oaep\_decode(). -If the RSA decrypted data isn't a valid OAEP packet then \textit{stat} is set to $0$. Otherwise, it is set to $1$. +If the RSA decrypted data is not a valid OAEP packet then \textit{stat} is set to $0$. Otherwise, it is set to $1$. -\subsection{RSA Hash Signatures} +\subsection{Extended Decryption} +As of v1.15, the library supports both v1.5 and v2.1 PKCS \#1 style paddings in these higher level functions. The following is the extended +decryption function: + +\index{rsa\_decrypt\_key\_ex()} +\begin{verbatim} +int rsa_decrypt_key_ex( + const unsigned char *in, + unsigned long inlen, + unsigned char *out, + unsigned long *outlen, + const unsigned char *lparam, + unsigned long lparamlen, + int hash_idx, + int padding, + int *stat, + rsa_key *key); +\end{verbatim} + +Similar to the extended encryption, the new parameter \textit{padding} indicates which version of the PKCS \#1 standard to use. +It must be set to \textbf{LTC\_PKCS\_1\_V1\_5} to perform v1.5 decryption, or set to \textbf{LTC\_PKCS\_1\_OAEP} to perform v2.1 decryption. + +When performing v1.5 decryption, the hash and lparam parameters are totally ignored and can be set to \textbf{NULL} or zero (respectively). + + +\mysection{RSA Signature Generation} Similar to RSA key encryption RSA is also used to \textit{digitally sign} message digests (hashes). To facilitate this process the following functions have been provided. @@ -3316,10 +3405,42 @@ int rsa_sign_hash(const unsigned char *in, rsa_key *key); \end{verbatim} -This will PSS encode the message hash \textit{in} of length \textit{inlen}. Next the PSS encoded message will be RSA \textit{signed} and -the output is stored in \textit{out} of length \textit{outlen}. +This will PSS encode the message digest pointed to by \textit{in} of length \textit{inlen} octets. Next, the PSS encoded hash will be RSA +\textit{signed} and the output stored in the buffer pointed to by \textit{out} of length \textit{outlen} octets. +The \textit{hash\_idx} parameter indicates which hash will be used to create the PSS encoding. It should be the same as the hash used to +hash the message being signed. The \textit{saltlen} parameter indicates the length of the desired salt, and should typically be small. A good +default value is between 8 and 16 octets. Strictly, it must be small than $modulus\_len - hLen - 2$ where \textit{modulus\_len} is the size of +the RSA modulus (in octets), and \textit{hLen} is the length of the message digest produced by the chosen hash. +\subsection{Extended Signatures} + +As of v1.15, the library supports both v1.5 and v2.1 signatures. The extended signature generation function has the following prototype: + +\index{rsa\_sign\_hash\_ex()} +\begin{verbatim} +int rsa_sign_hash_ex( + const unsigned char *in, + unsigned long inlen, + unsigned char *out, + unsigned long *outlen, + int padding, + prng_state *prng, + int prng_idx, + int hash_idx, + unsigned long saltlen, + rsa_key *key); +\end{verbatim} + +This will PKCS encode the message digest pointed to by \textit{in} of length \textit{inlen} octets. Next, the PKCS encoded hash will be RSA +\textit{signed} and the output stored in the buffer pointed to by \textit{out} of length \textit{outlen} octets. The \textit{padding} parameter +must be set to \textbf{LTC\_PKCS\_1\_V1\_5} to produce a v1.5 signature, otherwise, it must be set to \textbf{LTC\_PKCS\_1\_PSS} to produce a +v2.1 signature. + +When performing a v1.5 signature the \textit{prng}, \textit{prng\_idx}, and \textit{hash\_idx} parameters are not checked and can be left to any +values such as $\lbrace$\textbf{NULL}, 0, 0$\rbrace$. + +\mysection{RSA Signature Verification} \index{rsa\_verify\_hash()} \begin{verbatim} int rsa_verify_hash(const unsigned char *sig, @@ -3332,13 +3453,41 @@ int rsa_verify_hash(const unsigned char *sig, rsa_key *key); \end{verbatim} -This will RSA \textit{verify} the signature in \textit{sig} of length \textit{siglen}. Next the RSA decoded data is PSS decoded -and the extracted hash is compared against the message hash \textit{msghash} of length \textit{msghashlen}. +This will RSA \textit{verify} the signature pointed to by \textit{sig} of length \textit{siglen} octets. Next, the RSA decoded data is PSS decoded +and the extracted hash is compared against the message digest pointed to by \textit{msghash} of length \textit{msghashlen} octets. -If the RSA decoded data is not a valid PSS message or if the PSS decoded hash does not match the \textit{msghash} -the value \textit{res} is set to $0$. Otherwise, if the function succeeds and signature is valid \textit{res} is set -to $1$. +If the RSA decoded data is not a valid PSS message, or if the PSS decoded hash does not match the \textit{msghash} +value, \textit{res} is set to $0$. Otherwise, if the function succeeds, and signature is valid \textit{res} is set to $1$. +\subsection{Extended Verification} + +As of v1.15, the library supports both v1.5 and v2.1 signature verification. The extended signature verification function has the following prototype: + +\index{rsa\_verify\_hash\_ex()} +\begin{verbatim} +int rsa_verify_hash_ex( + const unsigned char *sig, + unsigned long siglen, + const unsigned char *hash, + unsigned long hashlen, + int padding, + int hash_idx, + unsigned long saltlen, + int *stat, + rsa_key *key); +\end{verbatim} + +This will RSA \textit{verify} the signature pointed to by \textit{sig} of length \textit{siglen} octets. Next, the RSA decoded data is PKCS decoded +and the extracted hash is compared against the message digest pointed to by \textit{msghash} of length \textit{msghashlen} octets. + +If the RSA decoded data is not a valid PSS message, or if the PKCS decoded hash does not match the \textit{msghash} +value, \textit{res} is set to $0$. Otherwise, if the function succeeds, and signature is valid \textit{res} is set to $1$. + +The \textit{padding} parameter must be set to \textbf{LTC\_PKCS\_1\_V1\_5} to perform a v1.5 verification. Otherwise, it must be set to +\textbf{LTC\_PKCS\_1\_PSS} to perform a v2.1 verification. When performing a v1.5 verification the \textit{hash\_idx} parameter is ignored. + +\mysection{RSA Encryption Example} +\begin{small} \begin{verbatim} #include int main(void) @@ -3410,6 +3559,12 @@ int main(void) /* if all went well pt == pt2, l2 == 16, res == 1 */ } \end{verbatim} +\end{small} + +\mysection{RSA Key Format} + +The RSA key format adopted for exporting and importing keys is the PKCS \#1 format defined by the ASN.1 constructs known as +RSAPublicKey and RSAPrivateKey. Additionally, the OpenSSL key format is supported by the import function only. \subsection{RSA Key Export} To export a RSA key use the following function. @@ -3455,6 +3610,9 @@ The curves in this library are taken from the following website: http://csrc.nist.gov/cryptval/dss.htm \end{verbatim} +As of v1.15 three new curves from the SECG standards are also included they are the secp112r1, secp128r1, and secp160r1 curves. These curves were added to +support smaller devices which do not need as large keys for security. + They are all curves over the integers modulo a prime. The curves have the basic equation that is: \begin{equation} y^2 = x^3 - 3x + b\mbox{ }(\mbox{mod }p) @@ -3462,13 +3620,14 @@ y^2 = x^3 - 3x + b\mbox{ }(\mbox{mod }p) The variable $b$ is chosen such that the number of points is nearly maximal. In fact the order of the base points $\beta$ provided are very close to $p$ that is $\vert \vert \phi(\beta) \vert \vert \approx \vert \vert p \vert \vert$. The curves -range in order from $\approx 2^{192}$ points to $\approx 2^{521}$. According to the source document any key size greater +range in order from $\approx 2^{112}$ points to $\approx 2^{521}$. According to the source document any key size greater than or equal to 256-bits is sufficient for long term security. \mysection{Fixed Point Optimizations} \index{Fixed Point ECC} +\index{MECC\_FP} As of v1.12 of LibTomCrypt, support for Fixed Point ECC point multiplication has been added. It is a generic optimization that is -supported by any conformant math plugin. It is enabled by defining \textbf{MECC\_FP} during the build, such as +supported by any conforming math plugin. It is enabled by defining \textbf{MECC\_FP} during the build, such as \begin{verbatim} CFLAGS="-DTFM_DESC -DMECC_FP" make @@ -3478,13 +3637,13 @@ which will build LTC using the TFM math library and enabling this new feature. safe (by default). It supports the LTC locking macros (such as by enabling LTC\_PTHREAD), but by default is not locked. \index{FP\_ENTRIES} -The optimization works by using a Fixed Point point multiplier on any base point you use twice or more in a short period of time. It has a limited size +The optimization works by using a Fixed Point multiplier on any base point you use twice or more in a short period of time. It has a limited size cache (of FP\_ENTRIES entries) which it uses to hold recent bases passed to ltc\_ecc\_mulmod(). Any base detected to be used twice is sent through the -pre--computation phase and then the fixed point algorithm can be used. For example, if you use a NIST base point twice in a row, the 2nd and +pre--computation phase, and then the fixed point algorithm can be used. For example, if you use a NIST base point twice in a row, the 2$^{nd}$ and all subsequent point multiplications with that point will use the faster algorithm. \index{FP\_LUT} -The optimization uses a window on the multiplicand of FP\_LUT bits (default: 8, min: 2, max: 12) and controls the memory/time trade-off. The larger the +The optimization uses a window on the multiplicand of FP\_LUT bits (default: 8, min: 2, max: 12), and this controls the memory/time trade-off. The larger the value the faster the algorithm will be but the more memory it will take. The memory usage is $3 \cdot 2^{FP\_LUT}$ integers which by default with TFM amounts to about 400kB of memory. Tuning TFM (by changing FP\_SIZE) can decrease the usage by a fair amount. Memory is only used by a cache entry if it is active. Both FP\_ENTRIES and FP\_LUT are definable on the command line if you wish to override them. For instance, @@ -3494,15 +3653,17 @@ CFLAGS="-DTFM_DESC -DMECC_FP -DFP_ENTRIES=8 -DFP_LUT=6" make \end{verbatim} \begin{flushleft} -would define a window of 6 bits and limit the cache to 8 entries. Generally it's better to first tune TFM by adjusting FP\_SIZE (from tfm.h). It defaults +\index{FP\_SIZE} \index{TFM} \index{tfm.h} +would define a window of 6 bits and limit the cache to 8 entries. Generally, it is better to first tune TFM by adjusting FP\_SIZE (from tfm.h). It defaults to 4096 bits (512 bytes) which is way more than what is required by ECC. At most, you need 1152 bits to accommodate ECC--521. If you're only using (say) ECC--256 you will only need 576 bits, which would reduce the memory usage by 700\%. \end{flushleft} \mysection{Key Format} -LibTomCrypt uses it's own format for ECC public and private keys. While ANSI X9.63 partially specifies key formats (it covers public keys) it does it in a less -than ideally simple manner. In the case of LibTomCrypt it is meant \textbf{solely} for NIST $GF(p)$ curves. The format of the keys is as follows: +LibTomCrypt uses a unique format for ECC public and private keys. While ANSI X9.63 partially specifies key formats, it does it in a less than ideally simple manner. \ +In the case of LibTomCrypt, it is meant \textbf{solely} for NIST and SECG $GF(p)$ curves. The format of the keys is as follows: +\index{ECC Key Format} \begin{small} \begin{verbatim} ECCPublicKey ::= SEQUENCE { @@ -3526,27 +3687,82 @@ ECCPrivateKey ::= SEQUENCE { The first flags bit denotes whether the key is public (zero) or private (one). -\mysection{Core Functions} +\vfil +\mysection{ECC Curve Parameters} +The library uses the following structure to describe an elliptic curve. This is used internally, as well as by the new +extended ECC functions which allow the user to specify their own curves. + +\index{ltc\_ecc\_set\_type} +\begin{verbatim} +/** Structure defines a NIST GF(p) curve */ +typedef struct { + /** The size of the curve in octets */ + int size; + + /** name of curve */ + char *name; + + /** The prime that defines the field (encoded in hex) */ + char *prime; + + /** The fields B param (hex) */ + char *B; + + /** The order of the curve (hex) */ + char *order; + + /** The x co-ordinate of the base point on the curve (hex) */ + char *Gx; + + /** The y co-ordinate of the base point on the curve (hex) */ + char *Gy; +} ltc_ecc_set_type; +\end{verbatim} + +The curve must be of the form $y^2 = x^3 - 3x + b$, and all of the integer parameters are encoded in hexadecimal format. + +\mysection{Core Functions} \subsection{ECC Key Generation} There is a key structure called \textit{ecc\_key} used by the ECC functions. There is a function to make a key: \index{ecc\_make\_key()} \begin{verbatim} -int ecc_make_key(prng_state *prng, int wprng, - int keysize, ecc_key *key); +int ecc_make_key(prng_state *prng, + int wprng, + int keysize, + ecc_key *key); \end{verbatim} -The \textit{keysize} is the size of the modulus in bytes desired. Currently directly supported values are 24, 28, 32, 48 and 65 bytes which -correspond to key sizes of 192, 224, 256, 384 and 521 bits respectively. If you pass a key size that is between any key size it will round -the keysize up to the next available one. To free the ram allocated by a ecc\_make\_key() or ecc\_import() call use the following function. +The \textit{keysize} is the size of the modulus in bytes desired. Currently directly supported values are 12, 16, 20, 24, 28, 32, 48, and 65 bytes which +correspond to key sizes of 112, 128, 160, 192, 224, 256, 384, and 521 bits respectively. If you pass a key size that is between any key size it will round +the keysize up to the next available one. +The function will free any internally allocated resources if there is an error. + +\subsection{Extended Key Generation} +As of v1.16, the library supports an extended key generation routine which allows the user to specify their own curve. It is specified as follows: + +\index{ecc\_make\_key\_ex()} +\begin{verbatim} +int ecc_make_key_ex( + prng_state *prng, + int wprng, + ecc_key *key, + const ltc_ecc_set_type *dp); +\end{verbatim} + +This function generates a random ECC key over the curve specified by the parameters by \textit{dp}. The rest of the parameters are equivalent to +those from the original key generation function. + +\subsection{ECC Key Free} +To free the memory allocated by a ecc\_make\_key(), ecc\_make\_key\_ex(), ecc\_import(), or ecc\_import\_ex() call use the following function: \index{ecc\_free()} \begin{verbatim} void ecc_free(ecc_key *key); \end{verbatim} \subsection{ECC Key Export} -To export an ECC key. +To export an ECC key using the LibTomCrypt format call the following function: \index{ecc\_export()} \begin{verbatim} int ecc_export(unsigned char *out, @@ -3554,21 +3770,72 @@ int ecc_export(unsigned char *out, int type, ecc_key *key); \end{verbatim} -This will export the key with the given \textit{type} (\textbf{PK\_PUBLIC} or \textbf{PK\_PRIVATE}) and store it to \textit{out}. +This will export the key with the given \textit{type} (\textbf{PK\_PUBLIC} or \textbf{PK\_PRIVATE}), and store it to \textit{out}. \subsection{ECC Key Import} +The following function imports a LibTomCrypt format ECC key: \index{ecc\_import()} \begin{verbatim} int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key); \end{verbatim} - -This will import the ECC key from \textit{in} and store it in the ecc\_key structure \textit{key}. If the operation fails it will free +This will import the ECC key from \textit{in}, and store it in the ecc\_key structure pointed to by \textit{key}. If the operation fails it will free any allocated memory automatically. +\subsection{Extended Key Import} + +The following function imports a LibTomCrypt format ECC key using a specified set of curve parameters: +\index{ecc\_import\_ex()} +\begin{verbatim} +int ecc_import_ex(const unsigned char *in, + unsigned long inlen, + ecc_key *key, + const ltc_ecc_set_type *dp); +\end{verbatim} +This will import the key from the array pointed to by \textit{in} of length \textit{inlen} octets. The key is stored in +the ECC structure pointed to by \textit{key}. The curve is specified by the parameters pointed to by \textit{dp}. The function will free +all internally allocated memory upon error. + +\subsection{ANSI X9.63 Export} +The following function exports an ECC public key in the ANSI X9.63 format: + +\index{ecc\_ansi\_x963\_export()} +\begin{verbatim} +int ecc_ansi_x963_export( ecc_key *key, + unsigned char *out, + unsigned long *outlen); +\end{verbatim} +The ECC key pointed to by \textit{key} is exported in public fashion to the array pointed to by \textit{out}. The ANSI X9.63 format used is from +section 4.3.6 of the standard. It does not allow for the export of private keys. + +\subsection{ANSI X9.63 Import} +The following function imports an ANSI X9.63 section 4.3.6 format public ECC key: + +\index{ecc\_ansi\_x963\_import()} +\begin{verbatim} +int ecc_ansi_x963_import(const unsigned char *in, + unsigned long inlen, + ecc_key *key); +\end{verbatim} +This will import the key stored in the array pointed to by \textit{in} of length \textit{inlen} octets. The imported key is stored in the ECC key pointed to by +\textit{key}. The function will free any allocated memory upon error. + +\subsection{Extended ANSI X9.63 Import} +The following function allows the importing of an ANSI x9.63 section 4.3.6 format public ECC key using user specified domain parameters: + +\index{ecc\_ansi\_x963\_import\_ex()} +\begin{verbatim} +int ecc_ansi_x963_import_ex(const unsigned char *in, + unsigned long inlen, + ecc_key *key, + ltc_ecc_set_type *dp); +\end{verbatim} +This will import the key stored in the array pointed to by \textit{in} of length \textit{inlen} octets using the domain parameters pointed to by \textit{dp}. +The imported key is stored in the ECC key pointed to by \textit{key}. The function will free any allocated memory upon error. + \subsection{ECC Shared Secret} -Finally when you share your public key you can make a shared secret with the following. +To construct a Diffie-Hellman shared secret with a private and public ECC key, use the following function: \index{ecc\_shared\_secret()} \begin{verbatim} int ecc_shared_secret( ecc_key *private_key, @@ -3576,13 +3843,15 @@ int ecc_shared_secret( ecc_key *private_key, unsigned char *out, unsigned long *outlen); \end{verbatim} -The \textit{private\_key} is your own key and \textit{public\_key} is the key the other user sent you. Note that this function stores only the -$x$ co-ordinate of the shared elliptic point as described in ANSI X9.63 ECC--DH. +The \textit{private\_key} is typically the local private key, and \textit{public\_key} is the key the remote party has shared. +Note: this function stores only the $x$ co-ordinate of the shared elliptic point as described in ANSI X9.63 ECC--DH. \mysection{ECC Diffie-Hellman Encryption} -Similar to the RSA API there are two functions which encrypt and decrypt symmetric keys using the ECC public key -algorithms. +ECC--DH Encryption is performed by producing a random key, hashing it, and XOR'ing the digest against the plaintext. It is not strictly ANSI X9.63 compliant +but it is very similar. It has been extended by using an ASN.1 sequence and hash object identifiers to allow portable usage. The following function +encrypts a short string (no longer than the message digest) using this technique: +\subsection{ECC-DH Encryption} \index{ecc\_encrypt\_key()} \begin{verbatim} int ecc_encrypt_key(const unsigned char *in, @@ -3595,15 +3864,15 @@ int ecc_encrypt_key(const unsigned char *in, ecc_key *key); \end{verbatim} -Where \textit{in} is an input symmetric key of no more than 64 bytes. This function creates a random public key -and computes the hash of the shared secret. The message digest is then XOR'ed against the symmetric key. All of the required -data is placed in \textit{out} by \textit{ecc\_encrypt\_key()}. The hash chosen must produce a message digest at least as large -as the symmetric key you are trying to share. - -The data is encrypted to the public ECC \textit{key} such that only the holder of the private key can decrypt the payload. If you want -to have multiple recipients you will have to call this function for each public ECC key you want to encrypt to. +As the name implies this function encrypts a (symmetric) key, and is not intended for encrypting long messages directly. It will encrypt the +plaintext in the array pointed to by \textit{in} of length \textit{inlen} octets. It uses the public ECC key pointed to by \textit{key}, and +hash algorithm indexed by \textit{hash} to construct a shared secret which may be XOR'ed against the plaintext. The ciphertext is stored in +the output buffer pointed to by \textit{out} of length \textit{outlen} octets. +The data is encrypted to the public ECC \textit{key} such that only the holder of the private key can decrypt the payload. To have multiple +recipients multiple call to this function for each public ECC key is required. +\subsection{ECC-DH Decryption} \index{ecc\_decrypt\_key()} \begin{verbatim} int ecc_decrypt_key(const unsigned char *in, @@ -3614,11 +3883,10 @@ int ecc_decrypt_key(const unsigned char *in, \end{verbatim} This function will decrypt an encrypted payload. The \textit{key} provided must be the private key corresponding to the public key -used during encryption. If the wrong key is provided the function won't specifically return an error code. It is important +used during encryption. If the wrong key is provided the function will not specifically return an error code. It is important to use some form of challenge response in that case (e.g. compute a MAC of a known string). -\subsection{Encrypt Encryption Format} - +\subsection{ECC Encryption Format} The packet format for the encrypted keys is the following ASN.1 SEQUENCE: \begin{verbatim} @@ -3630,9 +3898,14 @@ ECCEncrypt ::= SEQUENCE { } \end{verbatim} -\mysection{ECC DSA Signatures} +\mysection{EC DSA Signatures} + +There are also functions to sign and verify messages. They use the ANSI X9.62 EC-DSA algorithm to generate and verify signatures in the +ANSI X9.62 format. + +\subsection{EC-DSA Signature Generation} +To sign a message digest (hash) use the following function: -There are also functions to sign and verify the hash of a message. \index{ecc\_sign\_hash()} \begin{verbatim} int ecc_sign_hash(const unsigned char *in, @@ -3644,10 +3917,11 @@ int ecc_sign_hash(const unsigned char *in, ecc_key *key); \end{verbatim} -This function will EC--DSA sign the message digest stored in the buffer \textit{in} of length inlen octets. The signature -will be stored in the \textit{out} buffer of length \textit{outlen}. The function requires a properly seeded PRNG and +This function will EC--DSA sign the message digest stored in the array pointed to by \textit{in} of length \textit{inlen} octets. The signature +will be stored in the array pointed to by \textit{out} of length \textit{outlen} octets. The function requires a properly seeded PRNG, and the ECC \textit{key} provided must be a private key. +\subsection{EC-DSA Signature Verification} \index{ecc\_verify\_hash()} \begin{verbatim} int ecc_verify_hash(const unsigned char *sig, @@ -3658,32 +3932,27 @@ int ecc_verify_hash(const unsigned char *sig, ecc_key *key); \end{verbatim} -This function will verify the EC-DSA signature in \textit{sig} of length \textit{siglen} against the message digest \textit{hash}. -It will store a non--zero value in \textit{stat} if the signature is valid. Note that the function will not return -an error if the signature is invalid. It will if the actual signature payload is an invalid format. They ECC \textit{key} -must be the public (or private) ECC key corresponding to the key that performed the signature. +This function will verify the EC-DSA signature in the array pointed to by \textit{sig} of length \textit{siglen} octets, against the message digest +pointed to by the array \textit{hash} of length \textit{hashlen}. It will store a non--zero value in \textit{stat} if the signature is valid. Note: +the function will not return an error if the signature is invalid. It will return an error, if the actual signature payload is an invalid format. +The ECC \textit{key} must be the public (or private) ECC key corresponding to the key that performed the signature. \subsection{Signature Format} -The signature code is an implementation of X9.62 EC--DSA and the output is conformant for GF(p) curves. +The signature code is an implementation of X9.62 EC--DSA, and the output is compliant for GF(p) curves. \mysection{ECC Keysizes} -With ECC if you try and sign a hash that is bigger than your ECC key you can run into problems. The math will still work -and in effect the signature will still work. With ECC keys the strength of the signature is limited by the size of -the hash or the size of they key, whichever is smaller. For example, if you sign with SHA256 and an ECC-192 key in effect -you have 96-bits of security. +With ECC if you try to sign a hash that is bigger than your ECC key you can run into problems. The math will still work, and in effect the signature will still +work. With ECC keys the strength of the signature is limited by the size of the hash, or the size of they key, whichever is smaller. For example, if you sign with +SHA256 and an ECC-192 key, you in effect have 96--bits of security. -The library will not warn you if you make this mistake so it is important to check yourself before using the -signatures. +The library will not warn you if you make this mistake, so it is important to check yourself before using the signatures. \chapter{Digital Signature Algorithm} \mysection{Introduction} The Digital Signature Algorithm (or DSA) is a variant of the ElGamal Signature scheme which has been modified to -reduce the bandwidth of a signature. For example, to have \textit{80-bits of security} with ElGamal you need a group of -order at least 1024-bits. With DSA you need a group of order at least 160-bits. By comparison the ElGamal signature -would require at least 256 bytes where as the DSA signature would require only at least 40 bytes. - -The API for the DSA is essentially the same as the other PK algorithms. Except in the case of DSA no encryption or -decryption routines are provided. +reduce the bandwidth of the signatures. For example, to have \textit{80-bits of security} with ElGamal, you need a group with an order of at least 1024--bits. +With DSA, you need a group of order at least 160--bits. By comparison, the ElGamal signature would require at least 256 bytes of storage, whereas the DSA signature +would require only at least 40 bytes. \mysection{Key Format} Since no useful public standard for DSA key storage was presented to me during the course of this development I made my own ASN.1 SEQUENCE which I document @@ -3720,15 +3989,17 @@ DSAPrivateKey ::= SEQUENCE { } \end{verbatim} -The leading BIT STRING has a single bit in it which is zero for public keys and one for private keys. This makes the structure uniquely decodable and easy -to work with. +The leading BIT STRING has a single bit in it which is zero for public keys and one for private keys. This makes the structure uniquely decodable, +and easy to work with. \mysection{Key Generation} To make a DSA key you must call the following function \begin{verbatim} -int dsa_make_key(prng_state *prng, int wprng, - int group_size, int modulus_size, - dsa_key *key); +int dsa_make_key(prng_state *prng, + int wprng, + int group_size, + int modulus_size, + dsa_key *key); \end{verbatim} The variable \textit{prng} is an active PRNG state and \textit{wprng} the index to the descriptor. \textit{group\_size} and \textit{modulus\_size} control the difficulty of forging a signature. Both parameters are in bytes. The larger the @@ -3799,7 +4070,7 @@ and should not be used at all. If the result is $stat = 1$ the DSA key is valid \mysection{Signatures} \subsection{Signature Generation} -To generate a DSA signature call the following function +To generate a DSA signature call the following function: \index{dsa\_sign\_hash()} \begin{verbatim} @@ -3817,7 +4088,7 @@ of the signature in \textit{outlen}. If the signature is longer than the size y is stored and the function returns an error code. The DSA \textit{key} must be of the \textbf{PK\_PRIVATE} persuasion. \subsection{Signature Verification} -To verify a hash created with that function use the following function +To verify a hash created with that function use the following function: \index{dsa\_verify\_hash()} \begin{verbatim} @@ -3832,8 +4103,9 @@ Which will verify the data in \textit{hash} of length \textit{inlen} against the It will set \textit{stat} to $1$ if the signature is valid, otherwise it sets \textit{stat} to $0$. \mysection{DSA Encrypt and Decrypt} -As of version 1.07 the DSA keys can be used to encrypt and decrypt small payloads. It works similar to the ECC encryption where -a shared key is computed and the hash of the shared key XOR'ed against the plaintext forms the ciphertext. +As of version 1.07, the DSA keys can be used to encrypt and decrypt small payloads. It works similar to the ECC encryption where +a shared key is computed, and the hash of the shared key XOR'ed against the plaintext forms the ciphertext. The format used is functional port of +the ECC encryption format to the DSA algorithm. \subsection{DSA Encryption} This function will encrypt a small payload with a recipients public DSA key. @@ -3864,11 +4136,13 @@ int dsa_decrypt_key(const unsigned char *in, unsigned long *outlen, dsa_key *key); \end{verbatim} -This will decrypt the ciphertext \textit{in} of length \textit{inlen} and store the original payload in \textit{out} of length \textit{outlen}. The DSA \textit{key} must be a private key. +This will decrypt the ciphertext \textit{in} of length \textit{inlen}, and store the original payload in \textit{out} of length \textit{outlen}. +The DSA \textit{key} must be a private key. -\mysection{Import and Export} +\mysection{DSA Key Import and Export} -To export a DSA key so that it can be transported use the following function +\subsection{DSA Key Export} +To export a DSA key so that it can be transported use the following function: \index{dsa\_export()} \begin{verbatim} int dsa_export(unsigned char *out, @@ -3880,8 +4154,9 @@ This will export the DSA \textit{key} to the buffer \textit{out} and set the len initialized to the maximum buffer size). The \textit{type} variable may be either \textbf{PK\_PRIVATE} or \textbf{PK\_PUBLIC} depending on whether you want to export a private or public copy of the DSA key. +\subsection{DSA Key Import} To import an exported DSA key use the following function - +: \index{dsa\_import()} \begin{verbatim} int dsa_import(const unsigned char *in, @@ -3896,10 +4171,10 @@ will automatically free all of the heap allocated in the process (you don't have \mysection{ASN.1 Formats} LibTomCrypt supports a variety of ASN.1 data types encoded with the Distinguished Encoding Rules (DER) suitable for various cryptographic protocols. The data types are all provided with three basic functions with \textit{similar} prototypes. One function has been dedicated to calculate the length in octets of a given -format and two functions have been dedicated to encoding and decoding the format. +format, and two functions have been dedicated to encoding and decoding the format. On top of the basic data types are the SEQUENCE and SET data types which are collections of other ASN.1 types. They are provided -in the same manner as the other data types except they use list of objects known as the \textbf{ltc\_asn1\_list} structure. It is defined as +in the same manner as the other data types except they use list of objects known as the \textbf{ltc\_asn1\_list} structure. It is defined as the following: \index{ltc\_asn1\_list structure} \begin{verbatim} @@ -3961,6 +4236,7 @@ LTC_SET_ASN1(sequence, x++, LTC_ASN1_NULL, NULL, 0); \hline LTC\_ASN1\_NULL & NULL \\ \hline LTC\_ASN1\_OBJECT\_IDENTIFIER & OBJECT IDENTIFIER \\ \hline LTC\_ASN1\_IA5\_STRING & IA5 STRING (one octet per char) \\ +\hline LTC\_ASN1\_UTF8\_STRING & UTF8 STRING (one wchar\_t per char) \\ \hline LTC\_ASN1\_PRINTABLE\_STRING & PRINTABLE STRING (one octet per char) \\ \hline LTC\_ASN1\_UTCTIME & UTCTIME (see ltc\_utctime structure) \\ \hline LTC\_ASN1\_SEQUENCE & SEQUENCE (and SEQUENCE OF) \\ @@ -4055,19 +4331,39 @@ These either encode or decode (respectively) a SEQUENCE data type where the item The list of items are specified as a triple of the form \textit{(type, size, data)} where \textit{type} is an \textbf{int}, \textit{size} is a \textbf{unsigned long} and \textit{data} is \textbf{void} pointer. The list of items must be terminated with an item with the type \textbf{LTC\_ASN1\_EOL}. -It's ideal that you cast the \textit{size} values to unsigned long to ensure that the proper data type is passed to the function. Constants such as \textit{1} without +It is ideal that you cast the \textit{size} values to unsigned long to ensure that the proper data type is passed to the function. Constants such as \textit{1} without a cast or prototype are of type \textbf{int} by default. Appending \textit{UL} or pre-pending \textit{(unsigned long)} is enough to cast it to the correct type. +\begin{small} +\begin{verbatim} +unsigned char buf[MAXBUFSIZE]; +unsigned long buflen; +int err; + + buflen = sizeof(buf); + if ((err = + der_encode_sequence_multi(buf, &buflen, + LTC_ASN1_IA5_STRING, 5UL, "Hello", + LTC_ASN1_IA5_STRING, 7UL, " World!", + LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { + // error handling + } +\end{verbatim} +\end{small} + +This example encodes a SEQUENCE with two IA5 STRING types containing ``Hello'' and `` World!'' respectively. Note the usage of the \textbf{UL} modifier +on the size parameters. This forces the compiler to pass the numbers as the required \textbf{unsigned long} type that the function expects. + \subsection{SET and SET OF} \index{SET} \index{SET OF} -SET and SET OF are related to the SEQUENCE type in that they can be pretty much be decoded with the same code. However, they are different and they should -be carefully noted. The SET type is an unordered array of ASN.1 types sorted by the TAG (type identifier) whereas the SET OF type is an ordered array of +SET and SET OF are related to the SEQUENCE type in that they can be pretty much be decoded with the same code. However, they are different, and they should +be carefully noted. The SET type is an unordered array of ASN.1 types sorted by the TAG (type identifier), whereas the SET OF type is an ordered array of a \textbf{single} ASN.1 object sorted in ascending order by the DER their respective encodings. \subsubsection{SET Encoding} -SETs use the same array structure of ltc\_asn1\_list that the SEQUENCE functions use. They are encoded with the following function. +SETs use the same array structure of ltc\_asn1\_list that the SEQUENCE functions use. They are encoded with the following function: \index{der\_encode\_set()} \begin{verbatim} @@ -4077,11 +4373,11 @@ int der_encode_set(ltc_asn1_list *list, unsigned long *outlen); \end{verbatim} -This will encode the list of ASN.1 objects in \textit{list} of length \textit{inlen} objects and store the output in \textit{out} of length \textit{outlen} bytes. The function -will make a copy of the list provided and sort it by the TAG. Objects with identical TAGs are additionally sorted on their original placement in the +This will encode the list of ASN.1 objects in \textit{list} of length \textit{inlen} objects, and store the output in \textit{out} of length \textit{outlen} bytes. +The function will make a copy of the list provided, and sort it by the TAG. Objects with identical TAGs are additionally sorted on their original placement in the array (to make the process deterministic). -This function will \textbf{NOT} recognize \textit{DEFAULT} objects and it is the responsibility of the caller to remove them as required. +This function will \textbf{NOT} recognize \textit{DEFAULT} objects, and it is the responsibility of the caller to remove them as required. \subsubsection{SET Decoding} @@ -4130,28 +4426,24 @@ Like the SET type the der\_length\_sequence() function can be used to determine To encode or decode INTEGER data types use the following functions. -\index{der\_encode\_integer()} -\index{der\_decode\_integer()} -\index{der\_length\_integer()} +\index{der\_encode\_integer()}\index{der\_decode\_integer()}\index{der\_length\_integer()} \begin{verbatim} -int der_encode_integer( mp_int *num, +int der_encode_integer( void *num, unsigned char *out, unsigned long *outlen); int der_decode_integer(const unsigned char *in, unsigned long inlen, - mp_int *num); + void *num); -int der_length_integer( mp_int *num, +int der_length_integer( void *num, unsigned long *len); \end{verbatim} -These will encode or decode a signed INTEGER data type using the \textit{mp\_int} data type to store the large INTEGER. To encode smaller values without allocating -an mp\_int to store the value the \textit{short} INTEGER functions were made available. +These will encode or decode a signed INTEGER data type using the bignum data type to store the large INTEGER. To encode smaller values without allocating +a bignum to store the value, the \textit{short} INTEGER functions were made available. -\index{der\_encode\_short\_integer()} -\index{der\_decode\_short\_integer()} -\index{der\_length\_short\_integer()} +\index{der\_encode\_short\_integer()}\index{der\_decode\_short\_integer()}\index{der\_length\_short\_integer()} \begin{verbatim} int der_encode_short_integer(unsigned long num, unsigned char *out, @@ -4170,9 +4462,7 @@ and short integer functions can encode and decode each others outputs. \subsection{ASN.1 BIT STRING} -\index{der\_encode\_bit\_string()} -\index{der\_decode\_bit\_string()} -\index{der\_length\_bit\_string()} +\index{der\_encode\_bit\_string()}\index{der\_decode\_bit\_string()}\index{der\_length\_bit\_string()} \begin{verbatim} int der_encode_bit_string(const unsigned char *in, unsigned long inlen, @@ -4189,13 +4479,11 @@ int der_length_bit_string(unsigned long nbits, \end{verbatim} These will encode or decode a BIT STRING data type. The bits are passed in (or read out) using one \textbf{char} per bit. A non--zero value will be interpreted -as a one bit and a zero value a zero bit. +as a one bit, and a zero value a zero bit. \subsection{ASN.1 OCTET STRING} -\index{der\_encode\_octet\_string()} -\index{der\_decode\_octet\_string()} -\index{der\_length\_octet\_string()} +\index{der\_encode\_octet\_string()}\index{der\_decode\_octet\_string()}\index{der\_length\_octet\_string()} \begin{verbatim} int der_encode_octet_string(const unsigned char *in, unsigned long inlen, @@ -4211,13 +4499,11 @@ int der_length_octet_string(unsigned long noctets, unsigned long *outlen); \end{verbatim} -These will encode or decode an OCTET STRING data type. The octets are stored using one \textbf{char} each. +These will encode or decode an OCTET STRING data type. The octets are stored using one \textbf{unsigned char} each. \subsection{ASN.1 OBJECT IDENTIFIER} -\index{der\_encode\_object\_identifier()} -\index{der\_decode\_object\_identifier()} -\index{der\_length\_object\_identifier()} +\index{der\_encode\_object\_identifier()}\index{der\_decode\_object\_identifier()}\index{der\_length\_object\_identifier()} \begin{verbatim} int der_encode_object_identifier(unsigned long *words, unsigned long nwords, @@ -4234,14 +4520,12 @@ int der_length_object_identifier(unsigned long *words, unsigned long *outlen); \end{verbatim} -These will encode or decode an OBJECT IDENTIFIER object. The words of the OID are stored in individual \textbf{unsigned long} elements and must be in the range +These will encode or decode an OBJECT IDENTIFIER object. The words of the OID are stored in individual \textbf{unsigned long} elements, and must be in the range $0 \ldots 2^{32} - 1$. \subsection{ASN.1 IA5 STRING} -\index{der\_encode\_ia5\_string()} -\index{der\_decode\_ia5\_string()} -\index{der\_length\_ia5\_string()} +\index{der\_encode\_ia5\_string()}\index{der\_decode\_ia5\_string()}\index{der\_length\_ia5\_string()} \begin{verbatim} int der_encode_ia5_string(const unsigned char *in, unsigned long inlen, @@ -4258,18 +4542,14 @@ int der_length_ia5_string(const unsigned char *octets, unsigned long *outlen); \end{verbatim} -These will encode or decode an IA5 STRING. The characters are read or stored in individual \textbf{char} elements. This functions performs internal character +These will encode or decode an IA5 STRING. The characters are read or stored in individual \textbf{char} elements. These functions performs internal character to numerical conversions based on the conventions of the compiler being used. For instance, on an x86\_32 machine 'A' == 65 but the same may not be true on -say a SPARC machine. Internally these functions have a table of literal characters and their numerical ASCII values. This provides a stable conversion provided -that the build platform honours the run-time platforms character conventions. - -If you're worried try building the test suite and running it. It has hard coded test vectors to ensure it is operating properly. +say a SPARC machine. Internally, these functions have a table of literal characters and their numerical ASCII values. This provides a stable conversion provided +that the build platform honours the run--time platforms character conventions. \subsection{ASN.1 PRINTABLE STRING} -\index{der\_encode\_printable\_string()} -\index{der\_decode\_printable\_string()} -\index{der\_length\_printable\_string()} +\index{der\_encode\_printable\_string()}\index{der\_decode\_printable\_string()}\index{der\_length\_printable\_string()} \begin{verbatim} int der_encode_printable_string(const unsigned char *in, unsigned long inlen, @@ -4286,17 +4566,41 @@ int der_length_printable_string(const unsigned char *octets, unsigned long *outlen); \end{verbatim} -These will encode or decode an PRINTABLE STRING. The characters are read or stored in individual \textbf{char} elements. This functions performs internal character +These will encode or decode an PRINTABLE STRING. The characters are read or stored in individual \textbf{char} elements. These functions performs internal character to numerical conversions based on the conventions of the compiler being used. For instance, on an x86\_32 machine 'A' == 65 but the same may not be true on -say a SPARC machine. Internally these functions have a table of literal characters and their numerical ASCII values. This provides a stable conversion provided +say a SPARC machine. Internally, these functions have a table of literal characters and their numerical ASCII values. This provides a stable conversion provided that the build platform honours the run-time platforms character conventions. -If you're worried try building the test suite and running it. It has hard coded test vectors to ensure it is operating properly. +\subsection{ASN.1 UTF8 STRING} + +\index{der\_encode\_utf8\_string()}\index{der\_decode\_utf8\_string()}\index{der\_length\_utf8\_string()} +\begin{verbatim} +int der_encode_utf8_string(const wchar_t *in, + unsigned long inlen, + unsigned char *out, + unsigned long *outlen); + +int der_decode_utf8_string(const unsigned char *in, + unsigned long inlen, + wchar_t *out, + unsigned long *outlen); + +int der_length_utf8_string(const wchar_t *octets, + unsigned long noctets, + unsigned long *outlen); +\end{verbatim} + +These will encode or decode an UTF8 STRING. The characters are read or stored in individual \textbf{wchar\_t} elements. These function performs no internal +mapping and treat the characters as literals. + +These functions use the \textbf{wchar\_t} type which is not universally available. In those cases, the library will typedef it to \textbf{unsigned long}. If you +intend to use the ISO C functions for working with wide--char arrays, you should make sure that wchar\_t has been defined previously. \subsection{ASN.1 UTCTIME} The UTCTIME type is to store a date and time in ASN.1 format. It uses the following structure to organize the time. +\index{ltc\_utctime structure} \begin{verbatim} typedef struct { unsigned YY, /* year 00--99 */ @@ -4311,14 +4615,11 @@ typedef struct { } ltc_utctime; \end{verbatim} -The time can be offset plus or minus a set amount of hours (off\_hh) and minutes (off\_mm). When \textit{off\_dir} is zero the time will be added otherwise it -will be subtracted. +The time can be offset plus or minus a set amount of hours (off\_hh) and minutes (off\_mm). When \textit{off\_dir} is zero, the time will be added otherwise it +will be subtracted. For instance, the array $\lbrace 5, 6, 20, 22, 4, 00, 0, 5, 0 \rbrace$ represents the current time of +\textit{2005, June 20th, 22:04:00} with a time offset of +05h00. -For instance, the array $\lbrace 5, 6, 20, 22, 4, 00, 0, 5, 0 \rbrace$ represents the current time of 2005, June 20th, 22:04:00 with a time offset of +05h00. - -\index{der\_encode\_utctime()} -\index{der\_decode\_utctime()} -\index{der\_length\_utctime()} +\index{der\_encode\_utctime()}\index{der\_decode\_utctime()}\index{der\_length\_utctime()} \begin{verbatim} int der_encode_utctime( ltc_utctime *utctime, unsigned char *out, @@ -4332,7 +4633,7 @@ int der_length_utctime( ltc_utctime *utctime, unsigned long *outlen); \end{verbatim} -The encoder will store time in one of the two ASN.1 formats, either \textit{YYMMDDhhmmssZ} or \textit{YYMMDDhhmmss$\pm$hhmm} and perform minimal error checking on the +The encoder will store time in one of the two ASN.1 formats, either \textit{YYMMDDhhmmssZ} or \textit{YYMMDDhhmmss$\pm$hhmm}, and perform minimal error checking on the input. The decoder will read all valid ASN.1 formats and perform range checking on the values (not complete but rational) useful for catching packet errors. It is suggested that decoded data be further scrutinized (e.g. days of month in particular). @@ -4353,13 +4654,13 @@ int der_decode_choice(const unsigned char *in, unsigned long outlen); \end{verbatim} -This will decode the input in the \textit{in} field of length \textit{inlen}. It uses the provided ASN.1 list specified in the \textit{list} field which has \textit{outlen} elements. -The \textit{inlen} field will be updated with the length of the decoded data type as well as the respective entry in the \textit{list} field will have the \textit{used} flag -set to non--zero to reflect it was the data type decoded. +This will decode the input in the \textit{in} field of length \textit{inlen}. It uses the provided ASN.1 list specified in the \textit{list} field which has +\textit{outlen} elements. The \textit{inlen} field will be updated with the length of the decoded data type, as well as the respective entry in the \textit{list} field +will have the \textit{used} flag set to non--zero to reflect it was the data type decoded. \subsection{ASN.1 Flexi Decoder} The ASN.1 \textit{flexi} decoder allows the developer to decode arbitrary ASN.1 DER packets (provided they use data types LibTomCrypt supports) without first knowing -the structure of the data. Where der\_decode\_sequence() requires the developer to specify the data types to decode in advance the flexi decoder is entirely +the structure of the data. Where der\_decode \_sequence() requires the developer to specify the data types to decode in advance the flexi decoder is entirely free form. The flexi decoder uses the same \textit{ltc\_asn1\_list} but instead of being stored in an array it uses the linked list pointers \textit{prev}, \textit{next}, \textit{parent} @@ -4379,15 +4680,77 @@ int der_decode_sequence_flexi(const unsigned char *in, This will decode items in the \textit{in} buffer of max input length \textit{inlen} and store the newly created pointer to the list in \textit{out}. This function allocates all required memory for the decoding. It stores the number of octets read back into \textit{inlen}. -The function will terminate when either it hits an invalid ASN.1 type octet or it reads \textit{inlen} octets. An early terminate is a soft error and returns +The function will terminate when either it hits an invalid ASN.1 tag, or it reads \textit{inlen} octets. An early termination is a soft error, and returns normally. The decoded list \textit{out} will point to the very first element of the list (e.g. both parent and prev pointers will be \textbf{NULL}). -An invalid decoding will terminate the process and free the allocated memory automatically. +An invalid decoding will terminate the process, and free the allocated memory automatically. -\textbf{Note} that the list decoded by this function is \textbf{NOT} in the correct form for der\_encode\_sequence() to use directly. You will have to first +\textbf{Note:} the list decoded by this function is \textbf{NOT} in the correct form for der\_encode\_sequence() to use directly. You will have to first have to convert the list by first storing all of the siblings in an array then storing all the children as sub-lists of a sequence using the \textit{.data} pointer. Currently no function in LibTomCrypt provides this ability. +\subsubsection{Sample Decoding} +Suppose we decode the following structure: +\begin{small} +\begin{verbatim} +User ::= SEQUENCE { + Name IA5 STRING + LoginToken SEQUENCE { + passwdHash OCTET STRING + pubkey ECCPublicKey + } + LastOn UTCTIME +} +\end{verbatim} +\end{small} +\begin{flushleft}and we decoded it with the following code:\end{flushleft} + +\begin{small} +\begin{verbatim} +unsigned char inbuf[MAXSIZE]; +unsigned long inbuflen; +ltc_asn1_list *list; +int err; + +/* somehow fill inbuf/inbuflen */ +if ((err = der_decode_sequence_flexi(inbuf, inbuflen, &list)) != CRYPT_OK) { + printf("Error decoding: %s\n", error_to_string(err)); + exit(EXIT_FAILURE); +} +\end{verbatim} +\end{small} + +At this point \textit{list} would point to the SEQUENCE identified by \textit{User}. It would have no sibblings (prev or next), and only a child node. Walking to the child +node with the following code will bring us to the \textit{Name} portion of the SEQUENCE: +\begin{small} +\begin{verbatim} +list = list->child; +\end{verbatim} +\end{small} +Now \textit{list} points to the \textit{Name} member (with the tag IA5 STRING). The \textit{data}, \textit{size}, and \textit{type} members of \textit{list} should reflect +that of an IA5 STRING. The sibbling will now be the \textit{LoginToken} SEQUENCE. The sibbling has a child node which points to the \textit{passwdHash} OCTET STRING. +We can walk to this node with the following code: +\begin{small} +\begin{verbatim} +/* list already pointing to 'Name' */ +list = list->next->child; +\end{verbatim} +\end{small} +At this point, \textit{list} will point to the \textit{passwdHash} member of the innermost SEQUENCE. This node has a sibbling, the \textit{pubkey} member of the SEQUENCE. +The \textit{LastOn} member of the SEQUENCE is a sibbling of the LoginToken node, if we wanted to walk there we would have to go up and over via: +\begin{small} +\begin{verbatim} +list = list->parent->next; +\end{verbatim} +\end{small} +At this point, we are pointing to the last node of the list. Lists are terminated in all directions by a \textbf{NULL} pointer. All nodes are doubly linked so that you +can walk up and down the nodes without keeping pointers lying around. + + + + + +\subsubsection{Free'ing a Flexi List} To free the list use the following function. \index{der\_sequence\_free()} @@ -4405,7 +4768,7 @@ is made up of two algorithms, Algorithm One and Algorithm Two. Algorithm One is for completeness. Algorithm Two is a bit more modern and more flexible to work with. \subsection{Algorithm One} -Algorithm One accepts as input a password, an 8--byte salt and an iteration counter. The iteration counter is meant to act as delay for +Algorithm One accepts as input a password, an 8--byte salt, and an iteration counter. The iteration counter is meant to act as delay for people trying to brute force guess the password. The higher the iteration counter the longer the delay. This algorithm also requires a hash algorithm and produces an output no longer than the output of the hash. @@ -4419,17 +4782,17 @@ int pkcs_5_alg1(const unsigned char *password, unsigned char *out, unsigned long *outlen) \end{alltt} -Where \textit{password} is the users password. Since the algorithm allows binary passwords you must also specify the length in \textit{password\_len}. +Where \textit{password} is the user's password. Since the algorithm allows binary passwords you must also specify the length in \textit{password\_len}. The \textit{salt} is a fixed size 8--byte array which should be random for each user and session. The \textit{iteration\_count} is the delay desired on the password. The \textit{hash\_idx} is the index of the hash you wish to use in the descriptor table. -The output of length upto \textit{outlen} is stored in \textit{out}. If \textit{outlen} is initially larger than the size of the hash functions output +The output of length up to \textit{outlen} is stored in \textit{out}. If \textit{outlen} is initially larger than the size of the hash functions output it is set to the number of bytes stored. If it is smaller than not all of the hash output is stored in \textit{out}. \subsection{Algorithm Two} -Algorithm Two is the recommended algorithm for this task. It allows variable length salts and can produce outputs larger than the -hash functions output. As such it can easily be used to derive session keys for ciphers and MACs as well initial vectors as required +Algorithm Two is the recommended algorithm for this task. It allows variable length salts, and can produce outputs larger than the +hash functions output. As such, it can easily be used to derive session keys for ciphers and MACs as well initial vectors as required from a single password and invocation of this algorithm. \index{pkcs\_5\_alg2()} @@ -4445,11 +4808,12 @@ int pkcs_5_alg2(const unsigned char *password, \end{alltt} Where \textit{password} is the users password. Since the algorithm allows binary passwords you must also specify the length in \textit{password\_len}. The \textit{salt} is an array of size \textit{salt\_len}. It should be random for each user and session. The \textit{iteration\_count} is the delay desired -on the password. The \textit{hash\_idx} is the index of the hash you wish to use in the descriptor table. The output of length upto +on the password. The \textit{hash\_idx} is the index of the hash you wish to use in the descriptor table. The output of length up to \textit{outlen} is stored in \textit{out}. \begin{verbatim} -/* demo to show how to make session state material from a password */ +/* demo to show how to make session state material + * from a password */ #include int main(void) { @@ -4465,8 +4829,9 @@ int main(void) /* create the material (100 iterations in algorithm) */ outlen = sizeof(outbuf); - if ((err = pkcs_5_alg2(password, password_len, salt, salt_len, - 100, hash_idx, outbuf, &outlen)) + if ((err = pkcs_5_alg2(password, password_len, salt, + salt_len, 100, hash_idx, outbuf, + &outlen)) != CRYPT_OK) { /* error handle */ } @@ -4482,17 +4847,16 @@ int main(void) \chapter{Miscellaneous} \mysection{Base64 Encoding and Decoding} -The library provides functions to encode and decode a RFC1521 base64 coding scheme. This means that it can decode what it -encodes but the format used does not comply to any known standard. The characters used in the mappings are: +The library provides functions to encode and decode a RFC 1521 base--64 coding scheme. The characters used in the mappings are: \begin{verbatim} ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ \end{verbatim} -Those characters should are supported in virtually any 7-bit ASCII system which means they can be used for transport over +Those characters are supported in the 7-bit ASCII map, which means they can be used for transport over common e-mail, usenet and HTTP mediums. The format of an encoded stream is just a literal sequence of ASCII characters where a group of four represent 24-bits of input. The first four chars of the encoders output is the length of the original input. After the first four characters is the rest of the message. -Often it is desirable to line wrap the output to fit nicely in an e-mail or usenet posting. The decoder allows you to +Often, it is desirable to line wrap the output to fit nicely in an e-mail or usenet posting. The decoder allows you to put any character (that is not in the above sequence) in between any character of the encoders output. You may not however, break up the first four characters. @@ -4558,37 +4922,37 @@ is very likely prime. \chapter{Programming Guidelines} \mysection{Secure Pseudo Random Number Generators} -Probably the single most vulnerable point of any cryptosystem is the PRNG. Without one generating and protecting secrets -would be impossible. The requirement that one be setup correctly is vitally important and to address this point the library -does provide two RNG sources that will address the largest amount of end users as possible. The \textit{sprng} PRNG provided -provides and easy to access source of entropy for any application on a *NIX or Windows computer. +Probably the single most vulnerable point of any cryptosystem is the PRNG. Without one, generating and protecting secrets +would be impossible. The requirement that one be setup correctly is vitally important, and to address this point the library +does provide two RNG sources that will address the largest amount of end users as possible. The \textit{sprng} PRNG provides an easy to +access source of entropy for any application on a UNIX (and the like) or Windows computer. -However, when the end user is not on one of these platforms the application developer must address the issue of finding +However, when the end user is not on one of these platforms, the application developer must address the issue of finding entropy. This manual is not designed to be a text on cryptography. I would just like to highlight that when you design a cryptosystem make sure the first problem you solve is getting a fresh source of entropy. \mysection{Preventing Trivial Errors} -Two simple ways to prevent trivial errors is to prevent overflows and to check the return values. All of the functions +Two simple ways to prevent trivial errors is to prevent overflows, and to check the return values. All of the functions which output variable length strings will require you to pass the length of the destination. If the size of your output buffer is smaller than the output it will report an error. Therefore, make sure the size you pass is correct! -Also virtually all of the functions return an error code or {\bf CRYPT\_OK}. You should detect all errors as simple -typos or such can cause algorithms to fail to work as desired. +Also, virtually all of the functions return an error code or {\bf CRYPT\_OK}. You should detect all errors, as simple +typos can cause algorithms to fail to work as desired. \mysection{Registering Your Algorithms} -To avoid linking and other run-time errors it is important to register the ciphers, hashes and PRNGs you intend to use +To avoid linking and other run--time errors it is important to register the ciphers, hashes and PRNGs you intend to use before you try to use them. This includes any function which would use an algorithm indirectly through a descriptor table. A neat bonus to the registry system is that you can add external algorithms that are not part of the library without having to hack the library. For example, suppose you have a hardware specific PRNG on your system. You could easily -write the few functions required plus a descriptor. After registering your PRNG all of the library functions that -need a PRNG can instantly take advantage of it. +write the few functions required plus a descriptor. After registering your PRNG, all of the library functions that +need a PRNG can instantly take advantage of it. The same applies for ciphers, hashes, and bignum math routines. \mysection{Key Sizes} \subsection{Symmetric Ciphers} -For symmetric ciphers use as large as of a key as possible. For the most part \textit{bits are cheap} so using a 256-bit key -is not a hard thing to do. +For symmetric ciphers, use as large as of a key as possible. For the most part \textit{bits are cheap} so using a 256--bit key +is not a hard thing to do. As a good rule of thumb do not use a key smaller than 128 bits. \subsection{Asymmetric Ciphers} The following chart gives the work factor for solving a DH/RSA public key using the NFS. The work factor for a key of order @@ -4599,6 +4963,7 @@ e^{1.923 \cdot ln(n)^{1 \over 3} \cdot ln(ln(n))^{2 \over 3}} Note that $n$ is not the bit-length but the magnitude. For example, for a 1024-bit key $n = 2^{1024}$. The work required is: +\begin{figure}[here] \begin{center} \begin{tabular}{|c|c|} \hline RSA/DH Key Size (bits) & Work Factor ($log_2$) \\ @@ -4613,12 +4978,18 @@ is: \hline \end{tabular} \end{center} +\caption{RSA/DH Key Strength} +\end{figure} The work factor for ECC keys is much higher since the best attack is still fully exponential. Given a key of magnitude $n$ it requires $\sqrt n$ work. The following table summarizes the work required: +\begin{figure}[here] \begin{center} \begin{tabular}{|c|c|} \hline ECC Key Size (bits) & Work Factor ($log_2$) \\ + \hline 112 & 56 \\ + \hline 128 & 64 \\ + \hline 160 & 80 \\ \hline 192 & 96 \\ \hline 224 & 112 \\ \hline 256 & 128 \\ @@ -4627,71 +4998,68 @@ $n$ it requires $\sqrt n$ work. The following table summarizes the work require \hline \end{tabular} \end{center} +\caption{ECC Key Strength} +\end{figure} Using the above tables the following suggestions for key sizes seems appropriate: \begin{center} \begin{tabular}{|c|c|c|} \hline Security Goal & RSA/DH Key Size (bits) & ECC Key Size (bits) \\ - \hline Short term (less than a year) & 1024 & 160 \\ - \hline Short term (less than five years) & 1536 & 192 \\ - \hline Long Term (less than ten years) & 2560 & 256 \\ + \hline Near term & 1024 & 160 \\ + \hline Short term & 1536 & 192 \\ + \hline Long Term & 2560 & 384 \\ \hline \end{tabular} \end{center} \mysection{Thread Safety} -The library is not thread safe but several simple precautions can be taken to avoid any problems. The registry functions -such as register\_cipher() are not thread safe no matter what you do. Its best to call them from your programs initialization +The library is not fully thread safe but several simple precautions can be taken to avoid any problems. The registry functions +such as register\_cipher() are not thread safe no matter what you do. It is best to call them from your programs initialization code before threads are initiated. The rest of the code uses state variables you must pass it such as hash\_state, hmac\_state, etc. This means that if each -thread has its own state variables then they will not affect each other. This is fairly simple with symmetric ciphers -and hashes. However, the keyring and PRNG support is something the threads will want to share. The simplest workaround -is create semaphores or mutexes around calls to those functions. +thread has its own state variables then they will not affect each other, and are fully thread safe. This is fairly simple with symmetric ciphers +and hashes. -Since C does not have standard semaphores this support is not native to LibTomCrypt. Even a C based semaphore is not entire -possible as some compilers may ignore the \textit{volatile} keyword or have multiple processors. Provide your host application -is modular enough putting the locks in the right place should not bloat the code significantly and will solve all thread -safety issues within the library. +\index{LTC\_PTHREAD} +The only sticky issue is a shared PRNG which can be alleviated with the careful use of mutex devices. Defining LTC\_PTHREAD for instance, enables +pthreads based mutex locking in various routines such as the Yarrow and Fortuna PRNGs, the fixed point ECC multiplier, and other routines. \chapter{Configuring and Building the Library} \mysection{Introduction} -The library is fairly flexible about how it can be built, used and generally distributed. Additions are being made with +The library is fairly flexible about how it can be built, used, and generally distributed. Additions are being made with each new release that will make the library even more flexible. Each of the classes of functions can be disabled during the build process to make a smaller library. This is particularly useful for shared libraries. -As of v1.06 of the library the build process has been moved to two steps for the typical LibTomCrypt application. This is because -LibTomCrypt no longer provides a math API on its own and relies on third party libraries (such as LibTomMath or TomsFastMath). +As of v1.06 of the library, the build process has been moved to two steps for the typical LibTomCrypt application. This is because +LibTomCrypt no longer provides a math API on its own and relies on third party libraries (such as LibTomMath, GnuMP, or TomsFastMath). -The build process now consists of installing a math library first then building and installing LibTomCrypt with a math library +The build process now consists of installing a math library first, and then building and installing LibTomCrypt with a math library configured. Note that LibTomCrypt can be built with no internal math descriptors. This means that one must be provided at either -build or run time for the application. LibTomCrypt comes with two math descriptors that provide a standard interface to math -libraries. One for LibTomMath and one for TomsFastMath. +build, or run time for the application. LibTomCrypt comes with three math descriptors that provide a standard interface to math +libraries. \mysection{Makefile variables} All GNU driven makefiles (including the makefile for ICC) use a set of common variables to control the build and install process. Most of the settings can be overwritten from the command line which makes custom installation a breeze. -\index{MAKE} -\index{CC} -\index{AR} +\index{MAKE}\index{CC}\index{AR} \subsection{MAKE, CC and AR} The MAKE, CC and AR flags can all be overwritten. They default to \textit{make}, \textit{\$CC} and \textit{\$AR} respectively. - -Changing MAKE allows you to change what program will be invoked to handle sub--directories. E.g. +Changing MAKE allows you to change what program will be invoked to handle sub--directories. For example, this \begin{verbatim} MAKE=gmake gmake install \end{verbatim} -Will build and install the libraries with the \textit{gmake} tool. Similarly +\begin{flushleft} will build and install the libraries with the \textit{gmake} tool. Similarly, \end{flushleft} \begin{verbatim} CC=arm-gcc AR=arm-ar make \end{verbatim} -Will build the library using \textit{arm--gcc} as the compiler and \textit{arm--ar} as the archiver. +\begin{flushleft} will build the library using \textit{arm--gcc} as the compiler and \textit{arm--ar} as the archiver. \end{flushleft} \subsection{IGNORE\_SPEED} \index{IGNORE\_SPEED} @@ -4769,7 +5137,8 @@ total 1073 that GCC expects for global archives. \begin{verbatim} -CFLAGS="-DTFM_DESC -DUSE_TFM" EXTRALIBS=-ltfm make install test timing +CFLAGS="-DTFM_DESC -DUSE_TFM" EXTRALIBS=-ltfm make install \ + test timing \end{verbatim} This will install the library using the TomsFastMath library and link the \textit{libtfm.a} library out of the default library search path. The two @@ -4786,15 +5155,15 @@ Building a static library is fairly trivial as it only requires one invocation o CFLAGS="-DTFM_DESC" make install \end{verbatim} -That will build LibTomCrypt (including the TomsFastMath descriptor) and install it in the default locations indicated previously. You can enable -the built--in LibTomMath descriptor as well (or in place of the TomsFastMath descriptor). Similarly you can build the library with no built--in +That will build LibTomCrypt (including the TomsFastMath descriptor), and install it in the default locations indicated previously. You can enable +the built--in LibTomMath descriptor as well (or in place of the TomsFastMath descriptor). Similarly, you can build the library with no built--in math descriptors. \begin{verbatim} make install \end{verbatim} -In this case no math descriptors are present in the library and they will have to be made available at build or run time before you can use any of the +In this case, no math descriptors are present in the library and they will have to be made available at build or run time before you can use any of the public key functions. Note that even if you include the built--in descriptors you must link against the source library as well. @@ -4819,17 +5188,18 @@ CFLAGS="-DTFM_DESC" EXTRALIBS=-ltfm make -f makefile.shared install This will build and install the library and link the shared object against the TomsFastMath library (which must be installed as a shared object as well). The shared build process requires libtool to be installed. -\mysection{tomcrypt\_cfg.h} -The file \textit{tomcrypt\_cfg.h} is what lets you control various high level macros which control the behaviour -of the library. +\mysection{Header Configuration} +The file \textit{tomcrypt\_cfg.h} is what lets you control various high level macros which control the behaviour of the library. Build options are also +stored in \textit{tomcrypt\_custom.h} which allow the enabling and disabling of various algorithms. \subsubsection{ARGTYPE} -This lets you control how the \_ARGCHK macro will behave. The macro is used to check pointers inside the functions against -NULL. There are three settings for ARGTYPE. When set to 0 it will have the default behaviour of printing a message to -stderr and raising a SIGABRT signal. This is provided so all platforms that use libtomcrypt can have an error that functions -similarly. When set to 1 it will simply pass on to the assert() macro. When set to 2 the macro will display the error to +This lets you control how the LTC\_ARGCHK macro will behave. The macro is used to check pointers inside the functions against +NULL. There are four settings for ARGTYPE. When set to 0, it will have the default behaviour of printing a message to +stderr and raising a SIGABRT signal. This is provided so all platforms that use LibTomCrypt can have an error that functions +similarly. When set to 1, it will simply pass on to the assert() macro. When set to 2, the macro will display the error to stderr then return execution to the caller. This could lead to a segmentation fault (e.g. when a pointer is \textbf{NULL}) but is useful -if you handle signals on your own. When set to 3 it will resolve to a empty macro and no error checking will be performed. +if you handle signals on your own. When set to 3, it will resolve to a empty macro and no error checking will be performed. Finally, when set +to 4, it will return CRYPT\_INVALID\_ARG to the caller. \subsubsection{Endianess} There are five macros related to endianess issues. For little endian platforms define, \textbf{ENDIAN\_LITTLE}. For big endian @@ -4840,58 +5210,38 @@ which will work on all platforms. Currently LibTomCrypt will detect x86-32, x86-64, MIPS R5900, SPARC and SPARC64 running GCC as well as x86-32 running MSVC. \mysection{The Configure Script} -There are also options you can specify from the configure script or \textit{tomcrypt\_custom.h}. +There are also options you can specify from the \textit{tomcrypt\_custom.h} header file. \subsection{X memory routines} -At the top of tomcrypt\_custom.h are four macros denoted as XMALLOC, XCALLOC, XREALLOC and XFREE which resolve to -the name of the respective functions. This lets you substitute in your own memory routines. If you substitute in -your own functions they must behave like the standard C library functions in terms of what they expect as input and -output. By default the library uses the standard C routines. +\index{XMALLOC}\index{XCALLOC}\index{XREALLOC}\index{XFREE} +At the top of tomcrypt\_custom.h are a series of macros denoted as XMALLOC, XCALLOC, XREALLOC, XFREE, and so on. They resolve to +the name of the respective functions from the standard C library by default. This lets you substitute in your own memory routines. +If you substitute in your own functions they must behave like the standard C library functions in terms of what they expect as input and +output. + +These macros are handy for working with platforms which do not have a standard C library. For instance, the OLPC\footnote{See http://dev.laptop.org/git?p=bios-crypto;a=summary} +bios code uses these macros to redirect to very compact heap and string operations. \subsection{X clock routines} The rng\_get\_bytes() function can call a function that requires the clock() function. These macros let you override the default clock() used with a replacement. By default the standard C library clock() function is used. -\subsection{NO\_FILE} -During the build if NO\_FILE is defined then any function in the library that uses file I/O will not call the file I/O +\subsection{LTC\_NO\_FILE} +During the build if LTC\_NO\_FILE is defined then any function in the library that uses file I/O will not call the file I/O functions and instead simply return CRYPT\_NOP. This should help resolve any linker errors stemming from a lack of file I/O on embedded platforms. -\subsection{CLEAN\_STACK} +\subsection{LTC\_CLEAN\_STACK} When this functions is defined the functions that store key material on the stack will clean up afterwards. Assumes that you have no memory paging with the stack. \subsection{LTC\_TEST} -When this has been defined the various self--test functions (for ciphers, hashes, prngs, etc) are included in the build. -When this has been undefined the tests are removed and if called will return CRYPT\_NOP. +When this has been defined the various self--test functions (for ciphers, hashes, prngs, etc) are included in the build. This is the default configuration. +If LTC\_NO\_TEST has been defined, the testing routines will be compacted and only return CRYPT\_NOP. -\subsection{Symmetric Ciphers, One-way Hashes, PRNGS and Public Key Functions} -There are a plethora of macros for the ciphers, hashes, PRNGs and public key functions which are fairly -self-explanatory. When they are defined the functionality is included otherwise it is not. There are some -dependency issues which are noted in the file. For instance, Yarrow requires CTR chaining mode, a block -cipher and a hash function. - -Also see technical note number five for more details. - -\subsection{TWOFISH\_SMALL and TWOFISH\_TABLES} -Twofish is a 128-bit symmetric block cipher that is provided within the library. The cipher itself is flexible enough -to allow some trade-offs in the implementation. When TWOFISH\_SMALL is defined the scheduled symmetric key for Twofish -requires only 200 bytes of memory. This is achieved by not pre-computing the substitution boxes. Having this -defined will also greatly slow down the cipher. When this macro is not defined Twofish will pre-compute the -tables at a cost of 4KB of memory. The cipher will be much faster as a result. - -When TWOFISH\_TABLES is defined the cipher will use pre-computed (and fixed in code) tables required to work. This is -useful when TWOFISH\_SMALL is defined as the table values are computed on the fly. When this is defined the code size -will increase by approximately 500 bytes. If this is defined but TWOFISH\_SMALL is not the cipher will still work but -it will not speed up the encryption or decryption functions. - -\subsection{GCM\_TABLES} -When defined GCM will use a 64KB table (per GCM state) which will greatly speed up the per--packet latency. -It also increases the initialization time and isn't suitable when you are going to use a key a few times only. - -\subsection{SMALL\_CODE} -When this is defined some of the code such as the Rijndael and SAFER+ ciphers are replaced with smaller code variants. -These variants are slower but can save quite a bit of code space. +\subsection{LTC\_NO\_FAST} +When this has been defined the library will not use faster word oriented operations. By default, they are only enabled for platforms +which can be auto-detected. This macro ensures that they are never enabled. \subsection{LTC\_FAST} This mode (auto-detected with x86\_32,x86\_64 platforms with GCC or MSVC) configures various routines such as ctr\_encrypt() or @@ -4913,11 +5263,54 @@ whole word XOR operations. These operations will be unaligned. The simplest precaution is to make sure you process all data in power of two blocks and handle \textit{remainder} at the end. e.g. If you are CTR'ing a long stream process it in blocks of (say) four kilobytes and handle any remaining incomplete blocks at the end of the stream. +\index{LTC\_FAST\_TYPE} If you do plan on using the \textit{LTC\_FAST} mode you have to also define a \textit{LTC\_FAST\_TYPE} macro which resolves to an optimal sized data type you can perform integer operations with. Ideally it should be four or eight bytes since it must properly divide the size of your block cipher (e.g. 16 bytes for AES). This means sadly if you're on a platform with 57--bit words (or something) you can't use this mode. So sad. +\subsection{LTC\_NO\_ASM} +When this has been defined the library will not use any inline assembler. Only a few platforms support assembler inlines but various versions of ICC and GCC +cannot handle all of the assembler functions. + +\subsection{Symmetric Ciphers, One-way Hashes, PRNGS and Public Key Functions} +There are a plethora of macros for the ciphers, hashes, PRNGs and public key functions which are fairly +self-explanatory. When they are defined the functionality is included otherwise it is not. There are some +dependency issues which are noted in the file. For instance, Yarrow requires CTR chaining mode, a block +cipher and a hash function. + +Also see technical note number five for more details. + +\subsection{LTC\_EASY} +When defined the library is configured to build fewer algorithms and modes. Mostly it sticks to NIST and ANSI approved algorithms. See +the header file \textit{tomcrypt\_custom.h} for more details. It is meant to provide literally an easy method of trimming the library +build to the most minimum of useful functionality. + +\subsection{TWOFISH\_SMALL and TWOFISH\_TABLES} +Twofish is a 128-bit symmetric block cipher that is provided within the library. The cipher itself is flexible enough +to allow some trade-offs in the implementation. When TWOFISH\_SMALL is defined the scheduled symmetric key for Twofish +requires only 200 bytes of memory. This is achieved by not pre-computing the substitution boxes. Having this +defined will also greatly slow down the cipher. When this macro is not defined Twofish will pre-compute the +tables at a cost of 4KB of memory. The cipher will be much faster as a result. + +When TWOFISH\_TABLES is defined the cipher will use pre-computed (and fixed in code) tables required to work. This is +useful when TWOFISH\_SMALL is defined as the table values are computed on the fly. When this is defined the code size +will increase by approximately 500 bytes. If this is defined but TWOFISH\_SMALL is not the cipher will still work but +it will not speed up the encryption or decryption functions. + +\subsection{GCM\_TABLES} +When defined GCM will use a 64KB table (per GCM state) which will greatly speed up the per--packet latency. +It also increases the initialization time and is not suitable when you are going to use a key a few times only. + +\subsection{GCM\_TABLES\_SSE2} +\index{SSE2} +When defined GCM will use the SSE2 instructions to perform the $GF(2^x)$ multiply using 16 128--bit XOR operations. It shaves a few cycles per byte +of GCM output on both the AMD64 and Intel Pentium 4 platforms. Requires GCC and an SSE2 equipped platform. + +\subsection{LTC\_SMALL\_CODE} +When this is defined some of the code such as the Rijndael and SAFER+ ciphers are replaced with smaller code variants. +These variants are slower but can save quite a bit of code space. + \subsection{LTC\_PTHREAD} When this is activated all of the descriptor table functions will use pthread locking to ensure thread safe updates to the tables. Note that it doesn't prevent a thread that is passively using a table from being messed up by another thread that updates the table. @@ -4931,56 +5324,63 @@ algorithm which prevents leaking key bits of the private key (scalar). It is a where timing side channels pose a significant threat. \subsection{Math Descriptors} -The library comes with two math descriptors that allow you to interface the public key cryptography API to freely available math -libraries. In this case LibTomMath and TomsFastMath. When either of \textbf{LTM\_DESC} or \textbf{TFM\_DESC} are defined -descriptors for the respective library are built and included in the library as \textit{ltm\_desc} or \textit{tfm\_desc} respectively. +The library comes with three math descriptors that allow you to interface the public key cryptography API to freely available math +libraries. When \textbf{GMP\_DESC}, \textbf{LTM\_DESC}, or \textbf{TFM\_DESC} are defined +descriptors for the respective library are built and included in the library as \textit{gmp\_desc}, \textit{ltm\_desc}, or \textit{tfm\_desc} respectively. -In the test demos that use the libraries the additional flags \textbf{USE\_LTM} and \textbf{USE\_TFM} can be defined -to tell the program which library to use. They cannot both be defined at once. +In the test demos that use the libraries the additional flags \textbf{USE\_GMP}, \textbf{USE\_LTM}, and \textbf{USE\_TFM} can be defined +to tell the program which library to use. Only one of the USE flags can be defined at once. -\index{LTM\_DESC} \index{TFM\_DESC} \index{USE\_LTM} \index{USE\_TFM} +\index{GMP\_DESC} \index{USE\_GMP} \index{LTM\_DESC} \index{TFM\_DESC} \index{USE\_LTM} \index{USE\_TFM} \begin{small} \begin{verbatim} -CFLAGS="-DLTM_DESC -DTFM_DESC -DUSE_TFM" EXTRALIBS="-ltommath -ltfm" - make -f makefile.shared install timing +CFLAGS="-DGMP_DESC -DLTM_DESC -DTFM_DESC -DUSE_TFM" \ +EXTRALIBS="-lgmp -ltommath -ltfm" make -f makefile.shared install timing \end{verbatim} \end{small} -That will build and install the library with both descriptors (and link against both) but then only use TomsFastMath in the timing demo. +That will build and install the library with all descriptors (and link against all), but only use TomsFastMath in the timing demo. \chapter{Optimizations} \mysection{Introduction} -The entire API was designed with plug and play in mind at the low level. That is you can swap out any cipher, hash or PRNG and dependent API will not require -updating. This has the nice benefit that I can add ciphers not have to re--write large portions of the API. For the most part LibTomCrypt has also been written +The entire API was designed with plug and play in mind at the low level. That is you can swap out any cipher, hash, PRNG or bignum library and the dependent API will not +require updating. This has the nice benefit that one can add ciphers (etc.) not have to re--write portions of the API. For the most part, LibTomCrypt has also been written to be highly portable and easy to build out of the box on pretty much any platform. As such there are no assembler inlines throughout the code, I make no assumptions about the platform, etc... -That works well for most cases but there are times where time is of the essence. This API also allows optimized routines to be dropped in--place of the existing -portable routines. For instance, hand optimized assembler versions of AES could be provided and any existing function that uses the cipher could automatically use +That works well for most cases but there are times where performance is of the essence. This API allows optimized routines to be dropped in--place of the existing +portable routines. For instance, hand optimized assembler versions of AES could be provided. Any existing function that uses the cipher could automatically use the optimized code without re--writing. This also paves the way for hardware drivers that can access hardware accelerated cryptographic devices. At the heart of this flexibility is the \textit{descriptor} system. A descriptor is essentially just a C \textit{struct} which describes the algorithm and provides pointers -to functions that do the work. For a given class of operation (e.g. cipher, hash, prng) the functions have identical prototypes which makes development simple. In most -dependent routines all a developer has to do is register\_XXX() the descriptor and they're set. +to functions that do the required work. For a given class of operation (e.g. cipher, hash, prng, bignum) the functions of a descriptor have identical prototypes which makes +development simple. In most dependent routines all an end developer has to do is register\_XXX() the descriptor and they are set. \mysection{Ciphers} The ciphers in LibTomCrypt are accessed through the ltc\_cipher\_descriptor structure. +\label{sec:cipherdesc} \begin{small} \begin{verbatim} struct ltc_cipher_descriptor { /** name of cipher */ char *name; + /** internal ID */ unsigned char ID; + /** min keysize (octets) */ int min_key_length, + /** max keysize (octets) */ max_key_length, + /** block size (octets) */ block_length, + /** default number of rounds */ default_rounds; + /** Setup the cipher @param key The input symmetric key @param keylen The length of the input key (octets) @@ -4988,23 +5388,34 @@ struct ltc_cipher_descriptor { @param skey [out] The destination of the scheduled key @return CRYPT_OK if successful */ - int (*setup)(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); + int (*setup)(const unsigned char *key, + int keylen, + int num_rounds, + symmetric_key *skey); + /** Encrypt a block @param pt The plaintext @param ct [out] The ciphertext @param skey The scheduled key @return CRYPT_OK if successful */ - int (*ecb_encrypt)(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); + int (*ecb_encrypt)(const unsigned char *pt, + unsigned char *ct, + symmetric_key *skey); + /** Decrypt a block @param ct The ciphertext @param pt [out] The plaintext @param skey The scheduled key @return CRYPT_OK if successful */ - int (*ecb_decrypt)(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); + int (*ecb_decrypt)(const unsigned char *ct, + unsigned char *pt, + symmetric_key *skey); + /** Test the block cipher - @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled + @return CRYPT_OK if successful, + CRYPT_NOP if self-testing has been disabled */ int (*test)(void); @@ -5014,7 +5425,8 @@ struct ltc_cipher_descriptor { void (*done)(symmetric_key *skey); /** Determine a key size - @param keysize [in/out] The size of the key desired and the suggested size + @param keysize [in/out] The size of the key desired + The suggested size @return CRYPT_OK if successful */ int (*keysize)(int *keysize); @@ -5027,8 +5439,10 @@ struct ltc_cipher_descriptor { @param skey The scheduled key context @return CRYPT_OK if successful */ - int (*accel_ecb_encrypt)(const unsigned char *pt, unsigned char *ct, - unsigned long blocks, symmetric_key *skey); + int (*accel_ecb_encrypt)(const unsigned char *pt, + unsigned char *ct, + unsigned long blocks, + symmetric_key *skey); /** Accelerated ECB decryption @param pt Plaintext @@ -5037,8 +5451,10 @@ struct ltc_cipher_descriptor { @param skey The scheduled key context @return CRYPT_OK if successful */ - int (*accel_ecb_decrypt)(const unsigned char *ct, unsigned char *pt, - unsigned long blocks, symmetric_key *skey); + int (*accel_ecb_decrypt)(const unsigned char *ct, + unsigned char *pt, + unsigned long blocks, + symmetric_key *skey); /** Accelerated CBC encryption @param pt Plaintext @@ -5048,8 +5464,10 @@ struct ltc_cipher_descriptor { @param skey The scheduled key context @return CRYPT_OK if successful */ - int (*accel_cbc_encrypt)(const unsigned char *pt, unsigned char *ct, - unsigned long blocks, unsigned char *IV, + int (*accel_cbc_encrypt)(const unsigned char *pt, + unsigned char *ct, + unsigned long blocks, + unsigned char *IV, symmetric_key *skey); /** Accelerated CBC decryption @@ -5060,8 +5478,10 @@ struct ltc_cipher_descriptor { @param skey The scheduled key context @return CRYPT_OK if successful */ - int (*accel_cbc_decrypt)(const unsigned char *ct, unsigned char *pt, - unsigned long blocks, unsigned char *IV, + int (*accel_cbc_decrypt)(const unsigned char *ct, + unsigned char *pt, + unsigned long blocks, + unsigned char *IV, symmetric_key *skey); /** Accelerated CTR encryption @@ -5073,9 +5493,12 @@ struct ltc_cipher_descriptor { @param skey The scheduled key context @return CRYPT_OK if successful */ - int (*accel_ctr_encrypt)(const unsigned char *pt, unsigned char *ct, - unsigned long blocks, unsigned char *IV, - int mode, symmetric_key *skey); + int (*accel_ctr_encrypt)(const unsigned char *pt, + unsigned char *ct, + unsigned long blocks, + unsigned char *IV, + int mode, + symmetric_key *skey); /** Accelerated LRW @param pt Plaintext @@ -5086,9 +5509,12 @@ struct ltc_cipher_descriptor { @param skey The scheduled key context @return CRYPT_OK if successful */ - int (*accel_lrw_encrypt)(const unsigned char *pt, unsigned char *ct, - unsigned long blocks, unsigned char *IV, - const unsigned char *tweak, symmetric_key *skey); + int (*accel_lrw_encrypt)(const unsigned char *pt, + unsigned char *ct, + unsigned long blocks, + unsigned char *IV, + const unsigned char *tweak, + symmetric_key *skey); /** Accelerated LRW @param ct Ciphertext @@ -5099,14 +5525,17 @@ struct ltc_cipher_descriptor { @param skey The scheduled key context @return CRYPT_OK if successful */ - int (*accel_lrw_decrypt)(const unsigned char *ct, unsigned char *pt, - unsigned long blocks, unsigned char *IV, - const unsigned char *tweak, symmetric_key *skey); + int (*accel_lrw_decrypt)(const unsigned char *ct, + unsigned char *pt, + unsigned long blocks, + unsigned char *IV, + const unsigned char *tweak, + symmetric_key *skey); /** Accelerated CCM packet (one-shot) @param key The secret key to use @param keylen The length of the secret key (octets) - @param uskey A previously scheduled key [optional can be NULL] + @param uskey A previously scheduled key [can be NULL] @param nonce The session nonce [use once] @param noncelen The length of the nonce @param header The header for the session @@ -5115,7 +5544,8 @@ struct ltc_cipher_descriptor { @param ptlen The length of the plaintext (octets) @param ct [out] The ciphertext @param tag [out] The destination tag - @param taglen [in/out] The max size and resulting size of the authentication tag + @param taglen [in/out] The max size and resulting size + of the authentication tag @param direction Encrypt or Decrypt direction (0 or 1) @return CRYPT_OK if successful */ @@ -5130,18 +5560,18 @@ struct ltc_cipher_descriptor { int direction); /** Accelerated GCM packet (one shot) - @param key The secret key - @param keylen The length of the secret key - @param IV The initial vector - @param IVlen The length of the initial vector - @param adata The additional authentication data (header) - @param adatalen The length of the adata - @param pt The plaintext - @param ptlen The length of the plaintext (ciphertext length is the same) - @param ct The ciphertext - @param tag [out] The MAC tag - @param taglen [in/out] The MAC tag length - @param direction Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT) + @param key The secret key + @param keylen The length of the secret key + @param IV The initial vector + @param IVlen The length of the initial vector + @param adata The additional authentication data (header) + @param adatalen The length of the adata + @param pt The plaintext + @param ptlen The length of the plaintext/ciphertext + @param ct The ciphertext + @param tag [out] The MAC tag + @param taglen [in/out] The MAC tag length + @param direction Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT) @return CRYPT_OK on success */ int (*accel_gcm_memory)( @@ -5152,6 +5582,49 @@ struct ltc_cipher_descriptor { unsigned char *ct, unsigned char *tag, unsigned long *taglen, int direction); + + /** Accelerated one shot OMAC + @param key The secret key + @param keylen The key length (octets) + @param in The message + @param inlen Length of message (octets) + @param out [out] Destination for tag + @param outlen [in/out] Initial and final size of out + @return CRYPT_OK on success + */ + int (*omac_memory)( + const unsigned char *key, unsigned long keylen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen); + + /** Accelerated one shot XCBC + @param key The secret key + @param keylen The key length (octets) + @param in The message + @param inlen Length of message (octets) + @param out [out] Destination for tag + @param outlen [in/out] Initial and final size of out + @return CRYPT_OK on success + */ + int (*xcbc_memory)( + const unsigned char *key, unsigned long keylen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen); + + /** Accelerated one shot F9 + @param key The secret key + @param keylen The key length (octets) + @param in The message + @param inlen Length of message (octets) + @param out [out] Destination for tag + @param outlen [in/out] Initial and final size of out + @return CRYPT_OK on success + @remark Requires manual padding + */ + int (*f9_memory)( + const unsigned char *key, unsigned long keylen, + const unsigned char *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen); }; \end{verbatim} \end{small} @@ -5179,7 +5652,7 @@ To initialize a cipher (for ECB mode) the function setup() was provided. It acc can specify the number of rounds they want through \textit{num\_rounds} where $num\_rounds = 0$ means use the default. The destination of a scheduled key is stored in \textit{skey}. -Inside the \textit{symmetric\_key} union there is a \textit{void *data} which you can use to allocate data if you need a data structure that doesn't fit with the existing +Inside the \textit{symmetric\_key} union there is a \textit{void *data} which you can use to allocate data if you need a data structure that does not fit with the existing ones provided. Just make sure in your \textit{done()} function that you free the allocated memory. \subsection{Single block ECB} @@ -5187,10 +5660,11 @@ To process a single block in ECB mode the ecb\_encrypt() and ecb\_decrypt() func must make sure you do not overwrite the output before you are finished with the input. \subsection{Testing} -The test() function is used to self--test the \textit{device}. It takes no arguments and returns \textbf{CRYPT\_OK} if all is working properly. +The test() function is used to self--test the \textit{device}. It takes no arguments and returns \textbf{CRYPT\_OK} if all is working properly. You may return +\textbf{CRYPT\_NOP} to indicate that no testing was performed. \subsection{Key Sizing} -Occasionally a function will want to find a suitable key size to use since the input is oddly sized. The keysize() function is for this case. It accepts a +Occasionally, a function will want to find a suitable key size to use since the input is oddly sized. The keysize() function is for this case. It accepts a pointer to an integer which represents the desired size. The function then has to match it to the exact or a lower key size that is valid for the cipher. For example, if the input is $25$ and $24$ is valid then it stores $24$ back in the pointed to integer. It must not round up and must return an error if the keysize cannot be mapped to a valid key size for the cipher. @@ -5259,9 +5733,26 @@ function MUST support both key passing methods. \end{small} \end{center} +\index{ccm\_memory()} This function is called when the user calls ccm\_memory(). + \subsubsection{Accelerated GCM} +\index{gcm\_memory()} This function is meant for accelerated GCM encryption or decryption. It processes the entire packet in one call. Note that the setup() function will not -be called prior to this. This function must handle scheduling the key provided on its own. +be called prior to this. This function must handle scheduling the key provided on its own. It is called when the user calls gcm\_memory(). + +\subsubsection{Accelerated OMAC} +\index{omac\_memory()} +This function is meant to perform an optimized OMAC1 (CMAC) message authentication code computation when the user calls omac\_memory(). + +\subsubsection{Accelerated XCBC-MAC} +\index{xcbc\_memory()} +This function is meant to perform an optimized XCBC-MAC message authentication code computation when the user calls xcbc\_memory(). + +\subsubsection{Accelerated F9} +\index{f9\_memory()} +This function is meant to perform an optimized F9 message authentication code computation when the user calls f9\_memory(). Like f9\_memory(), it requires +the caller to perform any 3GPP related padding before calling in order to ensure proper compliance with F9. + \mysection{One--Way Hashes} The hash functions are accessed through the ltc\_hash\_descriptor structure. @@ -5271,43 +5762,62 @@ The hash functions are accessed through the ltc\_hash\_descriptor structure. struct ltc_hash_descriptor { /** name of hash */ char *name; + /** internal ID */ unsigned char ID; + /** Size of digest in octets */ unsigned long hashsize; + /** Input block size in octets */ unsigned long blocksize; + /** ASN.1 OID */ unsigned long OID[16]; + /** Length of DER encoding */ unsigned long OIDlen; + /** Init a hash state @param hash The hash to initialize @return CRYPT_OK if successful */ int (*init)(hash_state *hash); + /** Process a block of data @param hash The hash state @param in The data to hash @param inlen The length of the data (octets) @return CRYPT_OK if successful */ - int (*process)(hash_state *hash, const unsigned char *in, unsigned long inlen); + int (*process)( hash_state *hash, + const unsigned char *in, + unsigned long inlen); + /** Produce the digest and store it @param hash The hash state @param out [out] The destination of the digest @return CRYPT_OK if successful */ - int (*done)(hash_state *hash, unsigned char *out); + int (*done)( hash_state *hash, + unsigned char *out); + /** Self-test - @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled + @return CRYPT_OK if successful, + CRYPT_NOP if self-tests have been disabled */ int (*test)(void); - /* accelerated hmac callback: if you need to-do multiple packets just use the - generic hmac_memory and provide a hash callback */ - int (*hmac_block)(const unsigned char *key, unsigned long keylen, - const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen); + + /* accelerated hmac callback: if you need to-do + multiple packets just use the generic hmac_memory + and provide a hash callback + */ + int (*hmac_block)(const unsigned char *key, + unsigned long keylen, + const unsigned char *in, + unsigned long inlen, + unsigned char *out, + unsigned long *outlen); }; \end{verbatim} \end{small} @@ -5353,53 +5863,71 @@ The pseudo--random number generators are accessible through the ltc\_prng\_descr struct ltc_prng_descriptor { /** Name of the PRNG */ char *name; + /** size in bytes of exported state */ int export_size; + /** Start a PRNG state @param prng [out] The state to initialize @return CRYPT_OK if successful */ int (*start)(prng_state *prng); + /** Add entropy to the PRNG @param in The entropy - @param inlen Length of the entropy (octets)\ + @param inlen Length of the entropy (octets) @param prng The PRNG state @return CRYPT_OK if successful */ - int (*add_entropy)(const unsigned char *in, unsigned long inlen, prng_state *prng); + int (*add_entropy)(const unsigned char *in, + unsigned long inlen, + prng_state *prng); + /** Ready a PRNG state to read from @param prng The PRNG state to ready @return CRYPT_OK if successful */ int (*ready)(prng_state *prng); + /** Read from the PRNG @param out [out] Where to store the data @param outlen Length of data desired (octets) @param prng The PRNG state to read from @return Number of octets read */ - unsigned long (*read)(unsigned char *out, unsigned long outlen, prng_state *prng); + unsigned long (*read)(unsigned char *out, + unsigned long outlen, + prng_state *prng); + /** Terminate a PRNG state @param prng The PRNG state to terminate @return CRYPT_OK if successful */ int (*done)(prng_state *prng); + /** Export a PRNG state @param out [out] The destination for the state - @param outlen [in/out] The max size and resulting size of the PRNG state + @param outlen [in/out] The max size and resulting size @param prng The PRNG to export @return CRYPT_OK if successful */ - int (*pexport)(unsigned char *out, unsigned long *outlen, prng_state *prng); + int (*pexport)(unsigned char *out, + unsigned long *outlen, + prng_state *prng); + /** Import a PRNG state @param in The data to import @param inlen The length of the data to import (octets) @param prng The PRNG to initialize/import @return CRYPT_OK if successful */ - int (*pimport)(const unsigned char *in, unsigned long inlen, prng_state *prng); + int (*pimport)(const unsigned char *in, + unsigned long inlen, + prng_state *prng); + /** Self-test the PRNG - @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled + @return CRYPT_OK if successful, + CRYPT_NOP if self-testing has been disabled */ int (*test)(void); }; @@ -5481,14 +6009,14 @@ typedef struct { /** set small constant @param a Number to write to - @param n Source upto bits_per_digit (actually meant for very small constants) + @param n Source upto bits_per_digit (meant for small constants) @return CRYPT_OK on success */ int (*set_int)(void *a, unsigned long n); /** get small constant - @param a Number to read, only fetches upto bits_per_digit from the number - @return The lower bits_per_digit of the integer (unsigned) + @param a Small number to read + @return The lower bits_per_digit of the integer (unsigned) */ unsigned long (*get_int)(void *a); @@ -5561,8 +6089,8 @@ typedef struct { int (*write_radix)(void *a, char *str, int radix); /** get size as unsigned char string - @param a The integer to get the size (when stored in array of octets) - @return The length of the integer + @param a The integer to get the size + @return The length of the integer in octets */ unsigned long (*unsigned_size)(void *a); @@ -5579,7 +6107,9 @@ typedef struct { @param len The number of octets @return CRYPT_OK on success */ - int (*unsigned_read)(void *dst, unsigned char *src, unsigned long len); + int (*unsigned_read)( void *dst, + unsigned char *src, + unsigned long len); /* ---- basic math ---- */ @@ -5593,7 +6123,8 @@ typedef struct { /** add two integers @param a The first source integer - @param b The second source integer (single digit of upto bits_per_digit in length) + @param b The second source integer + (single digit of upto bits_per_digit in length) @param c The destination of "a + b" @return CRYPT_OK on success */ @@ -5609,7 +6140,8 @@ typedef struct { /** subtract two integers @param a The first source integer - @param b The second source integer (single digit of upto bits_per_digit in length) + @param b The second source integer + (single digit of upto bits_per_digit in length) @param c The destination of "a - b" @return CRYPT_OK on success */ @@ -5617,7 +6149,8 @@ typedef struct { /** multiply two integers @param a The first source integer - @param b The second source integer (single digit of upto bits_per_digit in length) + @param b The second source integer + (single digit of upto bits_per_digit in length) @param c The destination of "a * b" @return CRYPT_OK on success */ @@ -5625,7 +6158,8 @@ typedef struct { /** multiply two integers @param a The first source integer - @param b The second source integer (single digit of upto bits_per_digit in length) + @param b The second source integer + (single digit of upto bits_per_digit in length) @param c The destination of "a * b" @return CRYPT_OK on success */ @@ -5758,11 +6292,15 @@ typedef struct { @param G The point to multiply @param R The destination for kG @param modulus The modulus for the field - @param map Boolean indicated whether to map back to affine or not (can be - ignored if you work in affine only) + @param map Boolean indicated whether to map back to affine or not + (can be ignored if you work in affine only) @return CRYPT_OK on success */ - int (*ecc_ptmul)(void *k, ecc_point *G, ecc_point *R, void *modulus, int map); + int (*ecc_ptmul)( void *k, + ecc_point *G, + ecc_point *R, + void *modulus, + int map); /** ECC GF(p) point addition @param P The first point @@ -5772,7 +6310,11 @@ typedef struct { @param mp The "b" value from montgomery_setup() @return CRYPT_OK on success */ - int (*ecc_ptadd)(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *mp); + int (*ecc_ptadd)(ecc_point *P, + ecc_point *Q, + ecc_point *R, + void *modulus, + void *mp); /** ECC GF(p) point double @param P The first point @@ -5781,36 +6323,61 @@ typedef struct { @param mp The "b" value from montgomery_setup() @return CRYPT_OK on success */ - int (*ecc_ptdbl)(ecc_point *P, ecc_point *R, void *modulus, void *mp); + int (*ecc_ptdbl)(ecc_point *P, + ecc_point *R, + void *modulus, + void *mp); - /** ECC mapping from projective to affine, currently uses (x,y,z) => (x/z^2, y/z^3, 1) + /** ECC mapping from projective to affine, + currently uses (x,y,z) => (x/z^2, y/z^3, 1) @param P The point to map @param modulus The modulus @param mp The "b" value from montgomery_setup() @return CRYPT_OK on success - @remark The mapping can be different but keep in mind a ecc_point only has - three integers (x,y,z) so if you use a different mapping you have to make it fit. + @remark The mapping can be different but keep in mind a + ecc_point only has three integers (x,y,z) so if + you use a different mapping you have to make it fit. */ int (*ecc_map)(ecc_point *P, void *modulus, void *mp); + /** Computes kA*A + kB*B = C using Shamir's Trick + @param A First point to multiply + @param kA What to multiple A by + @param B Second point to multiply + @param kB What to multiple B by + @param C [out] Destination point (can overlap with A or B) + @param modulus Modulus for curve + @return CRYPT_OK on success + */ + int (*ecc_mul2add)(ecc_point *A, void *kA, + ecc_point *B, void *kB, + ecc_point *C, + void *modulus); + + /* ---- (optional) rsa optimized math (for internal CRT) ---- */ /** RSA Key Generation @param prng An active PRNG state @param wprng The index of the PRNG desired - @param size The size of the modulus (key size) desired (octets) - @param e The "e" value (public key). e==65537 is a good choice + @param size The size of the key in octets + @param e The "e" value (public key). + e==65537 is a good choice @param key [out] Destination of a newly created private key pair @return CRYPT_OK if successful, upon error all allocated ram is freed */ - int (*rsa_keygen)(prng_state *prng, int wprng, int size, long e, rsa_key *key); + int (*rsa_keygen)(prng_state *prng, + int wprng, + int size, + long e, + rsa_key *key); /** RSA exponentiation @param in The octet array representing the base @param inlen The length of the input @param out The destination (to be stored in an octet array format) - @param outlen The length of the output buffer and the resulting size (zero padded to the - size of the modulus) + @param outlen The length of the output buffer and the resulting size + (zero padded to the size of the modulus) @param which PK_PUBLIC for public RSA and PK_PRIVATE for private RSA @param key The RSA key to use @return CRYPT_OK on success @@ -5855,9 +6422,9 @@ typedef struct { } ecc_point; \end{verbatim} -All ECC functions must use this mapping system. The only exception is when you remap all three ECC callbacks which will allow you to have more control +All ECC functions must use this mapping system. The only exception is when you remap all ECC callbacks which will allow you to have more control over how the ECC math will be implemented. Out of the box you only have three parameters per point to use $(x, y, z)$ however, these are just void pointers. They -could point to anything you want. The only further exception is the ecc\_export() function which expects the values to be in affine format. +could point to anything you want. The only further exception is the export functions which expects the values to be in affine format. \subsubsection{Point Multiply} This will multiply the point $G$ by the scalar $k$ and store the result in the point $R$. The value should be mapped to affine only if $map$ is set to one. @@ -5869,6 +6436,14 @@ may be in either affine (with $z = 1$) or projective format and the output point \subsubsection{Point Mapping} This will map the point $P$ back from projective to affine. The output point $P$ must be of the form $(x, y, 1)$. +\subsubsection{Shamir's Trick} +\index{Shamir's Trick} +\index{ltc\_ecc\_mul2add()} +To accelerate EC--DSA verification the library provides a built--in function called ltc\_ecc\_mul2add(). This performs two point multiplications and an addition in +roughly the time of one point multiplication. It is called from ecc\_verify\_hash() if an accelerator is not present. The acclerator function must allow the points to +overlap (e.g., $A \leftarrow k_1A + k_2B$) and must return the final point in affine format. + + \subsection{RSA Functions} The RSA Modular Exponentiation (ME) function is used by the RSA API to perform exponentiations for private and public key operations. In particular for private key operations it uses the CRT approach to lower the time required. It is passed an RSA key with the following format. @@ -5910,5 +6485,5 @@ Since the function is given the entire RSA key (for private keys only) CRT is po \end{document} % $Source: /cvs/libtom/libtomcrypt/crypt.tex,v $ -% $Revision: 1.103 $ -% $Date: 2006/11/17 15:03:08 $ +% $Revision: 1.123 $ +% $Date: 2006/12/16 19:08:17 $ diff --git a/doc/crypt.pdf b/doc/crypt.pdf index f22c852..7738250 100644 Binary files a/doc/crypt.pdf and b/doc/crypt.pdf differ diff --git a/makefile b/makefile index 71f875f..554f072 100644 --- a/makefile +++ b/makefile @@ -4,7 +4,7 @@ # Modified by Clay Culver # The version -VERSION=1.15 +VERSION=1.16 # Compiler and Linker Names #CC=gcc @@ -187,15 +187,17 @@ src/pk/asn1/der/set/der_encode_setof.o src/pk/asn1/der/short_integer/der_decode_ src/pk/asn1/der/short_integer/der_encode_short_integer.o \ src/pk/asn1/der/short_integer/der_length_short_integer.o src/pk/asn1/der/utctime/der_decode_utctime.o \ src/pk/asn1/der/utctime/der_encode_utctime.o src/pk/asn1/der/utctime/der_length_utctime.o \ -src/pk/dsa/dsa_decrypt_key.o src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o \ -src/pk/dsa/dsa_import.o src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_shared_secret.o \ -src/pk/dsa/dsa_sign_hash.o src/pk/dsa/dsa_verify_hash.o src/pk/dsa/dsa_verify_key.o src/pk/ecc/ecc.o \ +src/pk/asn1/der/utf8/der_decode_utf8_string.o src/pk/asn1/der/utf8/der_encode_utf8_string.o \ +src/pk/asn1/der/utf8/der_length_utf8_string.o src/pk/dsa/dsa_decrypt_key.o \ +src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o src/pk/dsa/dsa_import.o \ +src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_shared_secret.o src/pk/dsa/dsa_sign_hash.o \ +src/pk/dsa/dsa_verify_hash.o src/pk/dsa/dsa_verify_key.o src/pk/ecc/ecc.o \ src/pk/ecc/ecc_ansi_x963_export.o src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o \ src/pk/ecc/ecc_encrypt_key.o src/pk/ecc/ecc_export.o src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_size.o \ src/pk/ecc/ecc_import.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_shared_secret.o \ src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \ -src/pk/ecc/ltc_ecc_is_valid_idx.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mulmod.o \ -src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \ +src/pk/ecc/ltc_ecc_is_valid_idx.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \ +src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \ src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \ src/pk/katja/katja_decrypt_key.o src/pk/katja/katja_encrypt_key.o src/pk/katja/katja_export.o \ src/pk/katja/katja_exptmod.o src/pk/katja/katja_free.o src/pk/katja/katja_import.o \ @@ -378,5 +380,5 @@ zipup: no_oops docs # $Source: /cvs/libtom/libtomcrypt/makefile,v $ -# $Revision: 1.142 $ -# $Date: 2006/11/08 22:38:16 $ +# $Revision: 1.145 $ +# $Date: 2006/12/02 19:23:21 $ diff --git a/makefile.icc b/makefile.icc index 8e1d7d2..3fafcf1 100644 --- a/makefile.icc +++ b/makefile.icc @@ -179,15 +179,17 @@ src/pk/asn1/der/set/der_encode_setof.o src/pk/asn1/der/short_integer/der_decode_ src/pk/asn1/der/short_integer/der_encode_short_integer.o \ src/pk/asn1/der/short_integer/der_length_short_integer.o src/pk/asn1/der/utctime/der_decode_utctime.o \ src/pk/asn1/der/utctime/der_encode_utctime.o src/pk/asn1/der/utctime/der_length_utctime.o \ -src/pk/dsa/dsa_decrypt_key.o src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o \ -src/pk/dsa/dsa_import.o src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_shared_secret.o \ -src/pk/dsa/dsa_sign_hash.o src/pk/dsa/dsa_verify_hash.o src/pk/dsa/dsa_verify_key.o src/pk/ecc/ecc.o \ +src/pk/asn1/der/utf8/der_decode_utf8_string.o src/pk/asn1/der/utf8/der_encode_utf8_string.o \ +src/pk/asn1/der/utf8/der_length_utf8_string.o src/pk/dsa/dsa_decrypt_key.o \ +src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o src/pk/dsa/dsa_import.o \ +src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_shared_secret.o src/pk/dsa/dsa_sign_hash.o \ +src/pk/dsa/dsa_verify_hash.o src/pk/dsa/dsa_verify_key.o src/pk/ecc/ecc.o \ src/pk/ecc/ecc_ansi_x963_export.o src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o \ src/pk/ecc/ecc_encrypt_key.o src/pk/ecc/ecc_export.o src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_size.o \ src/pk/ecc/ecc_import.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_shared_secret.o \ src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \ -src/pk/ecc/ltc_ecc_is_valid_idx.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mulmod.o \ -src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \ +src/pk/ecc/ltc_ecc_is_valid_idx.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \ +src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \ src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \ src/pk/katja/katja_decrypt_key.o src/pk/katja/katja_encrypt_key.o src/pk/katja/katja_export.o \ src/pk/katja/katja_exptmod.o src/pk/katja/katja_free.o src/pk/katja/katja_import.o \ @@ -285,6 +287,6 @@ install: library install -g $(GROUP) -o $(USER) $(HEADERS) $(DESTDIR)$(INCPATH) # $Source: /cvs/libtom/libtomcrypt/makefile.icc,v $ -# $Revision: 1.71 $ -# $Date: 2006/11/08 22:38:16 $ +# $Revision: 1.73 $ +# $Date: 2006/12/02 19:23:21 $ diff --git a/makefile.msvc b/makefile.msvc index 85831cf..2d408df 100644 --- a/makefile.msvc +++ b/makefile.msvc @@ -89,15 +89,17 @@ src/pk/asn1/der/set/der_encode_setof.obj src/pk/asn1/der/short_integer/der_decod src/pk/asn1/der/short_integer/der_encode_short_integer.obj \ src/pk/asn1/der/short_integer/der_length_short_integer.obj src/pk/asn1/der/utctime/der_decode_utctime.obj \ src/pk/asn1/der/utctime/der_encode_utctime.obj src/pk/asn1/der/utctime/der_length_utctime.obj \ -src/pk/dsa/dsa_decrypt_key.obj src/pk/dsa/dsa_encrypt_key.obj src/pk/dsa/dsa_export.obj src/pk/dsa/dsa_free.obj \ -src/pk/dsa/dsa_import.obj src/pk/dsa/dsa_make_key.obj src/pk/dsa/dsa_shared_secret.obj \ -src/pk/dsa/dsa_sign_hash.obj src/pk/dsa/dsa_verify_hash.obj src/pk/dsa/dsa_verify_key.obj src/pk/ecc/ecc.obj \ +src/pk/asn1/der/utf8/der_decode_utf8_string.obj src/pk/asn1/der/utf8/der_encode_utf8_string.obj \ +src/pk/asn1/der/utf8/der_length_utf8_string.obj src/pk/dsa/dsa_decrypt_key.obj \ +src/pk/dsa/dsa_encrypt_key.obj src/pk/dsa/dsa_export.obj src/pk/dsa/dsa_free.obj src/pk/dsa/dsa_import.obj \ +src/pk/dsa/dsa_make_key.obj src/pk/dsa/dsa_shared_secret.obj src/pk/dsa/dsa_sign_hash.obj \ +src/pk/dsa/dsa_verify_hash.obj src/pk/dsa/dsa_verify_key.obj src/pk/ecc/ecc.obj \ src/pk/ecc/ecc_ansi_x963_export.obj src/pk/ecc/ecc_ansi_x963_import.obj src/pk/ecc/ecc_decrypt_key.obj \ src/pk/ecc/ecc_encrypt_key.obj src/pk/ecc/ecc_export.obj src/pk/ecc/ecc_free.obj src/pk/ecc/ecc_get_size.obj \ src/pk/ecc/ecc_import.obj src/pk/ecc/ecc_make_key.obj src/pk/ecc/ecc_shared_secret.obj \ src/pk/ecc/ecc_sign_hash.obj src/pk/ecc/ecc_sizes.obj src/pk/ecc/ecc_test.obj src/pk/ecc/ecc_verify_hash.obj \ -src/pk/ecc/ltc_ecc_is_valid_idx.obj src/pk/ecc/ltc_ecc_map.obj src/pk/ecc/ltc_ecc_mulmod.obj \ -src/pk/ecc/ltc_ecc_mulmod_timing.obj src/pk/ecc/ltc_ecc_points.obj \ +src/pk/ecc/ltc_ecc_is_valid_idx.obj src/pk/ecc/ltc_ecc_map.obj src/pk/ecc/ltc_ecc_mul2add.obj \ +src/pk/ecc/ltc_ecc_mulmod.obj src/pk/ecc/ltc_ecc_mulmod_timing.obj src/pk/ecc/ltc_ecc_points.obj \ src/pk/ecc/ltc_ecc_projective_add_point.obj src/pk/ecc/ltc_ecc_projective_dbl_point.obj \ src/pk/katja/katja_decrypt_key.obj src/pk/katja/katja_encrypt_key.obj src/pk/katja/katja_export.obj \ src/pk/katja/katja_exptmod.obj src/pk/katja/katja_free.obj src/pk/katja/katja_import.obj \ @@ -143,5 +145,5 @@ timing: demos/timing.c library cl $(CFLAGS) demos/timing.c testprof/tomcrypt_prof.lib tomcrypt.lib advapi32.lib $(EXTRALIBS) # $Source: /cvs/libtom/libtomcrypt/makefile.msvc,v $ -# $Revision: 1.49 $ -# $Date: 2006/11/08 22:38:16 $ +# $Revision: 1.51 $ +# $Date: 2006/12/02 19:23:21 $ diff --git a/makefile.shared b/makefile.shared index 1c5a138..a66ab1f 100644 --- a/makefile.shared +++ b/makefile.shared @@ -6,7 +6,7 @@ # Tom St Denis # The version -VERSION=0:115 +VERSION=0:116 # Compiler and Linker Names CC=libtool --mode=compile --tag=CC gcc @@ -184,15 +184,17 @@ src/pk/asn1/der/set/der_encode_setof.o src/pk/asn1/der/short_integer/der_decode_ src/pk/asn1/der/short_integer/der_encode_short_integer.o \ src/pk/asn1/der/short_integer/der_length_short_integer.o src/pk/asn1/der/utctime/der_decode_utctime.o \ src/pk/asn1/der/utctime/der_encode_utctime.o src/pk/asn1/der/utctime/der_length_utctime.o \ -src/pk/dsa/dsa_decrypt_key.o src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o \ -src/pk/dsa/dsa_import.o src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_shared_secret.o \ -src/pk/dsa/dsa_sign_hash.o src/pk/dsa/dsa_verify_hash.o src/pk/dsa/dsa_verify_key.o src/pk/ecc/ecc.o \ +src/pk/asn1/der/utf8/der_decode_utf8_string.o src/pk/asn1/der/utf8/der_encode_utf8_string.o \ +src/pk/asn1/der/utf8/der_length_utf8_string.o src/pk/dsa/dsa_decrypt_key.o \ +src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o src/pk/dsa/dsa_import.o \ +src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_shared_secret.o src/pk/dsa/dsa_sign_hash.o \ +src/pk/dsa/dsa_verify_hash.o src/pk/dsa/dsa_verify_key.o src/pk/ecc/ecc.o \ src/pk/ecc/ecc_ansi_x963_export.o src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o \ src/pk/ecc/ecc_encrypt_key.o src/pk/ecc/ecc_export.o src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_size.o \ src/pk/ecc/ecc_import.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_shared_secret.o \ src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \ -src/pk/ecc/ltc_ecc_is_valid_idx.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mulmod.o \ -src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \ +src/pk/ecc/ltc_ecc_is_valid_idx.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \ +src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \ src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \ src/pk/katja/katja_decrypt_key.o src/pk/katja/katja_encrypt_key.o src/pk/katja/katja_export.o \ src/pk/katja/katja_exptmod.o src/pk/katja/katja_free.o src/pk/katja/katja_import.o \ @@ -273,5 +275,5 @@ timing: library testprof/$(LIBTEST) $(TIMINGS) gcc -o $(TIMING) $(TIMINGS) -ltomcrypt_prof -ltomcrypt $(EXTRALIBS) # $Source: /cvs/libtom/libtomcrypt/makefile.shared,v $ -# $Revision: 1.73 $ -# $Date: 2006/11/08 22:38:16 $ +# $Revision: 1.76 $ +# $Date: 2006/12/02 19:23:21 $ diff --git a/makefile.unix b/makefile.unix new file mode 100644 index 0000000..a4e0ff0 --- /dev/null +++ b/makefile.unix @@ -0,0 +1,239 @@ +# MAKEFILE for bsd make +# +# Tom St Denis + +# Compiler and Linker Names +CC=cc +LD=ld + +# Archiver [makes .a files] +AR=ar +ARFLAGS=r + +# Compilation flags. Note the += does not write over the user's CFLAGS! +CFLAGS = -c -I./testprof/ -I./src/headers/ -DLTC_SOURCE -O2 ${CFLAGS_OPTS} -o $@ + +LIBNAME=libtomcrypt.a +LIBTEST=libtomcrypt_prof.a +LIBTEST_S=$(LIBTEST) + +HASH=hashsum +CRYPT=encrypt +SMALL=small +PROF=x86_prof +TV=tv_gen +MULTI=multi +TIMING=timing +TEST=test + +#LIBPATH-The directory for libtomcrypt to be installed to. +#INCPATH-The directory to install the header files for libtomcrypt. +#DATAPATH-The directory to install the pdf docs. +LIBPATH=/usr/local/lib +INCPATH=/usr/local/include +DATAPATH=/usr/local/share/doc/libtomcrypt/pdf + +#Who do we install as? +USER=root + +GROUP=wheel + +#List of objects to compile. +#START_INS +OBJECTS=src/ciphers/aes/aes_enc.o src/ciphers/aes/aes.o src/ciphers/anubis.o src/ciphers/blowfish.o \ +src/ciphers/cast5.o src/ciphers/des.o src/ciphers/kasumi.o src/ciphers/khazad.o src/ciphers/kseed.o \ +src/ciphers/noekeon.o src/ciphers/rc2.o src/ciphers/rc5.o src/ciphers/rc6.o src/ciphers/safer/safer.o \ +src/ciphers/safer/safer_tab.o src/ciphers/safer/saferp.o src/ciphers/skipjack.o \ +src/ciphers/twofish/twofish.o src/ciphers/xtea.o src/encauth/ccm/ccm_memory.o \ +src/encauth/ccm/ccm_test.o src/encauth/eax/eax_addheader.o src/encauth/eax/eax_decrypt.o \ +src/encauth/eax/eax_decrypt_verify_memory.o src/encauth/eax/eax_done.o src/encauth/eax/eax_encrypt.o \ +src/encauth/eax/eax_encrypt_authenticate_memory.o src/encauth/eax/eax_init.o \ +src/encauth/eax/eax_test.o src/encauth/gcm/gcm_add_aad.o 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/ocb/ocb_decrypt.o \ +src/encauth/ocb/ocb_decrypt_verify_memory.o src/encauth/ocb/ocb_done_decrypt.o \ +src/encauth/ocb/ocb_done_encrypt.o src/encauth/ocb/ocb_encrypt.o \ +src/encauth/ocb/ocb_encrypt_authenticate_memory.o src/encauth/ocb/ocb_init.o src/encauth/ocb/ocb_ntz.o \ +src/encauth/ocb/ocb_shift_xor.o src/encauth/ocb/ocb_test.o src/encauth/ocb/s_ocb_done.o \ +src/hashes/chc/chc.o src/hashes/helper/hash_file.o src/hashes/helper/hash_filehandle.o \ +src/hashes/helper/hash_memory.o src/hashes/helper/hash_memory_multi.o src/hashes/md2.o src/hashes/md4.o \ +src/hashes/md5.o src/hashes/rmd128.o src/hashes/rmd160.o src/hashes/rmd256.o src/hashes/rmd320.o \ +src/hashes/sha1.o src/hashes/sha2/sha256.o src/hashes/sha2/sha512.o src/hashes/tiger.o \ +src/hashes/whirl/whirl.o src/mac/f9/f9_done.o src/mac/f9/f9_file.o src/mac/f9/f9_init.o \ +src/mac/f9/f9_memory.o src/mac/f9/f9_memory_multi.o src/mac/f9/f9_process.o src/mac/f9/f9_test.o \ +src/mac/hmac/hmac_done.o src/mac/hmac/hmac_file.o src/mac/hmac/hmac_init.o src/mac/hmac/hmac_memory.o \ +src/mac/hmac/hmac_memory_multi.o src/mac/hmac/hmac_process.o src/mac/hmac/hmac_test.o \ +src/mac/omac/omac_done.o src/mac/omac/omac_file.o src/mac/omac/omac_init.o src/mac/omac/omac_memory.o \ +src/mac/omac/omac_memory_multi.o src/mac/omac/omac_process.o src/mac/omac/omac_test.o \ +src/mac/pelican/pelican.o src/mac/pelican/pelican_memory.o src/mac/pelican/pelican_test.o \ +src/mac/pmac/pmac_done.o src/mac/pmac/pmac_file.o src/mac/pmac/pmac_init.o src/mac/pmac/pmac_memory.o \ +src/mac/pmac/pmac_memory_multi.o src/mac/pmac/pmac_ntz.o src/mac/pmac/pmac_process.o \ +src/mac/pmac/pmac_shift_xor.o src/mac/pmac/pmac_test.o src/mac/xcbc/xcbc_done.o \ +src/mac/xcbc/xcbc_file.o src/mac/xcbc/xcbc_init.o src/mac/xcbc/xcbc_memory.o \ +src/mac/xcbc/xcbc_memory_multi.o src/mac/xcbc/xcbc_process.o src/mac/xcbc/xcbc_test.o \ +src/math/fp/ltc_ecc_fp_mulmod.o src/math/gmp_desc.o src/math/ltm_desc.o src/math/multi.o \ +src/math/rand_prime.o src/math/tfm_desc.o src/misc/base64/base64_decode.o \ +src/misc/base64/base64_encode.o src/misc/burn_stack.o src/misc/crypt/crypt.o \ +src/misc/crypt/crypt_argchk.o src/misc/crypt/crypt_cipher_descriptor.o \ +src/misc/crypt/crypt_cipher_is_valid.o src/misc/crypt/crypt_find_cipher.o \ +src/misc/crypt/crypt_find_cipher_any.o src/misc/crypt/crypt_find_cipher_id.o \ +src/misc/crypt/crypt_find_hash.o src/misc/crypt/crypt_find_hash_any.o \ +src/misc/crypt/crypt_find_hash_id.o src/misc/crypt/crypt_find_hash_oid.o \ +src/misc/crypt/crypt_find_prng.o src/misc/crypt/crypt_fsa.o src/misc/crypt/crypt_hash_descriptor.o \ +src/misc/crypt/crypt_hash_is_valid.o src/misc/crypt/crypt_ltc_mp_descriptor.o \ +src/misc/crypt/crypt_prng_descriptor.o src/misc/crypt/crypt_prng_is_valid.o \ +src/misc/crypt/crypt_register_cipher.o src/misc/crypt/crypt_register_hash.o \ +src/misc/crypt/crypt_register_prng.o src/misc/crypt/crypt_unregister_cipher.o \ +src/misc/crypt/crypt_unregister_hash.o src/misc/crypt/crypt_unregister_prng.o \ +src/misc/error_to_string.o src/misc/pkcs5/pkcs_5_1.o src/misc/pkcs5/pkcs_5_2.o src/misc/zeromem.o \ +src/modes/cbc/cbc_decrypt.o src/modes/cbc/cbc_done.o src/modes/cbc/cbc_encrypt.o \ +src/modes/cbc/cbc_getiv.o src/modes/cbc/cbc_setiv.o src/modes/cbc/cbc_start.o \ +src/modes/cfb/cfb_decrypt.o src/modes/cfb/cfb_done.o src/modes/cfb/cfb_encrypt.o \ +src/modes/cfb/cfb_getiv.o src/modes/cfb/cfb_setiv.o src/modes/cfb/cfb_start.o \ +src/modes/ctr/ctr_decrypt.o src/modes/ctr/ctr_done.o src/modes/ctr/ctr_encrypt.o \ +src/modes/ctr/ctr_getiv.o src/modes/ctr/ctr_setiv.o src/modes/ctr/ctr_start.o src/modes/ctr/ctr_test.o \ +src/modes/ecb/ecb_decrypt.o src/modes/ecb/ecb_done.o src/modes/ecb/ecb_encrypt.o \ +src/modes/ecb/ecb_start.o src/modes/f8/f8_decrypt.o src/modes/f8/f8_done.o src/modes/f8/f8_encrypt.o \ +src/modes/f8/f8_getiv.o src/modes/f8/f8_setiv.o src/modes/f8/f8_start.o src/modes/f8/f8_test_mode.o \ +src/modes/lrw/lrw_decrypt.o src/modes/lrw/lrw_done.o src/modes/lrw/lrw_encrypt.o \ +src/modes/lrw/lrw_getiv.o src/modes/lrw/lrw_process.o src/modes/lrw/lrw_setiv.o \ +src/modes/lrw/lrw_start.o src/modes/lrw/lrw_test.o src/modes/ofb/ofb_decrypt.o src/modes/ofb/ofb_done.o \ +src/modes/ofb/ofb_encrypt.o src/modes/ofb/ofb_getiv.o src/modes/ofb/ofb_setiv.o \ +src/modes/ofb/ofb_start.o src/pk/asn1/der/bit/der_decode_bit_string.o \ +src/pk/asn1/der/bit/der_encode_bit_string.o src/pk/asn1/der/bit/der_length_bit_string.o \ +src/pk/asn1/der/boolean/der_decode_boolean.o src/pk/asn1/der/boolean/der_encode_boolean.o \ +src/pk/asn1/der/boolean/der_length_boolean.o src/pk/asn1/der/choice/der_decode_choice.o \ +src/pk/asn1/der/ia5/der_decode_ia5_string.o src/pk/asn1/der/ia5/der_encode_ia5_string.o \ +src/pk/asn1/der/ia5/der_length_ia5_string.o src/pk/asn1/der/integer/der_decode_integer.o \ +src/pk/asn1/der/integer/der_encode_integer.o src/pk/asn1/der/integer/der_length_integer.o \ +src/pk/asn1/der/object_identifier/der_decode_object_identifier.o \ +src/pk/asn1/der/object_identifier/der_encode_object_identifier.o \ +src/pk/asn1/der/object_identifier/der_length_object_identifier.o \ +src/pk/asn1/der/octet/der_decode_octet_string.o src/pk/asn1/der/octet/der_encode_octet_string.o \ +src/pk/asn1/der/octet/der_length_octet_string.o \ +src/pk/asn1/der/printable_string/der_decode_printable_string.o \ +src/pk/asn1/der/printable_string/der_encode_printable_string.o \ +src/pk/asn1/der/printable_string/der_length_printable_string.o \ +src/pk/asn1/der/sequence/der_decode_sequence_ex.o \ +src/pk/asn1/der/sequence/der_decode_sequence_flexi.o \ +src/pk/asn1/der/sequence/der_decode_sequence_multi.o \ +src/pk/asn1/der/sequence/der_encode_sequence_ex.o \ +src/pk/asn1/der/sequence/der_encode_sequence_multi.o src/pk/asn1/der/sequence/der_length_sequence.o \ +src/pk/asn1/der/sequence/der_sequence_free.o src/pk/asn1/der/set/der_encode_set.o \ +src/pk/asn1/der/set/der_encode_setof.o src/pk/asn1/der/short_integer/der_decode_short_integer.o \ +src/pk/asn1/der/short_integer/der_encode_short_integer.o \ +src/pk/asn1/der/short_integer/der_length_short_integer.o src/pk/asn1/der/utctime/der_decode_utctime.o \ +src/pk/asn1/der/utctime/der_encode_utctime.o src/pk/asn1/der/utctime/der_length_utctime.o \ +src/pk/asn1/der/utf8/der_decode_utf8_string.o src/pk/asn1/der/utf8/der_encode_utf8_string.o \ +src/pk/asn1/der/utf8/der_length_utf8_string.o src/pk/dsa/dsa_decrypt_key.o \ +src/pk/dsa/dsa_encrypt_key.o src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o src/pk/dsa/dsa_import.o \ +src/pk/dsa/dsa_make_key.o src/pk/dsa/dsa_shared_secret.o src/pk/dsa/dsa_sign_hash.o \ +src/pk/dsa/dsa_verify_hash.o src/pk/dsa/dsa_verify_key.o src/pk/ecc/ecc.o \ +src/pk/ecc/ecc_ansi_x963_export.o src/pk/ecc/ecc_ansi_x963_import.o src/pk/ecc/ecc_decrypt_key.o \ +src/pk/ecc/ecc_encrypt_key.o src/pk/ecc/ecc_export.o src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_size.o \ +src/pk/ecc/ecc_import.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_shared_secret.o \ +src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_test.o src/pk/ecc/ecc_verify_hash.o \ +src/pk/ecc/ltc_ecc_is_valid_idx.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \ +src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \ +src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \ +src/pk/katja/katja_decrypt_key.o src/pk/katja/katja_encrypt_key.o src/pk/katja/katja_export.o \ +src/pk/katja/katja_exptmod.o src/pk/katja/katja_free.o src/pk/katja/katja_import.o \ +src/pk/katja/katja_make_key.o src/pk/pkcs1/pkcs_1_i2osp.o src/pk/pkcs1/pkcs_1_mgf1.o \ +src/pk/pkcs1/pkcs_1_oaep_decode.o src/pk/pkcs1/pkcs_1_oaep_encode.o src/pk/pkcs1/pkcs_1_os2ip.o \ +src/pk/pkcs1/pkcs_1_pss_decode.o src/pk/pkcs1/pkcs_1_pss_encode.o src/pk/pkcs1/pkcs_1_v1_5_decode.o \ +src/pk/pkcs1/pkcs_1_v1_5_encode.o src/pk/rsa/rsa_decrypt_key.o src/pk/rsa/rsa_encrypt_key.o \ +src/pk/rsa/rsa_export.o src/pk/rsa/rsa_exptmod.o src/pk/rsa/rsa_free.o src/pk/rsa/rsa_import.o \ +src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_sign_hash.o src/pk/rsa/rsa_verify_hash.o src/prngs/fortuna.o \ +src/prngs/rc4.o src/prngs/rng_get_bytes.o src/prngs/rng_make_prng.o src/prngs/sober128.o \ +src/prngs/sprng.o src/prngs/yarrow.o + +HEADERS=src/headers/tomcrypt_cfg.h src/headers/tomcrypt_mac.h src/headers/tomcrypt_macros.h \ +src/headers/tomcrypt_custom.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cipher.h \ +src/headers/tomcrypt_pk.h src/headers/tomcrypt_hash.h src/headers/tomcrypt_math.h \ +src/headers/tomcrypt_misc.h src/headers/tomcrypt.h src/headers/tomcrypt_pkcs.h \ +src/headers/tomcrypt_prng.h testprof/tomcrypt_test.h + +#END_INS + +TESTOBJECTS=demos/test.o +HASHOBJECTS=demos/hashsum.o +CRYPTOBJECTS=demos/encrypt.o +SMALLOBJECTS=demos/small.o +TVS=demos/tv_gen.o +MULTIS=demos/multi.o +TIMINGS=demos/timing.o +TESTS=demos/test.o + +#Files left over from making the crypt.pdf. +LEFTOVERS=*.dvi *.log *.aux *.toc *.idx *.ilg *.ind *.out + +#Compressed filenames +COMPRESSED=crypt-$(VERSION).tar.bz2 crypt-$(VERSION).zip + +#The default rule for make builds the libtomcrypt library. +default:library + +#ciphers come in two flavours... enc+dec and enc +src/ciphers/aes/aes_enc.o: src/ciphers/aes/aes.c src/ciphers/aes/aes_tab.c + $(CC) $(CFLAGS) -DENCRYPT_ONLY -c src/ciphers/aes/aes.c -o src/ciphers/aes/aes_enc.o + +#These are the rules to make certain object files. +src/ciphers/aes/aes.o: src/ciphers/aes/aes.c src/ciphers/aes/aes_tab.c +src/ciphers/twofish/twofish.o: src/ciphers/twofish/twofish.c src/ciphers/twofish/twofish_tab.c +src/hashes/whirl/whirl.o: src/hashes/whirl/whirl.c src/hashes/whirl/whirltab.c +src/hashes/sha2/sha512.o: src/hashes/sha2/sha512.c src/hashes/sha2/sha384.c +src/hashes/sha2/sha256.o: src/hashes/sha2/sha256.c src/hashes/sha2/sha224.c + +#This rule makes the libtomcrypt library. +library: $(LIBNAME) + +testprof/$(LIBTEST): + cd testprof ; CFLAGS="$(CFLAGS)" LIBTEST_S=$(LIBTEST_S) $(MAKE) + +$(LIBNAME): $(OBJECTS) + $(AR) $(ARFLAGS) $@ $(OBJECTS) + $(RANLIB) $@ + +#This rule makes the hash program included with libtomcrypt +hashsum: library $(HASHOBJECTS) + $(CC) $(HASHOBJECTS) $(LIBNAME) $(EXTRALIBS) -o $(HASH) $(WARN) + +#makes the crypt program +crypt: library $(CRYPTOBJECTS) + $(CC) $(CRYPTOBJECTS) $(LIBNAME) $(EXTRALIBS) -o $(CRYPT) $(WARN) + +#makes the small program +small: library $(SMALLOBJECTS) + $(CC) $(SMALLOBJECTS) $(LIBNAME) $(EXTRALIBS) -o $(SMALL) $(WARN) + +tv_gen: library $(TVS) + $(CC) $(LDFLAGS) $(TVS) $(LIBNAME) $(EXTRALIBS) -o $(TV) + +multi: library $(MULTIS) + $(CC) $(MULTIS) $(LIBNAME) $(EXTRALIBS) -o $(MULTI) + +timing: library testprof/$(LIBTEST) $(TIMINGS) + $(CC) $(LDFLAGS) $(TIMINGS) testprof/$(LIBTEST) $(LIBNAME) $(EXTRALIBS) -o $(TIMING) + +test: library testprof/$(LIBTEST) $(TESTS) + $(CC) $(LDFLAGS) $(TESTS) testprof/$(LIBTEST) $(LIBNAME) $(EXTRALIBS) -o $(TEST) + +#This rule installs the library and the header files. This must be run +#as root in order to have a high enough permission to write to the correct +#directories and to set the owner and group to root. +install: library + install -d -g $(GROUP) -o $(USER) $(DESTDIR)$(LIBPATH) + install -d -g $(GROUP) -o $(USER) $(DESTDIR)$(INCPATH) + install -d -g $(GROUP) -o $(USER) $(DESTDIR)$(DATAPATH) + install -g $(GROUP) -o $(USER) $(LIBNAME) $(DESTDIR)$(LIBPATH) + install -g $(GROUP) -o $(USER) $(HEADERS) $(DESTDIR)$(INCPATH) + +install_test: testprof/$(LIBTEST) + install -d -g $(GROUP) -o $(USER) $(DESTDIR)$(LIBPATH) + install -d -g $(GROUP) -o $(USER) $(DESTDIR)$(INCPATH) + install -g $(GROUP) -o $(USER) testprof/$(LIBTEST) $(DESTDIR)$(LIBPATH) + +# $Source: /cvs/libtom/libtomcrypt/makefile.unix,v $ +# $Revision: 1.4 $ +# $Date: 2006/12/02 19:23:21 $ diff --git a/src/ciphers/twofish/twofish.c b/src/ciphers/twofish/twofish.c index cf3fb5a..ea842fa 100644 --- a/src/ciphers/twofish/twofish.c +++ b/src/ciphers/twofish/twofish.c @@ -412,8 +412,8 @@ int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetri /* make the sboxes (large ram variant) */ if (k == 2) { for (x = 0; x < 256; x++) { - tmpx0 = sbox(0, x); - tmpx1 = sbox(1, x); + tmpx0 = (unsigned char)sbox(0, x); + tmpx1 = (unsigned char)sbox(1, x); skey->twofish.S[0][x] = mds_column_mult(sbox(1, (sbox(0, tmpx0 ^ S[0]) ^ S[4])),0); skey->twofish.S[1][x] = mds_column_mult(sbox(0, (sbox(0, tmpx1 ^ S[1]) ^ S[5])),1); skey->twofish.S[2][x] = mds_column_mult(sbox(1, (sbox(1, tmpx0 ^ S[2]) ^ S[6])),2); @@ -421,8 +421,8 @@ int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetri } } else if (k == 3) { for (x = 0; x < 256; x++) { - tmpx0 = sbox(0, x); - tmpx1 = sbox(1, x); + tmpx0 = (unsigned char)sbox(0, x); + tmpx1 = (unsigned char)sbox(1, x); skey->twofish.S[0][x] = mds_column_mult(sbox(1, (sbox(0, sbox(0, tmpx1 ^ S[0]) ^ S[4]) ^ S[8])),0); skey->twofish.S[1][x] = mds_column_mult(sbox(0, (sbox(0, sbox(1, tmpx1 ^ S[1]) ^ S[5]) ^ S[9])),1); skey->twofish.S[2][x] = mds_column_mult(sbox(1, (sbox(1, sbox(0, tmpx0 ^ S[2]) ^ S[6]) ^ S[10])),2); @@ -430,8 +430,8 @@ int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetri } } else { for (x = 0; x < 256; x++) { - tmpx0 = sbox(0, x); - tmpx1 = sbox(1, x); + tmpx0 = (unsigned char)sbox(0, x); + tmpx1 = (unsigned char)sbox(1, x); skey->twofish.S[0][x] = mds_column_mult(sbox(1, (sbox(0, sbox(0, sbox(1, tmpx1 ^ S[0]) ^ S[4]) ^ S[8]) ^ S[12])),0); skey->twofish.S[1][x] = mds_column_mult(sbox(0, (sbox(0, sbox(1, sbox(1, tmpx0 ^ S[1]) ^ S[5]) ^ S[9]) ^ S[13])),1); skey->twofish.S[2][x] = mds_column_mult(sbox(1, (sbox(1, sbox(0, sbox(0, tmpx0 ^ S[2]) ^ S[6]) ^ S[10]) ^ S[14])),2); diff --git a/src/encauth/ccm/ccm_memory.c b/src/encauth/ccm/ccm_memory.c index b96e68d..e57f46e 100644 --- a/src/encauth/ccm/ccm_memory.c +++ b/src/encauth/ccm/ccm_memory.c @@ -140,9 +140,9 @@ int ccm_memory(int cipher, /* form B_0 == flags | Nonce N | l(m) */ x = 0; - PAD[x++] = ((headerlen > 0) ? (1<<6) : 0) | + PAD[x++] = (unsigned char)(((headerlen > 0) ? (1<<6) : 0) | (((*taglen - 2)>>1)<<3) | - (L-1); + (L-1)); /* nonce */ for (y = 0; y < (16 - (L + 1)); y++) { @@ -162,7 +162,7 @@ int ccm_memory(int cipher, PAD[x++] = 0; } for (; y < L; y++) { - PAD[x++] = (len >> 24) & 255; + PAD[x++] = (unsigned char)((len >> 24) & 255); len <<= 8; } @@ -212,7 +212,7 @@ int ccm_memory(int cipher, x = 0; /* flags */ - ctr[x++] = L-1; + ctr[x++] = (unsigned char)L-1; /* nonce */ for (y = 0; y < (16 - (L+1)); ++y) { diff --git a/src/encauth/ccm/ccm_test.c b/src/encauth/ccm/ccm_test.c index 0222a5b..3481962 100644 --- a/src/encauth/ccm/ccm_test.c +++ b/src/encauth/ccm/ccm_test.c @@ -157,7 +157,7 @@ int ccm_test(void) tests[x].header, tests[x].headerlen, buf2, tests[x].ptlen, buf, - tag2, &taglen, 1 )) != CRYPT_OK) { + tag2, &taglen, 1 )) != CRYPT_OK) { return err; } diff --git a/src/encauth/gcm/gcm_process.c b/src/encauth/gcm/gcm_process.c index f563180..20eb660 100644 --- a/src/encauth/gcm/gcm_process.c +++ b/src/encauth/gcm/gcm_process.c @@ -58,7 +58,7 @@ int gcm_process(gcm_state *gcm, } /* increment counter */ - for (y = 15; y >= 0; y--) { + for (y = 15; y >= 12; y--) { if (++gcm->Y[y] & 255) { break; } } /* encrypt the counter */ @@ -88,7 +88,7 @@ int gcm_process(gcm_state *gcm, gcm->pttotlen += 128; gcm_mult_h(gcm, gcm->X); /* increment counter */ - for (y = 15; y >= 0; y--) { + for (y = 15; y >= 12; y--) { if (++gcm->Y[y] & 255) { break; } } if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) { @@ -106,7 +106,7 @@ int gcm_process(gcm_state *gcm, gcm->pttotlen += 128; gcm_mult_h(gcm, gcm->X); /* increment counter */ - for (y = 15; y >= 0; y--) { + for (y = 15; y >= 12; y--) { if (++gcm->Y[y] & 255) { break; } } if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) { @@ -124,7 +124,7 @@ int gcm_process(gcm_state *gcm, gcm_mult_h(gcm, gcm->X); /* increment counter */ - for (y = 15; y >= 0; y--) { + for (y = 15; y >= 12; y--) { if (++gcm->Y[y] & 255) { break; } } if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) { diff --git a/src/encauth/gcm/gcm_test.c b/src/encauth/gcm/gcm_test.c index 52e9915..e712f8c 100644 --- a/src/encauth/gcm/gcm_test.c +++ b/src/encauth/gcm/gcm_test.c @@ -29,13 +29,13 @@ int gcm_test(void) static const struct { unsigned char K[32]; int keylen; - unsigned char P[64]; + unsigned char P[128]; unsigned long ptlen; - unsigned char A[64]; + unsigned char A[128]; unsigned long alen; - unsigned char IV[64]; + unsigned char IV[128]; unsigned long IVlen; - unsigned char C[64]; + unsigned char C[128]; unsigned char T[16]; } tests[] = { @@ -277,42 +277,56 @@ int gcm_test(void) 0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99, 0xd0, 0x50, } }, -#if 0 - -/* test case #10 */ +/* test case #46 from BG (catches the LTC bug of v1.15) */ { - { 0xdb, 0xbc, 0x85, 0x66, 0xd6, 0xf5, 0xb1, 0x58, - 0xda, 0x99, 0xa2, 0xff, 0x2e, 0x01, 0xdd, 0xa6, - 0x29, 0xb8, 0x9c, 0x34, 0xad, 0x1e, 0x5f, 0xeb, - 0xa7, 0x0e, 0x7a, 0xae, 0x43, 0x28, 0x28, 0x9c }, - 32, - - { 0xce, 0x20, 0x27, 0xb4, 0x7a, 0x84, 0x32, 0x52, - 0x01, 0x34, 0x65, 0x83, 0x4d, 0x75, 0xfd, 0x0f }, + /* key */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 16, - { 0 }, - 0, + /* PT */ + { 0xa2, 0xaa, 0xb3, 0xad, 0x8b, 0x17, 0xac, 0xdd, + 0xa2, 0x88, 0x42, 0x6c, 0xd7, 0xc4, 0x29, 0xb7, + 0xca, 0x86, 0xb7, 0xac, 0xa0, 0x58, 0x09, 0xc7, + 0x0c, 0xe8, 0x2d, 0xb2, 0x57, 0x11, 0xcb, 0x53, + 0x02, 0xeb, 0x27, 0x43, 0xb0, 0x36, 0xf3, 0xd7, + 0x50, 0xd6, 0xcf, 0x0d, 0xc0, 0xac, 0xb9, 0x29, + 0x50, 0xd5, 0x46, 0xdb, 0x30, 0x8f, 0x93, 0xb4, + 0xff, 0x24, 0x4a, 0xfa, 0x9d, 0xc7, 0x2b, 0xcd, + 0x75, 0x8d, 0x2c }, + 67, - { 0xcf, 0xc0, 0x6e, 0x72, 0x2b, 0xe9, 0x87, 0xb3, - 0x76, 0x7f, 0x70, 0xa7, 0xb8, 0x56, 0xb7, 0x74 }, + /* ADATA */ + { 0x68, 0x8e, 0x1a, 0xa9, 0x84, 0xde, 0x92, 0x6d, + 0xc7, 0xb4, 0xc4, 0x7f, 0x44 }, + 13, + + /* IV */ + { 0xb7, 0x21, 0x38, 0xb5, 0xa0, 0x5f, 0xf5, 0x07, + 0x0e, 0x8c, 0xd9, 0x41, 0x83, 0xf7, 0x61, 0xd8 }, 16, - { 0x03, 0x30, 0xea, 0x65, 0xb1, 0xf4, 0x8a, 0xd7, - 0x18, 0xc3, 0xf1, 0xf3, 0xdc, 0xef, 0xe4, 0x20 }, + /* CT */ + { 0xcb, 0xc8, 0xd2, 0xf1, 0x54, 0x81, 0xa4, 0xcc, + 0x7d, 0xd1, 0xe1, 0x9a, 0xaa, 0x83, 0xde, 0x56, + 0x78, 0x48, 0x3e, 0xc3, 0x59, 0xae, 0x7d, 0xec, + 0x2a, 0xb8, 0xd5, 0x34, 0xe0, 0x90, 0x6f, 0x4b, + 0x46, 0x63, 0xfa, 0xff, 0x58, 0xa8, 0xb2, 0xd7, + 0x33, 0xb8, 0x45, 0xee, 0xf7, 0xc9, 0xb3, 0x31, + 0xe9, 0xe1, 0x0e, 0xb2, 0x61, 0x2c, 0x99, 0x5f, + 0xeb, 0x1a, 0xc1, 0x5a, 0x62, 0x86, 0xcc, 0xe8, + 0xb2, 0x97, 0xa8 }, - { 0xe9, 0xef, 0xa9, 0x97, 0xd0, 0xae, 0x82, 0x42, - 0x90, 0xbb, 0x5a, 0x66, 0x95, 0xff, 0x2c, 0x7a } + /* TAG */ + { 0x8d, 0x2d, 0x2a, 0x93, 0x72, 0x62, 0x6f, 0x6b, + 0xee, 0x85, 0x80, 0x27, 0x6a, 0x63, 0x66, 0xbf } } -#endif - - /* rest of test cases are the same except AES key size changes... ignored... */ }; int idx, err; unsigned long x, y; - unsigned char out[2][64], T[2][16]; + unsigned char out[2][128], T[2][16]; /* find aes */ idx = find_cipher("aes"); diff --git a/src/headers/tomcrypt.h b/src/headers/tomcrypt.h index 68a3287..fe96e5f 100644 --- a/src/headers/tomcrypt.h +++ b/src/headers/tomcrypt.h @@ -16,8 +16,8 @@ extern "C" { #endif /* version */ -#define CRYPT 0x0115 -#define SCRYPT "1.15" +#define CRYPT 0x0116 +#define SCRYPT "1.16" /* max size of either a cipher/hash block or symmetric key [largest of the two] */ #define MAXBLOCKSIZE 128 diff --git a/src/headers/tomcrypt_cfg.h b/src/headers/tomcrypt_cfg.h index 7e52e2b..f7ad3cc 100644 --- a/src/headers/tomcrypt_cfg.h +++ b/src/headers/tomcrypt_cfg.h @@ -39,6 +39,8 @@ LTC_EXPORT void * LTC_CALL XMEMCPY(void *dest, const void *src, size_t n); LTC_EXPORT int LTC_CALL XMEMCMP(const void *s1, const void *s2, size_t n); LTC_EXPORT void * LTC_CALL XMEMSET(void *s, int c, size_t n); +LTC_EXPORT int LTC_CALL XSTRCMP(const char *s1, const char *s2); + #endif /* type of argument checking, 0=default, 1=fatal and 2=error+continue, 3=nothing */ diff --git a/src/headers/tomcrypt_custom.h b/src/headers/tomcrypt_custom.h index 995c3d4..cf4be6d 100644 --- a/src/headers/tomcrypt_custom.h +++ b/src/headers/tomcrypt_custom.h @@ -3,27 +3,54 @@ /* macros for various libc functions you can change for embedded targets */ #ifndef XMALLOC + #ifdef malloc + #define LTC_NO_PROTOTYPES + #endif #define XMALLOC malloc #endif #ifndef XREALLOC + #ifdef realloc + #define LTC_NO_PROTOTYPES + #endif #define XREALLOC realloc #endif #ifndef XCALLOC + #ifdef calloc + #define LTC_NO_PROTOTYPES + #endif #define XCALLOC calloc #endif #ifndef XFREE + #ifdef free + #define LTC_NO_PROTOTYPES + #endif #define XFREE free #endif #ifndef XMEMSET + #ifdef memset + #define LTC_NO_PROTOTYPES + #endif #define XMEMSET memset #endif #ifndef XMEMCPY + #ifdef memcpy + #define LTC_NO_PROTOTYPES + #endif #define XMEMCPY memcpy #endif #ifndef XMEMCMP + #ifdef memcmp + #define LTC_NO_PROTOTYPES + #endif #define XMEMCMP memcmp #endif +#ifndef XSTRCMP + #ifdef strcmp + #define LTC_NO_PROTOTYPES + #endif +#define XSTRCMP strcmp +#endif #ifndef XCLOCK #define XCLOCK clock @@ -33,6 +60,9 @@ #endif #ifndef XQSORT + #ifdef qsort + #define LTC_NO_PROTOTYPES + #endif #define XQSORT qsort #endif @@ -276,6 +306,9 @@ /* ECC */ #define MECC +/* use Shamir's trick for point mul (speeds up signature verification) */ +#define LTC_ECC_SHAMIR + #if defined(TFM_DESC) && defined(MECC) #define MECC_ACCEL #endif diff --git a/src/headers/tomcrypt_macros.h b/src/headers/tomcrypt_macros.h index 69574a9..6e4d757 100644 --- a/src/headers/tomcrypt_macros.h +++ b/src/headers/tomcrypt_macros.h @@ -72,9 +72,9 @@ #define STORE32H(x, y) \ asm __volatile__ ( \ "bswapl %0 \n\t" \ - "movl %0,(%2)\n\t" \ + "movl %0,(%1)\n\t" \ "bswapl %0 \n\t" \ - :"=r"(x):"0"(x), "r"(y)); + ::"r"(x), "r"(y)); #define LOAD32H(x, y) \ asm __volatile__ ( \ @@ -103,9 +103,9 @@ asm __volatile__ ( \ #define STORE64H(x, y) \ asm __volatile__ ( \ "bswapq %0 \n\t" \ - "movq %0,(%2)\n\t" \ + "movq %0,(%1)\n\t" \ "bswapq %0 \n\t" \ - :"=r"(x):"0"(x), "r"(y):"0"); + ::"r"(x), "r"(y)); #define LOAD64H(x, y) \ asm __volatile__ ( \ @@ -132,10 +132,10 @@ asm __volatile__ ( \ #ifdef ENDIAN_32BITWORD #define STORE32L(x, y) \ - { ulong32 __t = (x); memcpy(y, &__t, 4); } + { ulong32 __t = (x); XMEMCPY(y, &__t, 4); } #define LOAD32L(x, y) \ - memcpy(&(x), y, 4); + XMEMCPY(&(x), y, 4); #define STORE64L(x, y) \ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \ @@ -152,16 +152,16 @@ asm __volatile__ ( \ #else /* 64-bit words then */ #define STORE32L(x, y) \ - { ulong32 __t = (x); memcpy(y, &__t, 4); } + { ulong32 __t = (x); XMEMCPY(y, &__t, 4); } #define LOAD32L(x, y) \ - { memcpy(&(x), y, 4); x &= 0xFFFFFFFF; } + { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; } #define STORE64L(x, y) \ - { ulong64 __t = (x); memcpy(y, &__t, 8); } + { ulong64 __t = (x); XMEMCPY(y, &__t, 8); } #define LOAD64L(x, y) \ - { memcpy(&(x), y, 8); } + { XMEMCPY(&(x), y, 8); } #endif /* ENDIAN_64BITWORD */ @@ -193,10 +193,10 @@ asm __volatile__ ( \ #ifdef ENDIAN_32BITWORD #define STORE32H(x, y) \ - { ulong32 __t = (x); memcpy(y, &__t, 4); } + { ulong32 __t = (x); XMEMCPY(y, &__t, 4); } #define LOAD32H(x, y) \ - memcpy(&(x), y, 4); + XMEMCPY(&(x), y, 4); #define STORE64H(x, y) \ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ @@ -213,16 +213,16 @@ asm __volatile__ ( \ #else /* 64-bit words then */ #define STORE32H(x, y) \ - { ulong32 __t = (x); memcpy(y, &__t, 4); } + { ulong32 __t = (x); XMEMCPY(y, &__t, 4); } #define LOAD32H(x, y) \ - { memcpy(&(x), y, 4); x &= 0xFFFFFFFF; } + { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; } #define STORE64H(x, y) \ - { ulong64 __t = (x); memcpy(y, &__t, 8); } + { ulong64 __t = (x); XMEMCPY(y, &__t, 8); } #define LOAD64H(x, y) \ - { memcpy(&(x), y, 8); } + { XMEMCPY(&(x), y, 8); } #endif /* ENDIAN_64BITWORD */ #endif /* ENDIAN_BIG */ diff --git a/src/headers/tomcrypt_math.h b/src/headers/tomcrypt_math.h index a3534df..e6ee799 100644 --- a/src/headers/tomcrypt_math.h +++ b/src/headers/tomcrypt_math.h @@ -372,6 +372,20 @@ typedef struct { */ int (*ecc_map)(ecc_point *P, void *modulus, void *mp); + /** Computes kA*A + kB*B = C using Shamir's Trick + @param A First point to multiply + @param kA What to multiple A by + @param B Second point to multiply + @param kB What to multiple B by + @param C [out] Destination point (can overlap with A or B + @param modulus Modulus for curve + @return CRYPT_OK on success + */ + int (*ecc_mul2add)(ecc_point *A, void *kA, + ecc_point *B, void *kB, + ecc_point *C, + void *modulus); + /* ---- (optional) rsa optimized math (for internal CRT) ---- */ /** RSA Key Generation diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h index bf3b6ea..079ae3e 100644 --- a/src/headers/tomcrypt_pk.h +++ b/src/headers/tomcrypt_pk.h @@ -160,19 +160,19 @@ typedef struct { /** name of curve */ char *name; - /** The prime that defines the field the curve is in (encoded in base-64) */ + /** The prime that defines the field the curve is in (encoded in hex) */ char *prime; - /** The fields B param (base64) */ + /** The fields B param (hex) */ char *B; - /** The order of the curve (base64) */ + /** The order of the curve (hex) */ char *order; - /** The x co-ordinate of the base point on the curve (base64) */ + /** The x co-ordinate of the base point on the curve (hex) */ char *Gx; - /** The y co-ordinate of the base point on the curve (base64) */ + /** The y co-ordinate of the base point on the curve (hex) */ char *Gy; } ltc_ecc_set_type; @@ -193,9 +193,12 @@ typedef struct { /** Type of key, PK_PRIVATE or PK_PUBLIC */ int type; - /** Index into the ltc_ecc_sets[] for the parameters of this curve */ + /** Index into the ltc_ecc_sets[] for the parameters of this curve; if -1, then this key is using user supplied curve in dp */ int idx; + /** pointer to domain parameters; either points to NIST curves (identified by idx >= 0) or user supplied curve */ + const ltc_ecc_set_type *dp; + /** The public key */ ecc_point pubkey; @@ -211,13 +214,16 @@ void ecc_sizes(int *low, int *high); int ecc_get_size(ecc_key *key); int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key); +int ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_set_type *dp); void ecc_free(ecc_key *key); int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key); int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key); +int ecc_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_set_type *dp); int ecc_ansi_x963_export(ecc_key *key, unsigned char *out, unsigned long *outlen); int ecc_ansi_x963_import(const unsigned char *in, unsigned long inlen, ecc_key *key); +int ecc_ansi_x963_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, ltc_ecc_set_type *dp); int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, unsigned char *out, unsigned long *outlen); @@ -263,6 +269,22 @@ void ltc_ecc_fp_free(void); /* R = kG */ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map); +#ifdef LTC_ECC_SHAMIR +/* kA*A + kB*B = C */ +int ltc_ecc_mul2add(ecc_point *A, void *kA, + ecc_point *B, void *kB, + ecc_point *C, + void *modulus); + +#ifdef MECC_FP +int ltc_ecc_fp_mul2add(ecc_point *A, void *kA, + ecc_point *B, void *kB, + ecc_point *C, void *modulus); +#endif + +#endif + + /* map P to affine from projective */ int ltc_ecc_map(ecc_point *P, void *modulus, void *mp); @@ -351,6 +373,7 @@ enum { LTC_ASN1_OBJECT_IDENTIFIER, LTC_ASN1_IA5_STRING, LTC_ASN1_PRINTABLE_STRING, + LTC_ASN1_UTF8_STRING, LTC_ASN1_UTCTIME, LTC_ASN1_CHOICE, LTC_ASN1_SEQUENCE, @@ -472,6 +495,22 @@ int der_length_printable_string(const unsigned char *octets, unsigned long nocte int der_printable_char_encode(int c); int der_printable_value_decode(int v); +/* UTF-8 */ +#if (defined(SIZE_MAX) || __STDC_VERSION__ >= 199901L || defined(WCHAR_MAX) || defined(_WCHAR_T) || defined(_WCHAR_T_DEFINED)) && !defined(LTC_NO_WCHAR) +#include +#else +typedef ulong32 wchar_t; +#endif + +int der_encode_utf8_string(const wchar_t *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen); + +int der_decode_utf8_string(const unsigned char *in, unsigned long inlen, + wchar_t *out, unsigned long *outlen); +unsigned long der_utf8_charsize(const wchar_t c); +int der_length_utf8_string(const wchar_t *in, unsigned long noctets, unsigned long *outlen); + + /* CHOICE */ int der_decode_choice(const unsigned char *in, unsigned long *inlen, ltc_asn1_list *list, unsigned long outlen); diff --git a/src/mac/f9/f9_file.c b/src/mac/f9/f9_file.c index 11055d8..0fe37f9 100644 --- a/src/mac/f9/f9_file.c +++ b/src/mac/f9/f9_file.c @@ -64,7 +64,7 @@ int f9_file(int cipher, } while (x == sizeof(buf)); fclose(in); - if ((err = f9_done(&f9, out, outlen)) != CRYPT_OK) { + if ((err = f9_done(&f9, out, outlen)) != CRYPT_OK) { return err; } diff --git a/src/mac/f9/f9_memory.c b/src/mac/f9/f9_memory.c index aacf424..246127f 100644 --- a/src/mac/f9/f9_memory.c +++ b/src/mac/f9/f9_memory.c @@ -12,7 +12,7 @@ /** @file f9_process.c - f9 Support, terminate the state + f9 Support, Process a block through F9-MAC */ #ifdef LTC_F9_MODE diff --git a/src/mac/f9/f9_process.c b/src/mac/f9/f9_process.c index f4f088f..b15e18f 100644 --- a/src/mac/f9/f9_process.c +++ b/src/mac/f9/f9_process.c @@ -18,7 +18,7 @@ #ifdef LTC_F9_MODE /** Process data through f9-MAC - @param f9 The f9-MAC state + @param f9 The f9-MAC state @param in Input data to process @param inlen Length of input in octets Return CRYPT_OK on success diff --git a/src/mac/f9/f9_test.c b/src/mac/f9/f9_test.c index a3f9080..ff9d5fd 100644 --- a/src/mac/f9/f9_test.c +++ b/src/mac/f9/f9_test.c @@ -12,7 +12,7 @@ /** @file f9_test.c - f9 Support, terminate the state + f9 Support, Test F9 mode */ #ifdef LTC_F9_MODE diff --git a/src/mac/pelican/pelican_test.c b/src/mac/pelican/pelican_test.c index 84b76b9..d51df85 100644 --- a/src/mac/pelican/pelican_test.c +++ b/src/mac/pelican/pelican_test.c @@ -24,7 +24,7 @@ int pelican_test(void) #else static const struct { unsigned char K[32], MSG[64], T[16]; - int keylen, ptlen; + int keylen, ptlen; } tests[] = { /* K=16, M=0 */ { diff --git a/src/mac/xcbc/xcbc_memory.c b/src/mac/xcbc/xcbc_memory.c index 89debfe..daf6778 100644 --- a/src/mac/xcbc/xcbc_memory.c +++ b/src/mac/xcbc/xcbc_memory.c @@ -12,7 +12,7 @@ /** @file xcbc_process.c - XCBC Support, terminate the state + XCBC Support, XCBC-MAC a block of memory */ #ifdef LTC_XCBC diff --git a/src/mac/xcbc/xcbc_test.c b/src/mac/xcbc/xcbc_test.c index aeebc78..cb1d62f 100644 --- a/src/mac/xcbc/xcbc_test.c +++ b/src/mac/xcbc/xcbc_test.c @@ -12,7 +12,7 @@ /** @file xcbc_test.c - XCBC Support, terminate the state + XCBC Support, Test XCBC-MAC mode */ #ifdef LTC_XCBC diff --git a/src/math/fp/ltc_ecc_fp_mulmod.c b/src/math/fp/ltc_ecc_fp_mulmod.c index 614ef20..77c0d2a 100644 --- a/src/math/fp/ltc_ecc_fp_mulmod.c +++ b/src/math/fp/ltc_ecc_fp_mulmod.c @@ -897,6 +897,320 @@ static int accel_fp_mul(int idx, void *k, ecc_point *R, void *modulus, void *mp, return err; } +#ifdef LTC_ECC_SHAMIR +/* perform a fixed point ECC mulmod */ +static int accel_fp_mul2add(int idx1, int idx2, + void *kA, void *kB, + ecc_point *R, void *modulus, void *mp) +{ + unsigned char kb[2][128]; + int x; + unsigned y, z, err, bitlen, bitpos, lut_gap, first, zA, zB; + void *tka, *tkb, *order; + + /* if it's smaller than modulus we fine */ + if (mp_unsigned_bin_size(kA) > mp_unsigned_bin_size(modulus)) { + /* find order */ + y = mp_unsigned_bin_size(modulus); + for (x = 0; ltc_ecc_sets[x].size; x++) { + if (y <= (unsigned)ltc_ecc_sets[x].size) break; + } + + /* back off if we are on the 521 bit curve */ + if (y == 66) --x; + + if ((err = mp_init(&order)) != CRYPT_OK) { + return err; + } + if ((err = mp_read_radix(order, ltc_ecc_sets[x].order, 16)) != CRYPT_OK) { + mp_clear(&order); + return err; + } + + /* kA must be less than modulus */ + if (mp_cmp(kA, order) != LTC_MP_LT) { + if ((err = mp_init(&tka)) != CRYPT_OK) { + mp_clear(order); + return err; + } + if ((err = mp_mod(kA, order, tka)) != CRYPT_OK) { + mp_clear(tka); + mp_clear(order); + return err; + } + } else { + tka = kA; + } + mp_clear(order); + } else { + tka = kA; + } + + /* if it's smaller than modulus we fine */ + if (mp_unsigned_bin_size(kB) > mp_unsigned_bin_size(modulus)) { + /* find order */ + y = mp_unsigned_bin_size(modulus); + for (x = 0; ltc_ecc_sets[x].size; x++) { + if (y <= (unsigned)ltc_ecc_sets[x].size) break; + } + + /* back off if we are on the 521 bit curve */ + if (y == 66) --x; + + if ((err = mp_init(&order)) != CRYPT_OK) { + return err; + } + if ((err = mp_read_radix(order, ltc_ecc_sets[x].order, 16)) != CRYPT_OK) { + mp_clear(&order); + return err; + } + + /* kB must be less than modulus */ + if (mp_cmp(kB, order) != LTC_MP_LT) { + if ((err = mp_init(&tkb)) != CRYPT_OK) { + mp_clear(order); + return err; + } + if ((err = mp_mod(kB, order, tkb)) != CRYPT_OK) { + mp_clear(tkb); + mp_clear(order); + return err; + } + } else { + tkb = kB; + } + mp_clear(order); + } else { + tkb = kB; + } + + /* get bitlen and round up to next multiple of FP_LUT */ + bitlen = mp_unsigned_bin_size(modulus) << 3; + x = bitlen % FP_LUT; + if (x) { + bitlen += FP_LUT - x; + } + lut_gap = bitlen / FP_LUT; + + /* get the k value */ + if ((mp_unsigned_bin_size(tka) > (sizeof(kb[0]) - 2)) || (mp_unsigned_bin_size(tkb) > (sizeof(kb[0]) - 2)) ) { + if (tka != kA) { + mp_clear(tka); + } + if (tkb != kB) { + mp_clear(tkb); + } + return CRYPT_BUFFER_OVERFLOW; + } + + /* store k */ + zeromem(kb, sizeof(kb)); + if ((err = mp_to_unsigned_bin(tka, kb[0])) != CRYPT_OK) { + if (tka != kA) { + mp_clear(tka); + } + if (tkb != kB) { + mp_clear(tkb); + } + return err; + } + + /* let's reverse kb so it's little endian */ + x = 0; + y = mp_unsigned_bin_size(tka) - 1; + if (tka != kA) { + mp_clear(tka); + } + while ((unsigned)x < y) { + z = kb[0][x]; kb[0][x] = kb[0][y]; kb[0][y] = z; + ++x; --y; + } + + /* store b */ + if ((err = mp_to_unsigned_bin(tkb, kb[1])) != CRYPT_OK) { + if (tkb != kB) { + mp_clear(tkb); + } + return err; + } + + x = 0; + y = mp_unsigned_bin_size(tkb) - 1; + if (tkb != kB) { + mp_clear(tkb); + } + while ((unsigned)x < y) { + z = kb[1][x]; kb[1][x] = kb[1][y]; kb[1][y] = z; + ++x; --y; + } + + /* at this point we can start, yipee */ + first = 1; + for (x = lut_gap-1; x >= 0; x--) { + /* extract FP_LUT bits from kb spread out by lut_gap bits and offset by x bits from the start */ + bitpos = x; + for (y = zA = zB = 0; y < FP_LUT; y++) { + zA |= ((kb[0][bitpos>>3] >> (bitpos&7)) & 1) << y; + zB |= ((kb[1][bitpos>>3] >> (bitpos&7)) & 1) << y; + bitpos += lut_gap; /* it's y*lut_gap + x, but here we can avoid the mult in each loop */ + } + + /* double if not first */ + if (!first) { + if ((err = ltc_mp.ecc_ptdbl(R, R, modulus, mp)) != CRYPT_OK) { + return err; + } + } + + /* add if not first, otherwise copy */ + if (!first) { + if (zA) { + if ((err = ltc_mp.ecc_ptadd(R, fp_cache[idx1].LUT[zA], R, modulus, mp)) != CRYPT_OK) { + return err; + } + } + if (zB) { + if ((err = ltc_mp.ecc_ptadd(R, fp_cache[idx2].LUT[zB], R, modulus, mp)) != CRYPT_OK) { + return err; + } + } + } else { + if (zA) { + if ((mp_copy(fp_cache[idx1].LUT[zA]->x, R->x) != CRYPT_OK) || + (mp_copy(fp_cache[idx1].LUT[zA]->y, R->y) != CRYPT_OK) || + (mp_copy(fp_cache[idx1].mu, R->z) != CRYPT_OK)) { return CRYPT_MEM; } + first = 0; + } + if (zB && first == 0) { + if (zB) { + if ((err = ltc_mp.ecc_ptadd(R, fp_cache[idx2].LUT[zB], R, modulus, mp)) != CRYPT_OK) { + return err; + } + } + } else if (zB && first == 1) { + if ((mp_copy(fp_cache[idx2].LUT[zB]->x, R->x) != CRYPT_OK) || + (mp_copy(fp_cache[idx2].LUT[zB]->y, R->y) != CRYPT_OK) || + (mp_copy(fp_cache[idx2].mu, R->z) != CRYPT_OK)) { return CRYPT_MEM; } + first = 0; + } + } + } + zeromem(kb, sizeof(kb)); + return ltc_ecc_map(R, modulus, mp); +} + +/** ECC Fixed Point mulmod global + @param k The multiplicand + @param G Base point to multiply + @param R [out] Destination of product + @param modulus The modulus for the curve + @param map [boolean] If non-zero maps the point back to affine co-ordinates, otherwise it's left in jacobian-montgomery form + @return CRYPT_OK if successful +*/ +int ltc_ecc_fp_mul2add(ecc_point *A, void *kA, + ecc_point *B, void *kB, + ecc_point *C, void *modulus) +{ + int idx1, idx2, err; + void *mp, *mu; + + mp = NULL; + mu = NULL; + LTC_MUTEX_LOCK(<c_ecc_fp_lock); + /* find point */ + idx1 = find_base(A); + + /* no entry? */ + if (idx1 == -1) { + /* find hole and add it */ + idx1 = find_hole(); + + if ((err = add_entry(idx1, A)) != CRYPT_OK) { + goto LBL_ERR; + } + } + + /* increment LRU */ + ++(fp_cache[idx1].lru_count); + + /* find point */ + idx2 = find_base(B); + + /* no entry? */ + if (idx2 == -1) { + /* find hole and add it */ + idx2 = find_hole(); + + if ((err = add_entry(idx2, B)) != CRYPT_OK) { + goto LBL_ERR; + } + } + + /* increment LRU */ + ++(fp_cache[idx2].lru_count); + + /* if it's 2 build the LUT, if it's higher just use the LUT */ + if (fp_cache[idx1].lru_count == 2) { + /* compute mp */ + if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) { goto LBL_ERR; } + + /* compute mu */ + if ((err = mp_init(&mu)) != CRYPT_OK) { + goto LBL_ERR; + } + if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) { + goto LBL_ERR; + } + + /* build the LUT */ + if ((err = build_lut(idx1, modulus, mp, mu)) != CRYPT_OK) { + goto LBL_ERR;; + } + } + + /* if it's 2 build the LUT, if it's higher just use the LUT */ + if (fp_cache[idx2].lru_count == 2) { + if (mp == NULL) { + /* compute mp */ + if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) { goto LBL_ERR; } + + /* compute mu */ + if ((err = mp_init(&mu)) != CRYPT_OK) { + goto LBL_ERR; + } + if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) { + goto LBL_ERR; + } + } + + /* build the LUT */ + if ((err = build_lut(idx2, modulus, mp, mu)) != CRYPT_OK) { + goto LBL_ERR;; + } + } + + + if (fp_cache[idx1].lru_count >= 2 && fp_cache[idx2].lru_count >= 2) { + if (mp == NULL) { + /* compute mp */ + if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) { goto LBL_ERR; } + } + err = accel_fp_mul2add(idx1, idx2, kA, kB, C, modulus, mp); + } else { + err = ltc_ecc_mul2add(A, kA, B, kB, C, modulus); + } +LBL_ERR: + LTC_MUTEX_UNLOCK(<c_ecc_fp_lock); + if (mp != NULL) { + mp_montgomery_free(mp); + } + if (mu != NULL) { + mp_clear(mu); + } + return err; +} +#endif + /** ECC Fixed Point mulmod global @param k The multiplicand @param G Base point to multiply diff --git a/src/math/gmp_desc.c b/src/math/gmp_desc.c index decc7fd..2f30c2e 100644 --- a/src/math/gmp_desc.c +++ b/src/math/gmp_desc.c @@ -448,9 +448,18 @@ const ltc_math_descriptor gmp_desc = { <c_ecc_projective_add_point, <c_ecc_projective_dbl_point, <c_ecc_map, +#ifdef LTC_ECC_SHAMIR +#ifdef MECC_FP + <c_ecc_fp_mul2add, #else - NULL, NULL, NULL, NULL, -#endif + <c_ecc_mul2add, +#endif /* MECC_FP */ +#else + NULL, +#endif /* LTC_ECC_SHAMIR */ +#else + NULL, NULL, NULL, NULL, NULL +#endif /* MECC */ #ifdef MRSA &rsa_make_key, diff --git a/src/math/ltm_desc.c b/src/math/ltm_desc.c index 0333607..7638411 100644 --- a/src/math/ltm_desc.c +++ b/src/math/ltm_desc.c @@ -454,9 +454,18 @@ const ltc_math_descriptor ltm_desc = { <c_ecc_projective_add_point, <c_ecc_projective_dbl_point, <c_ecc_map, +#ifdef LTC_ECC_SHAMIR +#ifdef MECC_FP + <c_ecc_fp_mul2add, #else - NULL, NULL, NULL, NULL, -#endif + <c_ecc_mul2add, +#endif /* MECC_FP */ +#else + NULL, +#endif /* LTC_ECC_SHAMIR */ +#else + NULL, NULL, NULL, NULL, NULL, +#endif /* MECC */ #ifdef MRSA &rsa_make_key, diff --git a/src/math/tfm_desc.c b/src/math/tfm_desc.c index b1b4246..791a721 100644 --- a/src/math/tfm_desc.c +++ b/src/math/tfm_desc.c @@ -745,11 +745,20 @@ const ltc_math_descriptor tfm_desc = { #else <c_ecc_projective_add_point, <c_ecc_projective_dbl_point, -#endif +#endif /* MECC_ACCEL */ <c_ecc_map, +#ifdef LTC_ECC_SHAMIR +#ifdef MECC_FP + <c_ecc_fp_mul2add, #else - NULL, NULL, NULL, NULL, -#endif + <c_ecc_mul2add, +#endif /* MECC_FP */ +#else + NULL, +#endif /* LTC_ECC_SHAMIR */ +#else + NULL, NULL, NULL, NULL, NULL, +#endif /* MECC */ #ifdef MRSA &rsa_make_key, diff --git a/src/misc/crypt/crypt.c b/src/misc/crypt/crypt.c index 64f1940..c52cfee 100644 --- a/src/misc/crypt/crypt.c +++ b/src/misc/crypt/crypt.c @@ -350,6 +350,9 @@ const char *crypt_build_settings = #endif #if defined(MECC_FP) " MECC_FP " +#endif +#if defined(LTC_ECC_SHAMIR) + " LTC_ECC_SHAMIR " #endif "\n" "\n\n\n" diff --git a/src/misc/crypt/crypt_find_cipher.c b/src/misc/crypt/crypt_find_cipher.c index e1e5449..b9607d3 100644 --- a/src/misc/crypt/crypt_find_cipher.c +++ b/src/misc/crypt/crypt_find_cipher.c @@ -26,7 +26,7 @@ int find_cipher(const char *name) LTC_ARGCHK(name != NULL); LTC_MUTEX_LOCK(<c_cipher_mutex); for (x = 0; x < TAB_SIZE; x++) { - if (cipher_descriptor[x].name != NULL && !strcmp(cipher_descriptor[x].name, name)) { + if (cipher_descriptor[x].name != NULL && !XSTRCMP(cipher_descriptor[x].name, name)) { LTC_MUTEX_UNLOCK(<c_cipher_mutex); return x; } diff --git a/src/misc/crypt/crypt_find_hash.c b/src/misc/crypt/crypt_find_hash.c index 9882dfb..f04001a 100644 --- a/src/misc/crypt/crypt_find_hash.c +++ b/src/misc/crypt/crypt_find_hash.c @@ -26,7 +26,7 @@ int find_hash(const char *name) LTC_ARGCHK(name != NULL); LTC_MUTEX_LOCK(<c_hash_mutex); for (x = 0; x < TAB_SIZE; x++) { - if (hash_descriptor[x].name != NULL && strcmp(hash_descriptor[x].name, name) == 0) { + if (hash_descriptor[x].name != NULL && XSTRCMP(hash_descriptor[x].name, name) == 0) { LTC_MUTEX_UNLOCK(<c_hash_mutex); return x; } diff --git a/src/misc/crypt/crypt_find_prng.c b/src/misc/crypt/crypt_find_prng.c index faca946..c5f4a61 100644 --- a/src/misc/crypt/crypt_find_prng.c +++ b/src/misc/crypt/crypt_find_prng.c @@ -26,7 +26,7 @@ int find_prng(const char *name) LTC_ARGCHK(name != NULL); LTC_MUTEX_LOCK(<c_prng_mutex); for (x = 0; x < TAB_SIZE; x++) { - if ((prng_descriptor[x].name != NULL) && strcmp(prng_descriptor[x].name, name) == 0) { + if ((prng_descriptor[x].name != NULL) && XSTRCMP(prng_descriptor[x].name, name) == 0) { LTC_MUTEX_UNLOCK(<c_prng_mutex); return x; } diff --git a/src/modes/cbc/cbc_decrypt.c b/src/modes/cbc/cbc_decrypt.c index ed4e9ba..8941c17 100644 --- a/src/modes/cbc/cbc_decrypt.c +++ b/src/modes/cbc/cbc_decrypt.c @@ -69,18 +69,18 @@ int cbc_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, s /* xor IV against plaintext */ #if defined(LTC_FAST) - for (x = 0; x < cbc->blocklen; x += sizeof(LTC_FAST_TYPE)) { - tmpy = *((LTC_FAST_TYPE*)((unsigned char *)cbc->IV + x)) ^ *((LTC_FAST_TYPE*)((unsigned char *)tmp + x)); - *((LTC_FAST_TYPE*)((unsigned char *)cbc->IV + x)) = *((LTC_FAST_TYPE*)((unsigned char *)ct + x)); - *((LTC_FAST_TYPE*)((unsigned char *)pt + x)) = tmpy; - } - #else + for (x = 0; x < cbc->blocklen; x += sizeof(LTC_FAST_TYPE)) { + tmpy = *((LTC_FAST_TYPE*)((unsigned char *)cbc->IV + x)) ^ *((LTC_FAST_TYPE*)((unsigned char *)tmp + x)); + *((LTC_FAST_TYPE*)((unsigned char *)cbc->IV + x)) = *((LTC_FAST_TYPE*)((unsigned char *)ct + x)); + *((LTC_FAST_TYPE*)((unsigned char *)pt + x)) = tmpy; + } + #else for (x = 0; x < cbc->blocklen; x++) { tmpy = tmp[x] ^ cbc->IV[x]; cbc->IV[x] = ct[x]; pt[x] = tmpy; } - #endif + #endif ct += cbc->blocklen; pt += cbc->blocklen; diff --git a/src/modes/cbc/cbc_encrypt.c b/src/modes/cbc/cbc_encrypt.c index 678c433..5da4242 100644 --- a/src/modes/cbc/cbc_encrypt.c +++ b/src/modes/cbc/cbc_encrypt.c @@ -58,14 +58,14 @@ int cbc_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, s while (len) { /* xor IV against plaintext */ #if defined(LTC_FAST) - for (x = 0; x < cbc->blocklen; x += sizeof(LTC_FAST_TYPE)) { - *((LTC_FAST_TYPE*)((unsigned char *)cbc->IV + x)) ^= *((LTC_FAST_TYPE*)((unsigned char *)pt + x)); - } - #else + for (x = 0; x < cbc->blocklen; x += sizeof(LTC_FAST_TYPE)) { + *((LTC_FAST_TYPE*)((unsigned char *)cbc->IV + x)) ^= *((LTC_FAST_TYPE*)((unsigned char *)pt + x)); + } + #else for (x = 0; x < cbc->blocklen; x++) { cbc->IV[x] ^= pt[x]; } - #endif + #endif /* encrypt */ if ((err = cipher_descriptor[cbc->cipher].ecb_encrypt(cbc->IV, ct, &cbc->key)) != CRYPT_OK) { @@ -74,14 +74,14 @@ int cbc_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, s /* store IV [ciphertext] for a future block */ #if defined(LTC_FAST) - for (x = 0; x < cbc->blocklen; x += sizeof(LTC_FAST_TYPE)) { - *((LTC_FAST_TYPE*)((unsigned char *)cbc->IV + x)) = *((LTC_FAST_TYPE*)((unsigned char *)ct + x)); - } - #else + for (x = 0; x < cbc->blocklen; x += sizeof(LTC_FAST_TYPE)) { + *((LTC_FAST_TYPE*)((unsigned char *)cbc->IV + x)) = *((LTC_FAST_TYPE*)((unsigned char *)ct + x)); + } + #else for (x = 0; x < cbc->blocklen; x++) { cbc->IV[x] = ct[x]; } - #endif + #endif ct += cbc->blocklen; pt += cbc->blocklen; diff --git a/src/modes/cfb/cfb_decrypt.c b/src/modes/cfb/cfb_decrypt.c index 98793d8..fd34b91 100644 --- a/src/modes/cfb/cfb_decrypt.c +++ b/src/modes/cfb/cfb_decrypt.c @@ -54,7 +54,7 @@ int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, s *pt = *ct ^ cfb->IV[cfb->padlen]; ++pt; ++ct; - ++cfb->padlen; + ++(cfb->padlen); } return CRYPT_OK; } diff --git a/src/modes/cfb/cfb_encrypt.c b/src/modes/cfb/cfb_encrypt.c index 03260e2..83f87d8 100644 --- a/src/modes/cfb/cfb_encrypt.c +++ b/src/modes/cfb/cfb_encrypt.c @@ -53,7 +53,7 @@ int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, s cfb->pad[cfb->padlen] = (*ct = *pt ^ cfb->IV[cfb->padlen]); ++pt; ++ct; - ++cfb->padlen; + ++(cfb->padlen); } return CRYPT_OK; } diff --git a/src/modes/ctr/ctr_encrypt.c b/src/modes/ctr/ctr_encrypt.c index 509819e..3f3f954 100644 --- a/src/modes/ctr/ctr_encrypt.c +++ b/src/modes/ctr/ctr_encrypt.c @@ -92,13 +92,13 @@ int ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, s *((LTC_FAST_TYPE*)((unsigned char *)ct + x)) = *((LTC_FAST_TYPE*)((unsigned char *)pt + x)) ^ *((LTC_FAST_TYPE*)((unsigned char *)ctr->pad + x)); } - pt += ctr->blocklen; - ct += ctr->blocklen; - len -= ctr->blocklen; - ctr->padlen = ctr->blocklen; - continue; - } -#endif + pt += ctr->blocklen; + ct += ctr->blocklen; + len -= ctr->blocklen; + ctr->padlen = ctr->blocklen; + continue; + } +#endif *ct++ = *pt++ ^ ctr->pad[ctr->padlen++]; --len; } diff --git a/src/modes/ofb/ofb_encrypt.c b/src/modes/ofb/ofb_encrypt.c index 036f977..d025d83 100644 --- a/src/modes/ofb/ofb_encrypt.c +++ b/src/modes/ofb/ofb_encrypt.c @@ -48,7 +48,7 @@ int ofb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, s } ofb->padlen = 0; } - *ct++ = *pt++ ^ ofb->IV[ofb->padlen++]; + *ct++ = *pt++ ^ ofb->IV[(ofb->padlen)++]; } return CRYPT_OK; } diff --git a/src/pk/asn1/der/bit/der_encode_bit_string.c b/src/pk/asn1/der/bit/der_encode_bit_string.c index 62cc5a2..862048c 100644 --- a/src/pk/asn1/der/bit/der_encode_bit_string.c +++ b/src/pk/asn1/der/bit/der_encode_bit_string.c @@ -29,7 +29,8 @@ int der_encode_bit_string(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen) { - unsigned long len, x, y, buf; + unsigned long len, x, y; + unsigned char buf; int err; LTC_ARGCHK(in != NULL); @@ -52,18 +53,18 @@ int der_encode_bit_string(const unsigned char *in, unsigned long inlen, out[x++] = 0x03; if (y < 128) { - out[x++] = y; + out[x++] = (unsigned char)y; } else if (y < 256) { out[x++] = 0x81; - out[x++] = y; + out[x++] = (unsigned char)y; } else if (y < 65536) { out[x++] = 0x82; - out[x++] = (y>>8)&255; - out[x++] = y&255; + out[x++] = (unsigned char)((y>>8)&255); + out[x++] = (unsigned char)(y&255); } /* store number of zero padding bits */ - out[x++] = (8 - inlen) & 7; + out[x++] = (unsigned char)((8 - inlen) & 7); /* store the bits in big endian format */ for (y = buf = 0; y < inlen; y++) { diff --git a/src/pk/asn1/der/choice/der_decode_choice.c b/src/pk/asn1/der/choice/der_decode_choice.c index 7f6155c..aafdf42 100644 --- a/src/pk/asn1/der/choice/der_decode_choice.c +++ b/src/pk/asn1/der/choice/der_decode_choice.c @@ -135,6 +135,17 @@ int der_decode_choice(const unsigned char *in, unsigned long *inlen, } break; + case LTC_ASN1_UTF8_STRING: + if (der_decode_utf8_string(in, *inlen, data, &size) == CRYPT_OK) { + if (der_length_utf8_string(data, size, &z) == CRYPT_OK) { + list[x].used = 1; + list[x].size = size; + *inlen = z; + return CRYPT_OK; + } + } + break; + case LTC_ASN1_UTCTIME: z = *inlen; if (der_decode_utctime(in, &z, data) == CRYPT_OK) { diff --git a/src/pk/asn1/der/ia5/der_encode_ia5_string.c b/src/pk/asn1/der/ia5/der_encode_ia5_string.c index f19756d..1ef955c 100644 --- a/src/pk/asn1/der/ia5/der_encode_ia5_string.c +++ b/src/pk/asn1/der/ia5/der_encode_ia5_string.c @@ -50,19 +50,19 @@ int der_encode_ia5_string(const unsigned char *in, unsigned long inlen, x = 0; out[x++] = 0x16; if (inlen < 128) { - out[x++] = inlen; + out[x++] = (unsigned char)inlen; } else if (inlen < 256) { out[x++] = 0x81; - out[x++] = inlen; + out[x++] = (unsigned char)inlen; } else if (inlen < 65536UL) { out[x++] = 0x82; - out[x++] = (inlen>>8)&255; - out[x++] = inlen&255; + out[x++] = (unsigned char)((inlen>>8)&255); + out[x++] = (unsigned char)(inlen&255); } else if (inlen < 16777216UL) { out[x++] = 0x83; - out[x++] = (inlen>>16)&255; - out[x++] = (inlen>>8)&255; - out[x++] = inlen&255; + out[x++] = (unsigned char)((inlen>>16)&255); + out[x++] = (unsigned char)((inlen>>8)&255); + out[x++] = (unsigned char)(inlen&255); } else { return CRYPT_INVALID_ARG; } diff --git a/src/pk/asn1/der/integer/der_encode_integer.c b/src/pk/asn1/der/integer/der_encode_integer.c index 10985f9..ee3968f 100644 --- a/src/pk/asn1/der/integer/der_encode_integer.c +++ b/src/pk/asn1/der/integer/der_encode_integer.c @@ -70,16 +70,16 @@ int der_encode_integer(void *num, unsigned char *out, unsigned long *outlen) *out++ = (unsigned char)y; } else if (y < 256) { *out++ = 0x81; - *out++ = y; + *out++ = (unsigned char)y; } else if (y < 65536UL) { *out++ = 0x82; - *out++ = (y>>8)&255; - *out++ = y; + *out++ = (unsigned char)((y>>8)&255); + *out++ = (unsigned char)y; } else if (y < 16777216UL) { *out++ = 0x83; - *out++ = (y>>16)&255; - *out++ = (y>>8)&255; - *out++ = y; + *out++ = (unsigned char)((y>>16)&255); + *out++ = (unsigned char)((y>>8)&255); + *out++ = (unsigned char)y; } else { return CRYPT_INVALID_ARG; } diff --git a/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c b/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c index 71efcb1..c821259 100644 --- a/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c +++ b/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c @@ -77,13 +77,13 @@ int der_decode_object_identifier(const unsigned char *in, unsigned long inle if (y >= *outlen) { return CRYPT_BUFFER_OVERFLOW; } - if (y == 0) { - words[0] = t / 40; - words[1] = t % 40; - y = 2; - } else { + if (y == 0) { + words[0] = t / 40; + words[1] = t % 40; + y = 2; + } else { words[y++] = t; - } + } t = 0; } } diff --git a/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c b/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c index 9f1fe3b..844729c 100644 --- a/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c +++ b/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c @@ -58,14 +58,14 @@ int der_encode_object_identifier(unsigned long *words, unsigned long nwords, x = 0; out[x++] = 0x06; if (z < 128) { - out[x++] = z; + out[x++] = (unsigned char)z; } else if (z < 256) { out[x++] = 0x81; - out[x++] = z; + out[x++] = (unsigned char)z; } else if (z < 65536UL) { out[x++] = 0x82; - out[x++] = (z>>8)&255; - out[x++] = z&255; + out[x++] = (unsigned char)((z>>8)&255); + out[x++] = (unsigned char)(z&255); } else { return CRYPT_INVALID_ARG; } @@ -79,14 +79,14 @@ int der_encode_object_identifier(unsigned long *words, unsigned long nwords, y = x; mask = 0; while (t) { - out[x++] = (t & 0x7F) | mask; + out[x++] = (unsigned char)((t & 0x7F) | mask); t >>= 7; mask |= 0x80; /* upper bit is set on all but the last byte */ } /* now swap bytes y...x-1 */ z = x - 1; while (y < z) { - t = out[y]; out[y] = out[z]; out[z] = t; + t = out[y]; out[y] = out[z]; out[z] = (unsigned char)t; ++y; --z; } diff --git a/src/pk/asn1/der/octet/der_encode_octet_string.c b/src/pk/asn1/der/octet/der_encode_octet_string.c index 54bd38b..b855964 100644 --- a/src/pk/asn1/der/octet/der_encode_octet_string.c +++ b/src/pk/asn1/der/octet/der_encode_octet_string.c @@ -51,19 +51,19 @@ int der_encode_octet_string(const unsigned char *in, unsigned long inlen, x = 0; out[x++] = 0x04; if (inlen < 128) { - out[x++] = inlen; + out[x++] = (unsigned char)inlen; } else if (inlen < 256) { out[x++] = 0x81; - out[x++] = inlen; + out[x++] = (unsigned char)inlen; } else if (inlen < 65536UL) { out[x++] = 0x82; - out[x++] = (inlen>>8)&255; - out[x++] = inlen&255; + out[x++] = (unsigned char)((inlen>>8)&255); + out[x++] = (unsigned char)(inlen&255); } else if (inlen < 16777216UL) { out[x++] = 0x83; - out[x++] = (inlen>>16)&255; - out[x++] = (inlen>>8)&255; - out[x++] = inlen&255; + out[x++] = (unsigned char)((inlen>>16)&255); + out[x++] = (unsigned char)((inlen>>8)&255); + out[x++] = (unsigned char)(inlen&255); } else { return CRYPT_INVALID_ARG; } diff --git a/src/pk/asn1/der/printable_string/der_encode_printable_string.c b/src/pk/asn1/der/printable_string/der_encode_printable_string.c index ae81ced..f3040d3 100644 --- a/src/pk/asn1/der/printable_string/der_encode_printable_string.c +++ b/src/pk/asn1/der/printable_string/der_encode_printable_string.c @@ -50,19 +50,19 @@ int der_encode_printable_string(const unsigned char *in, unsigned long inlen, x = 0; out[x++] = 0x13; if (inlen < 128) { - out[x++] = inlen; + out[x++] = (unsigned char)inlen; } else if (inlen < 256) { out[x++] = 0x81; - out[x++] = inlen; + out[x++] = (unsigned char)inlen; } else if (inlen < 65536UL) { out[x++] = 0x82; - out[x++] = (inlen>>8)&255; - out[x++] = inlen&255; + out[x++] = (unsigned char)((inlen>>8)&255); + out[x++] = (unsigned char)(inlen&255); } else if (inlen < 16777216UL) { out[x++] = 0x83; - out[x++] = (inlen>>16)&255; - out[x++] = (inlen>>8)&255; - out[x++] = inlen&255; + out[x++] = (unsigned char)((inlen>>16)&255); + out[x++] = (unsigned char)((inlen>>8)&255); + out[x++] = (unsigned char)(inlen&255); } else { return CRYPT_INVALID_ARG; } diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c index 34e68d3..2b9172f 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_ex.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_ex.c @@ -95,15 +95,15 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, switch (type) { case LTC_ASN1_BOOLEAN: - z = inlen; - if ((err = der_decode_boolean(in + x, z, ((int *)data))) != CRYPT_OK) { - goto LBL_ERR; - } - if ((err = der_length_boolean(&z)) != CRYPT_OK) { - goto LBL_ERR; - } - break; - + z = inlen; + if ((err = der_decode_boolean(in + x, z, ((int *)data))) != CRYPT_OK) { + goto LBL_ERR; + } + if ((err = der_length_boolean(&z)) != CRYPT_OK) { + goto LBL_ERR; + } + break; + case LTC_ASN1_INTEGER: z = inlen; if ((err = der_decode_integer(in + x, z, data)) != CRYPT_OK) { @@ -197,6 +197,18 @@ int der_decode_sequence_ex(const unsigned char *in, unsigned long inlen, } break; + case LTC_ASN1_UTF8_STRING: + z = inlen; + if ((err = der_decode_utf8_string(in + x, z, data, &size)) != CRYPT_OK) { + if (!ordered) { continue; } + goto LBL_ERR; + } + list[i].size = size; + if ((err = der_length_utf8_string(data, size, &z)) != CRYPT_OK) { + goto LBL_ERR; + } + break; + case LTC_ASN1_UTCTIME: z = inlen; if ((err = der_decode_utctime(in + x, &z, data)) != CRYPT_OK) { diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c b/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c index 42e0b5b..d55b1cd 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c @@ -105,18 +105,18 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc /* now switch on type */ switch (type) { case 0x01: /* BOOLEAN */ - l->type = LTC_ASN1_BOOLEAN; - l->size = 1; - l->data = XCALLOC(1, sizeof(int)); - - if ((err = der_decode_boolean(in, *inlen, l->data)) != CRYPT_OK) { - goto error; + l->type = LTC_ASN1_BOOLEAN; + l->size = 1; + l->data = XCALLOC(1, sizeof(int)); + + if ((err = der_decode_boolean(in, *inlen, l->data)) != CRYPT_OK) { + goto error; } - - if ((err = der_length_boolean(&len)) != CRYPT_OK) { - goto error; + + if ((err = der_length_boolean(&len)) != CRYPT_OK) { + goto error; } - break; + break; case 0x02: /* INTEGER */ /* init field */ @@ -218,7 +218,26 @@ int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc } l->data = realloc_tmp; break; + + case 0x0C: /* UTF8 */ + /* init field */ + l->type = LTC_ASN1_UTF8_STRING; + l->size = len; + + if ((l->data = XCALLOC(sizeof(wchar_t), l->size)) == NULL) { + err = CRYPT_MEM; + goto error; + } + + if ((err = der_decode_utf8_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) { + goto error; + } + + if ((err = der_length_utf8_string(l->data, l->size, &len)) != CRYPT_OK) { + goto error; + } + break; case 0x13: /* PRINTABLE */ diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_multi.c b/src/pk/asn1/der/sequence/der_decode_sequence_multi.c index 64af93c..4c376d2 100644 --- a/src/pk/asn1/der/sequence/der_decode_sequence_multi.c +++ b/src/pk/asn1/der/sequence/der_decode_sequence_multi.c @@ -58,6 +58,7 @@ int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...) case LTC_ASN1_OBJECT_IDENTIFIER: case LTC_ASN1_IA5_STRING: case LTC_ASN1_PRINTABLE_STRING: + case LTC_ASN1_UTF8_STRING: case LTC_ASN1_UTCTIME: case LTC_ASN1_SET: case LTC_ASN1_SETOF: @@ -105,6 +106,7 @@ int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...) case LTC_ASN1_OBJECT_IDENTIFIER: case LTC_ASN1_IA5_STRING: case LTC_ASN1_PRINTABLE_STRING: + case LTC_ASN1_UTF8_STRING: case LTC_ASN1_UTCTIME: case LTC_ASN1_SEQUENCE: case LTC_ASN1_SET: diff --git a/src/pk/asn1/der/sequence/der_encode_sequence_ex.c b/src/pk/asn1/der/sequence/der_encode_sequence_ex.c index fc2eba1..cdb4f1e 100644 --- a/src/pk/asn1/der/sequence/der_encode_sequence_ex.c +++ b/src/pk/asn1/der/sequence/der_encode_sequence_ex.c @@ -52,11 +52,11 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, switch (type) { case LTC_ASN1_BOOLEAN: - if ((err = der_length_boolean(&x)) != CRYPT_OK) { - goto LBL_ERR; - } - y += x; - break; + if ((err = der_length_boolean(&x)) != CRYPT_OK) { + goto LBL_ERR; + } + y += x; + break; case LTC_ASN1_INTEGER: if ((err = der_length_integer(data, &x)) != CRYPT_OK) { @@ -111,6 +111,13 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, y += x; break; + case LTC_ASN1_UTF8_STRING: + if ((err = der_length_utf8_string(data, size, &x)) != CRYPT_OK) { + goto LBL_ERR; + } + y += x; + break; + case LTC_ASN1_UTCTIME: if ((err = der_length_utctime(data, &x)) != CRYPT_OK) { goto LBL_ERR; @@ -163,19 +170,19 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, out[x++] = (type_of == LTC_ASN1_SEQUENCE) ? 0x30 : 0x31; if (z < 128) { - out[x++] = z; + out[x++] = (unsigned char)z; } else if (z < 256) { out[x++] = 0x81; - out[x++] = z; + out[x++] = (unsigned char)z; } else if (z < 65536UL) { out[x++] = 0x82; - out[x++] = (z>>8UL)&255; - out[x++] = z&255; + out[x++] = (unsigned char)((z>>8UL)&255); + out[x++] = (unsigned char)(z&255); } else if (z < 16777216UL) { out[x++] = 0x83; - out[x++] = (z>>16UL)&255; - out[x++] = (z>>8UL)&255; - out[x++] = z&255; + out[x++] = (unsigned char)((z>>16UL)&255); + out[x++] = (unsigned char)((z>>8UL)&255); + out[x++] = (unsigned char)(z&255); } /* store data */ @@ -191,14 +198,14 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, switch (type) { case LTC_ASN1_BOOLEAN: - z = *outlen; - if ((err = der_encode_boolean(*((int *)data), out + x, &z)) != CRYPT_OK) { - goto LBL_ERR; - } - x += z; - *outlen -= z; - break; - + z = *outlen; + if ((err = der_encode_boolean(*((int *)data), out + x, &z)) != CRYPT_OK) { + goto LBL_ERR; + } + x += z; + *outlen -= z; + break; + case LTC_ASN1_INTEGER: z = *outlen; if ((err = der_encode_integer(data, out + x, &z)) != CRYPT_OK) { @@ -268,6 +275,15 @@ int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen, *outlen -= z; break; + case LTC_ASN1_UTF8_STRING: + z = *outlen; + if ((err = der_encode_utf8_string(data, size, out + x, &z)) != CRYPT_OK) { + goto LBL_ERR; + } + x += z; + *outlen -= z; + break; + case LTC_ASN1_UTCTIME: z = *outlen; if ((err = der_encode_utctime(data, out + x, &z)) != CRYPT_OK) { diff --git a/src/pk/asn1/der/sequence/der_encode_sequence_multi.c b/src/pk/asn1/der/sequence/der_encode_sequence_multi.c index 4386a0a..4ac2fa0 100644 --- a/src/pk/asn1/der/sequence/der_encode_sequence_multi.c +++ b/src/pk/asn1/der/sequence/der_encode_sequence_multi.c @@ -59,6 +59,7 @@ int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...) case LTC_ASN1_OBJECT_IDENTIFIER: case LTC_ASN1_IA5_STRING: case LTC_ASN1_PRINTABLE_STRING: + case LTC_ASN1_UTF8_STRING: case LTC_ASN1_UTCTIME: case LTC_ASN1_SEQUENCE: case LTC_ASN1_SET: @@ -105,6 +106,7 @@ int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...) case LTC_ASN1_OBJECT_IDENTIFIER: case LTC_ASN1_IA5_STRING: case LTC_ASN1_PRINTABLE_STRING: + case LTC_ASN1_UTF8_STRING: case LTC_ASN1_UTCTIME: case LTC_ASN1_SEQUENCE: case LTC_ASN1_SET: diff --git a/src/pk/asn1/der/sequence/der_length_sequence.c b/src/pk/asn1/der/sequence/der_length_sequence.c index 7ba535c..8e6e2bb 100644 --- a/src/pk/asn1/der/sequence/der_length_sequence.c +++ b/src/pk/asn1/der/sequence/der_length_sequence.c @@ -47,12 +47,12 @@ int der_length_sequence(ltc_asn1_list *list, unsigned long inlen, switch (type) { case LTC_ASN1_BOOLEAN: - if ((err = der_length_boolean(&x)) != CRYPT_OK) { - goto LBL_ERR; - } - y += x; - break; - + if ((err = der_length_boolean(&x)) != CRYPT_OK) { + goto LBL_ERR; + } + y += x; + break; + case LTC_ASN1_INTEGER: if ((err = der_length_integer(data, &x)) != CRYPT_OK) { goto LBL_ERR; @@ -113,6 +113,13 @@ int der_length_sequence(ltc_asn1_list *list, unsigned long inlen, y += x; break; + case LTC_ASN1_UTF8_STRING: + if ((err = der_length_utf8_string(data, size, &x)) != CRYPT_OK) { + goto LBL_ERR; + } + y += x; + break; + case LTC_ASN1_SET: case LTC_ASN1_SETOF: case LTC_ASN1_SEQUENCE: diff --git a/src/pk/asn1/der/set/der_encode_set.c b/src/pk/asn1/der/set/der_encode_set.c index 2fb33d1..c09ee9f 100644 --- a/src/pk/asn1/der/set/der_encode_set.c +++ b/src/pk/asn1/der/set/der_encode_set.c @@ -28,6 +28,7 @@ static int ltc_to_asn1(int v) case LTC_ASN1_OCTET_STRING: return 0x04; case LTC_ASN1_NULL: return 0x05; case LTC_ASN1_OBJECT_IDENTIFIER: return 0x06; + case LTC_ASN1_UTF8_STRING: return 0x0C; case LTC_ASN1_PRINTABLE_STRING: return 0x13; case LTC_ASN1_IA5_STRING: return 0x16; case LTC_ASN1_UTCTIME: return 0x17; diff --git a/src/pk/asn1/der/short_integer/der_encode_short_integer.c b/src/pk/asn1/der/short_integer/der_encode_short_integer.c index d9aebba..09b843c 100644 --- a/src/pk/asn1/der/short_integer/der_encode_short_integer.c +++ b/src/pk/asn1/der/short_integer/der_encode_short_integer.c @@ -70,7 +70,7 @@ int der_encode_short_integer(unsigned long num, unsigned char *out, unsigned lon /* store header */ x = 0; out[x++] = 0x02; - out[x++] = z; + out[x++] = (unsigned char)z; /* if 31st bit is set output a leading zero and decrement count */ if (z == 5) { @@ -80,7 +80,7 @@ int der_encode_short_integer(unsigned long num, unsigned char *out, unsigned lon /* store values */ for (y = 0; y < z; y++) { - out[x++] = (num >> 24) & 0xFF; + out[x++] = (unsigned char)((num >> 24) & 0xFF); num <<= 8; } diff --git a/src/pk/asn1/der/utctime/der_encode_utctime.c b/src/pk/asn1/der/utctime/der_encode_utctime.c index 510f09f..31f1ba9 100644 --- a/src/pk/asn1/der/utctime/der_encode_utctime.c +++ b/src/pk/asn1/der/utctime/der_encode_utctime.c @@ -69,7 +69,7 @@ int der_encode_utctime(ltc_utctime *utctime, } /* store length */ - out[1] = x - 2; + out[1] = (unsigned char)(x - 2); /* all good let's return */ *outlen = x; diff --git a/src/pk/asn1/der/utf8/der_decode_utf8_string.c b/src/pk/asn1/der/utf8/der_decode_utf8_string.c new file mode 100644 index 0000000..beb326f --- /dev/null +++ b/src/pk/asn1/der/utf8/der_decode_utf8_string.c @@ -0,0 +1,111 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com + */ +#include "tomcrypt.h" + +/** + @file der_decode_utf8_string.c + ASN.1 DER, encode a UTF8 STRING, Tom St Denis +*/ + + +#ifdef LTC_DER + +/** + Store a UTF8 STRING + @param in The DER encoded UTF8 STRING + @param inlen The size of the DER UTF8 STRING + @param out [out] The array of utf8s stored (one per char) + @param outlen [in/out] The number of utf8s stored + @return CRYPT_OK if successful +*/ +int der_decode_utf8_string(const unsigned char *in, unsigned long inlen, + wchar_t *out, unsigned long *outlen) +{ + wchar_t tmp; + unsigned long x, y, z, len; + + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(out != NULL); + LTC_ARGCHK(outlen != NULL); + + /* must have header at least */ + if (inlen < 2) { + return CRYPT_INVALID_PACKET; + } + + /* check for 0x0C */ + if ((in[0] & 0x1F) != 0x0C) { + return CRYPT_INVALID_PACKET; + } + x = 1; + + /* decode the length */ + if (in[x] & 0x80) { + /* valid # of bytes in length are 1,2,3 */ + y = in[x] & 0x7F; + if ((y == 0) || (y > 3) || ((x + y) > inlen)) { + return CRYPT_INVALID_PACKET; + } + + /* read the length in */ + len = 0; + ++x; + while (y--) { + len = (len << 8) | in[x++]; + } + } else { + len = in[x++] & 0x7F; + } + + if (len + x > inlen) { + return CRYPT_INVALID_PACKET; + } + + /* proceed to decode */ + for (y = 0; x < inlen; ) { + /* get first byte */ + tmp = in[x++]; + + /* count number of bytes */ + for (z = 0; (tmp & 0x80) && (z <= 4); z++, tmp = (tmp << 1) & 0xFF); + + if (z > 4 || (x + (z - 1) > inlen)) { + return CRYPT_INVALID_PACKET; + } + + /* decode, grab upper bits */ + tmp >>= z; + + /* grab remaining bytes */ + if (z > 1) { --z; } + while (z-- != 0) { + if ((in[x] & 0xC0) != 0x80) { + return CRYPT_INVALID_PACKET; + } + tmp = (tmp << 6) | ((wchar_t)in[x++] & 0x3F); + } + + if (y > *outlen) { + *outlen = y; + return CRYPT_BUFFER_OVERFLOW; + } + out[y++] = tmp; + } + *outlen = y; + + return CRYPT_OK; +} + +#endif + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ diff --git a/src/pk/asn1/der/utf8/der_encode_utf8_string.c b/src/pk/asn1/der/utf8/der_encode_utf8_string.c new file mode 100644 index 0000000..b0d3302 --- /dev/null +++ b/src/pk/asn1/der/utf8/der_encode_utf8_string.c @@ -0,0 +1,105 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com + */ +#include "tomcrypt.h" + +/** + @file der_encode_utf8_string.c + ASN.1 DER, encode a UTF8 STRING, Tom St Denis +*/ + + +#ifdef LTC_DER + +/** + Store an UTF8 STRING + @param in The array of UTF8 to store (one per wchar_t) + @param inlen The number of UTF8 to store + @param out [out] The destination for the DER encoded UTF8 STRING + @param outlen [in/out] The max size and resulting size of the DER UTF8 STRING + @return CRYPT_OK if successful +*/ +int der_encode_utf8_string(const wchar_t *in, unsigned long inlen, + unsigned char *out, unsigned long *outlen) +{ + unsigned long x, y, len; + + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(out != NULL); + LTC_ARGCHK(outlen != NULL); + + /* get the size */ + for (x = len = 0; x < inlen; x++) { + if (in[x] < 0 || in[x] > 0x1FFFF) { + return CRYPT_INVALID_ARG; + } + len += der_utf8_charsize(in[x]); + } + + if (len < 128) { + y = 2 + len; + } else if (len < 256) { + y = 3 + len; + } else if (len < 65536UL) { + y = 4 + len; + } else if (len < 16777216UL) { + y = 5 + len; + } else { + return CRYPT_INVALID_ARG; + } + + /* too big? */ + if (y > *outlen) { + *outlen = len; + return CRYPT_BUFFER_OVERFLOW; + } + + /* encode the header+len */ + x = 0; + out[x++] = 0x0C; + if (len < 128) { + out[x++] = len; + } else if (len < 256) { + out[x++] = 0x81; + out[x++] = len; + } else if (len < 65536UL) { + out[x++] = 0x82; + out[x++] = (len>>8)&255; + out[x++] = len&255; + } else if (len < 16777216UL) { + out[x++] = 0x83; + out[x++] = (len>>16)&255; + out[x++] = (len>>8)&255; + out[x++] = len&255; + } else { + return CRYPT_INVALID_ARG; + } + + /* store UTF8 */ + for (y = 0; y < inlen; y++) { + switch (der_utf8_charsize(in[y])) { + case 1: out[x++] = in[y]; break; + case 2: out[x++] = 0xC0 | ((in[y] >> 6) & 0x1F); out[x++] = 0x80 | (in[y] & 0x3F); break; + case 3: out[x++] = 0xE0 | ((in[y] >> 12) & 0x0F); out[x++] = 0x80 | ((in[y] >> 6) & 0x3F); out[x++] = 0x80 | (in[y] & 0x3F); break; + case 4: out[x++] = 0xF0 | ((in[y] >> 18) & 0x07); out[x++] = 0x80 | ((in[y] >> 12) & 0x3F); out[x++] = 0x80 | ((in[y] >> 6) & 0x3F); out[x++] = 0x80 | (in[y] & 0x3F); break; + } + } + + /* retun length */ + *outlen = x; + + return CRYPT_OK; +} + +#endif + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ diff --git a/src/pk/asn1/der/utf8/der_length_utf8_string.c b/src/pk/asn1/der/utf8/der_length_utf8_string.c new file mode 100644 index 0000000..81af327 --- /dev/null +++ b/src/pk/asn1/der/utf8/der_length_utf8_string.c @@ -0,0 +1,83 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com + */ +#include "tomcrypt.h" + +/** + @file der_length_utf8_string.c + ASN.1 DER, get length of UTF8 STRING, Tom St Denis +*/ + +#ifdef LTC_DER + +/** Return the size in bytes of a UTF-8 character + @param c The UTF-8 character to measure + @return The size in bytes +*/ +unsigned long der_utf8_charsize(const wchar_t c) +{ + if (c <= 0x7F) { + return 1; + } else if (c <= 0x7FF) { + return 2; + } else if (c <= 0xFFFF) { + return 3; + } else { + return 4; + } +} + +/** + Gets length of DER encoding of UTF8 STRING + @param in The characters to measure the length of + @param noctets The number of octets in the string to encode + @param outlen [out] The length of the DER encoding for the given string + @return CRYPT_OK if successful +*/ +int der_length_utf8_string(const wchar_t *in, unsigned long noctets, unsigned long *outlen) +{ + unsigned long x, len; + + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(outlen != NULL); + + len = 0; + for (x = 0; x < noctets; x++) { + if (in[x] < 0 || in[x] > 0x10FFFF) { + return CRYPT_INVALID_ARG; + } + len += der_utf8_charsize(in[x]); + } + + if (len < 128) { + /* 0C LL DD DD DD ... */ + *outlen = 2 + len; + } else if (len < 256) { + /* 0C 81 LL DD DD DD ... */ + *outlen = 3 + len; + } else if (len < 65536UL) { + /* 0C 82 LL LL DD DD DD ... */ + *outlen = 4 + len; + } else if (len < 16777216UL) { + /* 0C 83 LL LL LL DD DD DD ... */ + *outlen = 5 + len; + } else { + return CRYPT_INVALID_ARG; + } + + return CRYPT_OK; +} + +#endif + + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ diff --git a/src/pk/dsa/dsa_decrypt_key.c b/src/pk/dsa/dsa_decrypt_key.c index d574759..338eda9 100644 --- a/src/pk/dsa/dsa_decrypt_key.c +++ b/src/pk/dsa/dsa_decrypt_key.c @@ -125,7 +125,7 @@ LBL_ERR: XFREE(expt); XFREE(skey); - + mp_clear(g_pub); return err; diff --git a/src/pk/dsa/dsa_encrypt_key.c b/src/pk/dsa/dsa_encrypt_key.c index a8801f5..0ff60ba 100644 --- a/src/pk/dsa/dsa_encrypt_key.c +++ b/src/pk/dsa/dsa_encrypt_key.c @@ -125,7 +125,6 @@ LBL_ERR: XFREE(expt); mp_clear_multi(g_pub, g_priv, NULL); - return err; } diff --git a/src/pk/dsa/dsa_make_key.c b/src/pk/dsa/dsa_make_key.c index f75736c..5052df9 100644 --- a/src/pk/dsa/dsa_make_key.c +++ b/src/pk/dsa/dsa_make_key.c @@ -54,11 +54,12 @@ int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, /* init mp_ints */ if ((err = mp_init_multi(&tmp, &tmp2, &key->g, &key->q, &key->p, &key->x, &key->y, NULL)) != CRYPT_OK) { - goto LBL_ERR; + XFREE(buf); + return err; } /* make our prime q */ - if ((err = rand_prime(key->q, group_size, prng, wprng)) != CRYPT_OK) { goto LBL_ERR; } + if ((err = rand_prime(key->q, group_size, prng, wprng)) != CRYPT_OK) { goto error; } /* double q */ if ((err = mp_add(key->q, key->q, tmp)) != CRYPT_OK) { goto error; } @@ -66,7 +67,7 @@ int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, /* now make a random string and multply it against q */ if (prng_descriptor[wprng].read(buf+1, modulus_size - group_size, prng) != (unsigned long)(modulus_size - group_size)) { err = CRYPT_ERROR_READPRNG; - goto LBL_ERR; + goto error; } /* force magnitude */ @@ -81,7 +82,7 @@ int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, /* now loop until p is prime */ for (;;) { - if ((err = mp_prime_is_prime(key->p, 8, &res)) != CRYPT_OK) { goto LBL_ERR; } + if ((err = mp_prime_is_prime(key->p, 8, &res)) != CRYPT_OK) { goto error; } if (res == LTC_MP_YES) break; /* add 2q to p and 2 to tmp2 */ @@ -106,7 +107,7 @@ int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, do { if (prng_descriptor[wprng].read(buf, group_size, prng) != (unsigned long)group_size) { err = CRYPT_ERROR_READPRNG; - goto LBL_ERR; + goto error; } if ((err = mp_read_unsigned_bin(key->x, buf, group_size)) != CRYPT_OK) { goto error; } } while (mp_cmp_d(key->x, 1) != LTC_MP_GT); @@ -122,11 +123,9 @@ int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, err = CRYPT_OK; goto done; error: -LBL_ERR: mp_clear_multi(key->g, key->q, key->p, key->x, key->y, NULL); done: mp_clear_multi(tmp, tmp2, NULL); - XFREE(buf); return err; } diff --git a/src/pk/dsa/dsa_shared_secret.c b/src/pk/dsa/dsa_shared_secret.c index ed7c4fb..25a30e7 100644 --- a/src/pk/dsa/dsa_shared_secret.c +++ b/src/pk/dsa/dsa_shared_secret.c @@ -30,9 +30,9 @@ int dsa_shared_secret(void *private_key, void *base, dsa_key *public_key, unsigned char *out, unsigned long *outlen) { - unsigned long x; - void *res; - int err; + unsigned long x; + void *res; + int err; LTC_ARGCHK(private_key != NULL); LTC_ARGCHK(public_key != NULL); diff --git a/src/pk/dsa/dsa_sign_hash.c b/src/pk/dsa/dsa_sign_hash.c index cd66505..5cb8df9 100644 --- a/src/pk/dsa/dsa_sign_hash.c +++ b/src/pk/dsa/dsa_sign_hash.c @@ -59,7 +59,7 @@ int dsa_sign_hash_raw(const unsigned char *in, unsigned long inlen, } /* Init our temps */ - if ((err = mp_init_multi(&k, &kinv, &tmp, NULL)) != CRYPT_OK) { goto error; } + if ((err = mp_init_multi(&k, &kinv, &tmp, NULL)) != CRYPT_OK) { goto ERRBUF; } retry: @@ -67,7 +67,7 @@ retry: /* gen random k */ if (prng_descriptor[wprng].read(buf, key->qord, prng) != (unsigned long)key->qord) { err = CRYPT_ERROR_READPRNG; - goto LBL_ERR; + goto error; } /* read k */ @@ -98,11 +98,9 @@ retry: if (mp_iszero(s) == LTC_MP_YES) { goto retry; } err = CRYPT_OK; - goto LBL_ERR; - error: -LBL_ERR: mp_clear_multi(k, kinv, tmp, NULL); +ERRBUF: #ifdef LTC_CLEAN_STACK zeromem(buf, MDSA_MAX_GROUP); #endif @@ -138,7 +136,7 @@ int dsa_sign_hash(const unsigned char *in, unsigned long inlen, } if ((err = dsa_sign_hash_raw(in, inlen, r, s, prng, wprng, key)) != CRYPT_OK) { - goto LBL_ERR; + goto error; } err = der_encode_sequence_multi(out, outlen, @@ -146,7 +144,7 @@ int dsa_sign_hash(const unsigned char *in, unsigned long inlen, LTC_ASN1_INTEGER, 1UL, s, LTC_ASN1_EOL, 0UL, NULL); -LBL_ERR: +error: mp_clear_multi(r, s, NULL); return err; } diff --git a/src/pk/dsa/dsa_verify_hash.c b/src/pk/dsa/dsa_verify_hash.c index b87edbb..f58a53b 100644 --- a/src/pk/dsa/dsa_verify_hash.c +++ b/src/pk/dsa/dsa_verify_hash.c @@ -51,7 +51,7 @@ int dsa_verify_hash_raw( void *r, void *s, /* neither r or s can be null or >q*/ if (mp_iszero(r) == LTC_MP_YES || mp_iszero(s) == LTC_MP_YES || mp_cmp(r, key->q) != LTC_MP_LT || mp_cmp(s, key->q) != LTC_MP_LT) { err = CRYPT_INVALID_PACKET; - goto done; + goto error; } /* w = 1/s mod q */ @@ -76,10 +76,8 @@ int dsa_verify_hash_raw( void *r, void *s, } err = CRYPT_OK; - goto done; - -error : -done : mp_clear_multi(w, v, u1, u2, NULL); +error: + mp_clear_multi(w, v, u1, u2, NULL); return err; } diff --git a/src/pk/dsa/dsa_verify_key.c b/src/pk/dsa/dsa_verify_key.c index 22a8325..3c6adcc 100644 --- a/src/pk/dsa/dsa_verify_key.c +++ b/src/pk/dsa/dsa_verify_key.c @@ -53,45 +53,44 @@ int dsa_verify_key(dsa_key *key, int *stat) if (mp_cmp_d(key->g, 0) == LTC_MP_EQ || mp_cmp_d(key->g, 1) == LTC_MP_EQ) { return CRYPT_OK; } - if ((err = mp_init_multi(&tmp, &tmp2, NULL)) != CRYPT_OK) { goto error; } - if ((err = mp_sub_d(key->p, 1, tmp)) != CRYPT_OK) { goto error; } + if ((err = mp_init_multi(&tmp, &tmp2, NULL)) != CRYPT_OK) { return err; } + if ((err = mp_sub_d(key->p, 1, tmp)) != CRYPT_OK) { goto error; } if (mp_cmp(tmp, key->g) == LTC_MP_EQ || mp_cmp(key->g, key->p) != LTC_MP_LT) { err = CRYPT_OK; - goto done; + goto error; } /* 1 < y < p-1 */ if (!(mp_cmp_d(key->y, 1) == LTC_MP_GT && mp_cmp(key->y, tmp) == LTC_MP_LT)) { err = CRYPT_OK; - goto done; + goto error; } /* now we have to make sure that g^q = 1, and that p-1/q gives 0 remainder */ if ((err = mp_div(tmp, key->q, tmp, tmp2)) != CRYPT_OK) { goto error; } if (mp_iszero(tmp2) != LTC_MP_YES) { err = CRYPT_OK; - goto done; + goto error; } if ((err = mp_exptmod(key->g, key->q, key->p, tmp)) != CRYPT_OK) { goto error; } if (mp_cmp_d(tmp, 1) != LTC_MP_EQ) { err = CRYPT_OK; - goto done; + goto error; } /* now we have to make sure that y^q = 1, this makes sure y \in g^x mod p */ if ((err = mp_exptmod(key->y, key->q, key->p, tmp)) != CRYPT_OK) { goto error; } if (mp_cmp_d(tmp, 1) != LTC_MP_EQ) { err = CRYPT_OK; - goto done; + goto error; } /* at this point we are out of tests ;-( */ err = CRYPT_OK; *stat = 1; - goto done; error: -done : mp_clear_multi(tmp, tmp2, NULL); + mp_clear_multi(tmp, tmp2, NULL); return err; } #endif diff --git a/src/pk/ecc/ecc_ansi_x963_export.c b/src/pk/ecc/ecc_ansi_x963_export.c index e3fac2b..1921512 100644 --- a/src/pk/ecc/ecc_ansi_x963_export.c +++ b/src/pk/ecc/ecc_ansi_x963_export.c @@ -31,7 +31,7 @@ */ int ecc_ansi_x963_export(ecc_key *key, unsigned char *out, unsigned long *outlen) { - unsigned char buf[128]; + unsigned char buf[ECC_BUF_SIZE]; unsigned long numlen; LTC_ARGCHK(key != NULL); @@ -41,7 +41,7 @@ int ecc_ansi_x963_export(ecc_key *key, unsigned char *out, unsigned long *outlen if (ltc_ecc_is_valid_idx(key->idx) == 0) { return CRYPT_INVALID_ARG; } - numlen = ltc_ecc_sets[key->idx].size; + numlen = key->dp->size; if (*outlen < (1 + 2*numlen)) { *outlen = 1 + 2*numlen; diff --git a/src/pk/ecc/ecc_ansi_x963_import.c b/src/pk/ecc/ecc_ansi_x963_import.c index 9f85453..c0ba18a 100644 --- a/src/pk/ecc/ecc_ansi_x963_import.c +++ b/src/pk/ecc/ecc_ansi_x963_import.c @@ -29,10 +29,15 @@ @param key [out] destination to store imported key \ */ int ecc_ansi_x963_import(const unsigned char *in, unsigned long inlen, ecc_key *key) +{ + return ecc_ansi_x963_import_ex(in, inlen, key, NULL); +} + +int ecc_ansi_x963_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, ltc_ecc_set_type *dp) { int x, err; - LTC_ARGCHK(in != NULL); + LTC_ARGCHK(in != NULL); LTC_ARGCHK(key != NULL); /* must be odd */ @@ -59,21 +64,30 @@ int ecc_ansi_x963_import(const unsigned char *in, unsigned long inlen, ecc_key * if ((err = mp_read_unsigned_bin(key->pubkey.y, (unsigned char *)in+1+((inlen-1)>>1), (inlen-1)>>1)) != CRYPT_OK) { goto error; } - mp_set(key->pubkey.z, 1); + if ((err = mp_set(key->pubkey.z, 1)) != CRYPT_OK) { goto error; } - /* determine the idx */ - for (x = 0; ltc_ecc_sets[x].size != 0; x++) { - if ((unsigned)ltc_ecc_sets[x].size >= ((inlen-1)>>1)) { - break; + if (dp == NULL) { + /* determine the idx */ + for (x = 0; ltc_ecc_sets[x].size != 0; x++) { + if ((unsigned)ltc_ecc_sets[x].size >= ((inlen-1)>>1)) { + break; + } } + if (ltc_ecc_sets[x].size == 0) { + err = CRYPT_INVALID_PACKET; + goto error; + } + /* set the idx */ + key->idx = x; + key->dp = <c_ecc_sets[x]; + } else { + if (((inlen-1)>>1) != (unsigned long) dp->size) { + err = CRYPT_INVALID_PACKET; + goto error; + } + key->idx = -1; + key->dp = dp; } - if (ltc_ecc_sets[x].size == 0) { - err = CRYPT_INVALID_PACKET; - goto error; - } - - /* set the idx */ - key->idx = x; key->type = PK_PUBLIC; /* we're done */ diff --git a/src/pk/ecc/ecc_encrypt_key.c b/src/pk/ecc/ecc_encrypt_key.c index c2f3364..30ba9a4 100644 --- a/src/pk/ecc/ecc_encrypt_key.c +++ b/src/pk/ecc/ecc_encrypt_key.c @@ -64,7 +64,7 @@ int ecc_encrypt_key(const unsigned char *in, unsigned long inlen, } /* make a random key and export the public copy */ - if ((err = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { + if ((err = ecc_make_key_ex(prng, wprng, &pubkey, key->dp)) != CRYPT_OK) { return err; } diff --git a/src/pk/ecc/ecc_export.c b/src/pk/ecc/ecc_export.c index 188932c..5e4260c 100644 --- a/src/pk/ecc/ecc_export.c +++ b/src/pk/ecc/ecc_export.c @@ -51,7 +51,7 @@ int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key } /* we store the NIST byte size */ - key_size = ltc_ecc_sets[key->idx].size; + key_size = key->dp->size; if (type == PK_PRIVATE) { flags[0] = 1; diff --git a/src/pk/ecc/ecc_get_size.c b/src/pk/ecc/ecc_get_size.c index 595b377..b4c15ad 100644 --- a/src/pk/ecc/ecc_get_size.c +++ b/src/pk/ecc/ecc_get_size.c @@ -32,7 +32,7 @@ int ecc_get_size(ecc_key *key) { LTC_ARGCHK(key != NULL); if (ltc_ecc_is_valid_idx(key->idx)) - return ltc_ecc_sets[key->idx].size; + return key->dp->size; else return INT_MAX; /* large value known to cause it to fail when passed to ecc_make_key() */ } diff --git a/src/pk/ecc/ecc_import.c b/src/pk/ecc/ecc_import.c index 7250e64..f33245d 100644 --- a/src/pk/ecc/ecc_import.c +++ b/src/pk/ecc/ecc_import.c @@ -33,8 +33,8 @@ static int is_point(ecc_key *key) } /* load prime and b */ - if ((err = mp_read_radix(prime, ltc_ecc_sets[key->idx].prime, 16)) != CRYPT_OK) { goto error; } - if ((err = mp_read_radix(b, ltc_ecc_sets[key->idx].B, 16)) != CRYPT_OK) { goto error; } + if ((err = mp_read_radix(prime, key->dp->prime, 16)) != CRYPT_OK) { goto error; } + if ((err = mp_read_radix(b, key->dp->B, 16)) != CRYPT_OK) { goto error; } /* compute y^2 */ if ((err = mp_sqr(key->pubkey.y, t1)) != CRYPT_OK) { goto error; } @@ -79,6 +79,19 @@ error: @return CRYPT_OK if successful, upon error all allocated memory will be freed */ int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key) +{ + return ecc_import_ex(in, inlen, key, NULL); +} + +/** + Import an ECC key from a binary packet, using user supplied domain params rather than one of the NIST ones + @param in The packet to import + @param inlen The length of the packet + @param key [out] The destination of the import + @param dp pointer to user supplied params; must be the same as the params used when exporting + @return CRYPT_OK if successful, upon error all allocated memory will be freed +*/ +int ecc_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_set_type *dp) { unsigned long key_size; unsigned char flags[1]; @@ -126,15 +139,20 @@ int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key) } } - /* find the idx */ - for (key->idx = 0; ltc_ecc_sets[key->idx].size && (unsigned long)ltc_ecc_sets[key->idx].size != key_size; ++key->idx); - if (ltc_ecc_sets[key->idx].size == 0) { - err = CRYPT_INVALID_PACKET; - goto done; + if (dp == NULL) { + /* find the idx */ + for (key->idx = 0; ltc_ecc_sets[key->idx].size && (unsigned long)ltc_ecc_sets[key->idx].size != key_size; ++key->idx); + if (ltc_ecc_sets[key->idx].size == 0) { + err = CRYPT_INVALID_PACKET; + goto done; + } + key->dp = <c_ecc_sets[key->idx]; + } else { + key->idx = -1; + key->dp = dp; } - /* set z */ - mp_set(key->pubkey.z, 1); + if ((err = mp_set(key->pubkey.z, 1)) != CRYPT_OK) { goto done; } /* is it a point on the curve? */ if ((err = is_point(key)) != CRYPT_OK) { @@ -147,7 +165,6 @@ done: mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL); return err; } - #endif /* $Source$ */ /* $Revision$ */ diff --git a/src/pk/ecc/ecc_make_key.c b/src/pk/ecc/ecc_make_key.c index 35c5255..e7617a6 100644 --- a/src/pk/ecc/ecc_make_key.c +++ b/src/pk/ecc/ecc_make_key.c @@ -33,18 +33,7 @@ */ int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key) { - int x, err; - ecc_point *base; - void *prime; - unsigned char *buf; - - LTC_ARGCHK(key != NULL); - LTC_ARGCHK(ltc_mp.name != NULL); - - /* good prng? */ - if ((err = prng_is_valid(wprng)) != CRYPT_OK) { - return err; - } + int x, err; /* find key size */ for (x = 0; (keysize > ltc_ecc_sets[x].size) && (ltc_ecc_sets[x].size != 0); x++); @@ -53,7 +42,31 @@ int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key) if (keysize > ECC_MAXSIZE || ltc_ecc_sets[x].size == 0) { return CRYPT_INVALID_KEYSIZE; } + err = ecc_make_key_ex(prng, wprng, key, <c_ecc_sets[x]); key->idx = x; + return err; +} + +int ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_set_type *dp) +{ + int err; + ecc_point *base; + void *prime; + unsigned char *buf; + int keysize; + + LTC_ARGCHK(key != NULL); + LTC_ARGCHK(ltc_mp.name != NULL); + LTC_ARGCHK(dp != NULL); + + /* good prng? */ + if ((err = prng_is_valid(wprng)) != CRYPT_OK) { + return err; + } + + key->idx = -1; + key->dp = dp; + keysize = dp->size; /* allocate ram */ base = NULL; @@ -65,43 +78,43 @@ int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key) /* make up random string */ if (prng_descriptor[wprng].read(buf, (unsigned long)keysize, prng) != (unsigned long)keysize) { err = CRYPT_ERROR_READPRNG; - goto LBL_ERR2; + goto ERR_BUF; } /* setup the key variables */ if ((err = mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, &prime, NULL)) != CRYPT_OK) { - goto done; + goto ERR_BUF; } base = ltc_ecc_new_point(); if (base == NULL) { - mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, prime, NULL); err = CRYPT_MEM; - goto done; + goto errkey; } /* read in the specs for this key */ - if ((err = mp_read_radix(prime, (char *)ltc_ecc_sets[key->idx].prime, 16)) != CRYPT_OK) { goto done; } - if ((err = mp_read_radix(base->x, (char *)ltc_ecc_sets[key->idx].Gx, 16)) != CRYPT_OK) { goto done; } - if ((err = mp_read_radix(base->y, (char *)ltc_ecc_sets[key->idx].Gy, 16)) != CRYPT_OK) { goto done; } - mp_set(base->z, 1); - if ((err = mp_read_unsigned_bin(key->k, (unsigned char *)buf, keysize)) != CRYPT_OK) { goto done; } + if ((err = mp_read_radix(prime, (char *)key->dp->prime, 16)) != CRYPT_OK) { goto errkey; } + if ((err = mp_read_radix(base->x, (char *)key->dp->Gx, 16)) != CRYPT_OK) { goto errkey; } + if ((err = mp_read_radix(base->y, (char *)key->dp->Gy, 16)) != CRYPT_OK) { goto errkey; } + if ((err = mp_set(base->z, 1)) != CRYPT_OK) { goto errkey; } + if ((err = mp_read_unsigned_bin(key->k, (unsigned char *)buf, keysize)) != CRYPT_OK) { goto errkey; } /* make the public key */ - if ((err = ltc_mp.ecc_ptmul(key->k, base, &key->pubkey, prime, 1)) != CRYPT_OK) { goto done; } + if ((err = ltc_mp.ecc_ptmul(key->k, base, &key->pubkey, prime, 1)) != CRYPT_OK) { goto errkey; } key->type = PK_PRIVATE; /* free up ram */ err = CRYPT_OK; -done: + goto cleanup; +errkey: + mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL); +cleanup: ltc_ecc_del_point(base); mp_clear(prime); -LBL_ERR2: +ERR_BUF: #ifdef LTC_CLEAN_STACK zeromem(buf, ECC_MAXSIZE); #endif - XFREE(buf); - return err; } diff --git a/src/pk/ecc/ecc_shared_secret.c b/src/pk/ecc/ecc_shared_secret.c index c1f8a7d..36fd058 100644 --- a/src/pk/ecc/ecc_shared_secret.c +++ b/src/pk/ecc/ecc_shared_secret.c @@ -34,10 +34,10 @@ int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, unsigned char *out, unsigned long *outlen) { - unsigned long x; - ecc_point *result; - void *prime; - int err; + unsigned long x; + ecc_point *result; + void *prime; + int err; LTC_ARGCHK(private_key != NULL); LTC_ARGCHK(public_key != NULL); @@ -49,11 +49,11 @@ int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, return CRYPT_PK_NOT_PRIVATE; } - if (ltc_ecc_is_valid_idx(private_key->idx) == 0) { + if (ltc_ecc_is_valid_idx(private_key->idx) == 0 || ltc_ecc_is_valid_idx(public_key->idx) == 0) { return CRYPT_INVALID_ARG; } - if (private_key->idx != public_key->idx) { + if (XSTRCMP(private_key->dp->name, public_key->dp->name) != 0) { return CRYPT_PK_TYPE_MISMATCH; } @@ -68,7 +68,7 @@ int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key, return err; } - if ((err = mp_read_radix(prime, (char *)ltc_ecc_sets[private_key->idx].prime, 16)) != CRYPT_OK) { goto done; } + if ((err = mp_read_radix(prime, (char *)private_key->dp->prime, 16)) != CRYPT_OK) { goto done; } if ((err = ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1)) != CRYPT_OK) { goto done; } x = (unsigned long)mp_unsigned_bin_size(prime); diff --git a/src/pk/ecc/ecc_sign_hash.c b/src/pk/ecc/ecc_sign_hash.c index bf641b4..5e7a325 100644 --- a/src/pk/ecc/ecc_sign_hash.c +++ b/src/pk/ecc/ecc_sign_hash.c @@ -64,22 +64,21 @@ int ecc_sign_hash(const unsigned char *in, unsigned long inlen, /* get the hash and load it as a bignum into 'e' */ /* init the bignums */ if ((err = mp_init_multi(&r, &s, &p, &e, NULL)) != CRYPT_OK) { - ecc_free(&pubkey); - goto LBL_ERR; + return err; } - if ((err = mp_read_radix(p, (char *)ltc_ecc_sets[key->idx].order, 16)) != CRYPT_OK) { goto error; } - if ((err = mp_read_unsigned_bin(e, (unsigned char *)in, (int)inlen)) != CRYPT_OK) { goto error; } + if ((err = mp_read_radix(p, (char *)key->dp->order, 16)) != CRYPT_OK) { goto errnokey; } + if ((err = mp_read_unsigned_bin(e, (unsigned char *)in, (int)inlen)) != CRYPT_OK) { goto errnokey; } /* make up a key and export the public copy */ for (;;) { - if ((err = ecc_make_key(prng, wprng, ecc_get_size(key), &pubkey)) != CRYPT_OK) { - return err; + if ((err = ecc_make_key_ex(prng, wprng, &pubkey, key->dp)) != CRYPT_OK) { + goto errnokey; } /* find r = x1 mod n */ if ((err = mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK) { goto error; } - if (mp_iszero(r)) { + if (mp_iszero(r) == LTC_MP_YES) { ecc_free(&pubkey); } else { /* find s = (e + xr)/k */ @@ -88,10 +87,8 @@ int ecc_sign_hash(const unsigned char *in, unsigned long inlen, if ((err = mp_add(e, s, s)) != CRYPT_OK) { goto error; } /* s = e + xr */ if ((err = mp_mod(s, p, s)) != CRYPT_OK) { goto error; } /* s = e + xr */ if ((err = mp_mulmod(s, pubkey.k, p, s)) != CRYPT_OK) { goto error; } /* s = (e + xr)/k */ - - if (mp_iszero(s)) { - ecc_free(&pubkey); - } else { + ecc_free(&pubkey); + if (mp_iszero(s) == LTC_MP_NO) { break; } } @@ -102,12 +99,11 @@ int ecc_sign_hash(const unsigned char *in, unsigned long inlen, LTC_ASN1_INTEGER, 1UL, r, LTC_ASN1_INTEGER, 1UL, s, LTC_ASN1_EOL, 0UL, NULL); - goto LBL_ERR; + goto errnokey; error: -LBL_ERR: - mp_clear_multi(r, s, p, e, NULL); ecc_free(&pubkey); - +errnokey: + mp_clear_multi(r, s, p, e, NULL); return err; } diff --git a/src/pk/ecc/ecc_test.c b/src/pk/ecc/ecc_test.c index 545fb10..de2ca02 100644 --- a/src/pk/ecc/ecc_test.c +++ b/src/pk/ecc/ecc_test.c @@ -80,7 +80,6 @@ int ecc_test(void) } } err = CRYPT_OK; - goto done; done: ltc_ecc_del_point(GG); ltc_ecc_del_point(G); diff --git a/src/pk/ecc/ecc_verify_hash.c b/src/pk/ecc/ecc_verify_hash.c index 5b2ea9f..92f689a 100644 --- a/src/pk/ecc/ecc_verify_hash.c +++ b/src/pk/ecc/ecc_verify_hash.c @@ -76,7 +76,7 @@ int ecc_verify_hash(const unsigned char *sig, unsigned long siglen, mQ = ltc_ecc_new_point(); if (mQ == NULL || mG == NULL) { err = CRYPT_MEM; - goto done; + goto error; } /* parse header */ @@ -84,19 +84,19 @@ int ecc_verify_hash(const unsigned char *sig, unsigned long siglen, LTC_ASN1_INTEGER, 1UL, r, LTC_ASN1_INTEGER, 1UL, s, LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { - goto done; + goto error; } /* get the order */ - if ((err = mp_read_radix(p, (char *)ltc_ecc_sets[key->idx].order, 16)) != CRYPT_OK) { goto error; } + if ((err = mp_read_radix(p, (char *)key->dp->order, 16)) != CRYPT_OK) { goto error; } /* get the modulus */ - if ((err = mp_read_radix(m, (char *)ltc_ecc_sets[key->idx].prime, 16)) != CRYPT_OK) { goto error; } + if ((err = mp_read_radix(m, (char *)key->dp->prime, 16)) != CRYPT_OK) { goto error; } /* check for zero */ if (mp_iszero(r) || mp_iszero(s) || mp_cmp(r, p) != LTC_MP_LT || mp_cmp(s, p) != LTC_MP_LT) { err = CRYPT_INVALID_PACKET; - goto done; + goto error; } /* read hash */ @@ -111,28 +111,35 @@ int ecc_verify_hash(const unsigned char *sig, unsigned long siglen, /* u2 = rw */ if ((err = mp_mulmod(r, w, p, u2)) != CRYPT_OK) { goto error; } - /* find mG = u1*G */ - if ((err = mp_read_radix(mG->x, (char *)ltc_ecc_sets[key->idx].Gx, 16)) != CRYPT_OK) { goto error; } - if ((err = mp_read_radix(mG->y, (char *)ltc_ecc_sets[key->idx].Gy, 16)) != CRYPT_OK) { goto error; } - mp_set(mG->z, 1); - if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, m, 0)) != CRYPT_OK) { goto done; } + /* find mG and mQ */ + if ((err = mp_read_radix(mG->x, (char *)key->dp->Gx, 16)) != CRYPT_OK) { goto error; } + if ((err = mp_read_radix(mG->y, (char *)key->dp->Gy, 16)) != CRYPT_OK) { goto error; } + if ((err = mp_set(mG->z, 1)) != CRYPT_OK) { goto error; } - /* find mQ = u2*Q */ if ((err = mp_copy(key->pubkey.x, mQ->x)) != CRYPT_OK) { goto error; } if ((err = mp_copy(key->pubkey.y, mQ->y)) != CRYPT_OK) { goto error; } if ((err = mp_copy(key->pubkey.z, mQ->z)) != CRYPT_OK) { goto error; } - if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0)) != CRYPT_OK) { goto done; } + + /* compute u1*mG + u2*mQ = mG */ + if (ltc_mp.ecc_mul2add == NULL) { + if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, m, 0)) != CRYPT_OK) { goto error; } + if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0)) != CRYPT_OK) { goto error; } - /* find the montgomery mp */ - if ((err = mp_montgomery_setup(m, &mp)) != CRYPT_OK) { goto error; } - /* add them */ - if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp)) != CRYPT_OK) { goto done; } + /* find the montgomery mp */ + if ((err = mp_montgomery_setup(m, &mp)) != CRYPT_OK) { goto error; } + + /* add them */ + if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp)) != CRYPT_OK) { goto error; } - /* reduce */ - if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK) { goto done; } + /* reduce */ + if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK) { goto error; } + } else { + /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */ + if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m)) != CRYPT_OK) { goto error; } + } /* v = X_x1 mod n */ - if ((err = mp_mod(mG->x, p, v)) != CRYPT_OK) { goto done; } + if ((err = mp_mod(mG->x, p, v)) != CRYPT_OK) { goto error; } /* does v == r */ if (mp_cmp(v, r) == LTC_MP_EQ) { @@ -141,9 +148,7 @@ int ecc_verify_hash(const unsigned char *sig, unsigned long siglen, /* clear up and return */ err = CRYPT_OK; - goto done; error: -done: ltc_ecc_del_point(mG); ltc_ecc_del_point(mQ); mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL); diff --git a/src/pk/ecc/ltc_ecc_is_valid_idx.c b/src/pk/ecc/ltc_ecc_is_valid_idx.c index de4c818..9335555 100644 --- a/src/pk/ecc/ltc_ecc_is_valid_idx.c +++ b/src/pk/ecc/ltc_ecc_is_valid_idx.c @@ -32,10 +32,11 @@ int ltc_ecc_is_valid_idx(int n) int x; for (x = 0; ltc_ecc_sets[x].size != 0; x++); - if ((n < 0) || (n >= x)) { - return 0; + /* -1 is a valid index --- indicating that the domain params were supplied by the user */ + if ((n >= -1) || (n < x)) { + return 1; } - return 1; + return 0; } #endif diff --git a/src/pk/ecc/ltc_ecc_map.c b/src/pk/ecc/ltc_ecc_map.c index a1cacc7..97df5cb 100644 --- a/src/pk/ecc/ltc_ecc_map.c +++ b/src/pk/ecc/ltc_ecc_map.c @@ -33,7 +33,7 @@ int ltc_ecc_map(ecc_point *P, void *modulus, void *mp) { void *t1, *t2; - int err; + int err; LTC_ARGCHK(P != NULL); LTC_ARGCHK(modulus != NULL); @@ -60,10 +60,9 @@ int ltc_ecc_map(ecc_point *P, void *modulus, void *mp) if ((err = mp_montgomery_reduce(P->x, modulus, mp)) != CRYPT_OK) { goto done; } if ((err = mp_mul(P->y, t1, P->y)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(P->y, modulus, mp)) != CRYPT_OK) { goto done; } - mp_set(P->z, 1); + if ((err = mp_set(P->z, 1)) != CRYPT_OK) { goto done; } err = CRYPT_OK; - goto done; done: mp_clear_multi(t1, t2, NULL); return err; diff --git a/src/pk/ecc/ltc_ecc_mul2add.c b/src/pk/ecc/ltc_ecc_mul2add.c new file mode 100644 index 0000000..2236b88 --- /dev/null +++ b/src/pk/ecc/ltc_ecc_mul2add.c @@ -0,0 +1,207 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com + */ + +/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b + * + * All curves taken from NIST recommendation paper of July 1999 + * Available at http://csrc.nist.gov/cryptval/dss.htm + */ +#include "tomcrypt.h" + +/** + @file ltc_ecc_mul2add.c + ECC Crypto, Shamir's Trick, Tom St Denis +*/ + +#ifdef MECC + +#ifdef LTC_ECC_SHAMIR + +/** Computes kA*A + kB*B = C using Shamir's Trick + @param A First point to multiply + @param kA What to multiple A by + @param B Second point to multiply + @param kB What to multiple B by + @param C [out] Destination point (can overlap with A or B + @param modulus Modulus for curve + @return CRYPT_OK on success +*/ +int ltc_ecc_mul2add(ecc_point *A, void *kA, + ecc_point *B, void *kB, + ecc_point *C, + void *modulus) +{ + ecc_point *precomp[16]; + unsigned bitbufA, bitbufB, lenA, lenB, len, x, y, nA, nB, nibble; + unsigned char *tA, *tB; + int err, first; + void *mp, *mu; + + /* argchks */ + LTC_ARGCHK(A != NULL); + LTC_ARGCHK(B != NULL); + LTC_ARGCHK(C != NULL); + LTC_ARGCHK(kA != NULL); + LTC_ARGCHK(kB != NULL); + LTC_ARGCHK(modulus != NULL); + + /* allocate memory */ + tA = XCALLOC(1, ECC_BUF_SIZE); + if (tA == NULL) { + return CRYPT_MEM; + } + tB = XCALLOC(1, ECC_BUF_SIZE); + if (tB == NULL) { + XFREE(tA); + return CRYPT_MEM; + } + + /* get sizes */ + lenA = mp_unsigned_bin_size(kA); + lenB = mp_unsigned_bin_size(kB); + len = MAX(lenA, lenB); + + /* sanity check */ + if ((lenA > ECC_BUF_SIZE) || (lenB > ECC_BUF_SIZE)) { + err = CRYPT_INVALID_ARG; + goto ERR_T; + } + + /* extract and justify kA */ + mp_to_unsigned_bin(kA, (len - lenA) + tA); + + /* extract and justify kB */ + mp_to_unsigned_bin(kB, (len - lenB) + tB); + + /* allocate the table */ + for (x = 0; x < 16; x++) { + precomp[x] = ltc_ecc_new_point(); + if (precomp[x] == NULL) { + for (y = 0; y < x; ++y) { + ltc_ecc_del_point(precomp[y]); + } + err = CRYPT_MEM; + goto ERR_T; + } + } + + /* init montgomery reduction */ + if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) { + goto ERR_P; + } + if ((err = mp_init(&mu)) != CRYPT_OK) { + goto ERR_MP; + } + if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) { + goto ERR_MU; + } + + /* copy ones ... */ + if ((err = mp_mulmod(A->x, mu, modulus, precomp[1]->x)) != CRYPT_OK) { goto ERR_MU; } + if ((err = mp_mulmod(A->y, mu, modulus, precomp[1]->y)) != CRYPT_OK) { goto ERR_MU; } + if ((err = mp_mulmod(A->z, mu, modulus, precomp[1]->z)) != CRYPT_OK) { goto ERR_MU; } + + if ((err = mp_mulmod(B->x, mu, modulus, precomp[1<<2]->x)) != CRYPT_OK) { goto ERR_MU; } + if ((err = mp_mulmod(B->y, mu, modulus, precomp[1<<2]->y)) != CRYPT_OK) { goto ERR_MU; } + if ((err = mp_mulmod(B->z, mu, modulus, precomp[1<<2]->z)) != CRYPT_OK) { goto ERR_MU; } + + /* precomp [i,0](A + B) table */ + if ((err = ltc_mp.ecc_ptdbl(precomp[1], precomp[2], modulus, mp)) != CRYPT_OK) { goto ERR_MU; } + if ((err = ltc_mp.ecc_ptadd(precomp[1], precomp[2], precomp[3], modulus, mp)) != CRYPT_OK) { goto ERR_MU; } + + /* precomp [0,i](A + B) table */ + if ((err = ltc_mp.ecc_ptdbl(precomp[1<<2], precomp[2<<2], modulus, mp)) != CRYPT_OK) { goto ERR_MU; } + if ((err = ltc_mp.ecc_ptadd(precomp[1<<2], precomp[2<<2], precomp[3<<2], modulus, mp)) != CRYPT_OK) { goto ERR_MU; } + + /* precomp [i,j](A + B) table (i != 0, j != 0) */ + for (x = 1; x < 4; x++) { + for (y = 1; y < 4; y++) { + if ((err = ltc_mp.ecc_ptadd(precomp[x], precomp[(y<<2)], precomp[x+(y<<2)], modulus, mp)) != CRYPT_OK) { goto ERR_MU; } + } + } + + nibble = 3; + first = 1; + bitbufA = tA[0]; + bitbufB = tB[0]; + + /* for every byte of the multiplicands */ + for (x = -1;; ) { + /* grab a nibble */ + if (++nibble == 4) { + ++x; if (x == len) break; + bitbufA = tA[x]; + bitbufB = tB[x]; + nibble = 0; + } + + /* extract two bits from both, shift/update */ + nA = (bitbufA >> 6) & 0x03; + nB = (bitbufB >> 6) & 0x03; + bitbufA = (bitbufA << 2) & 0xFF; + bitbufB = (bitbufB << 2) & 0xFF; + + /* if both zero, if first, continue */ + if ((nA == 0) && (nB == 0) && (first == 1)) { + continue; + } + + /* double twice, only if this isn't the first */ + if (first == 0) { + /* double twice */ + if ((err = ltc_mp.ecc_ptdbl(C, C, modulus, mp)) != CRYPT_OK) { goto ERR_MU; } + if ((err = ltc_mp.ecc_ptdbl(C, C, modulus, mp)) != CRYPT_OK) { goto ERR_MU; } + } + + /* if not both zero */ + if ((nA != 0) || (nB != 0)) { + if (first == 1) { + /* if first, copy from table */ + first = 0; + if ((err = mp_copy(precomp[nA + (nB<<2)]->x, C->x)) != CRYPT_OK) { goto ERR_MU; } + if ((err = mp_copy(precomp[nA + (nB<<2)]->y, C->y)) != CRYPT_OK) { goto ERR_MU; } + if ((err = mp_copy(precomp[nA + (nB<<2)]->z, C->z)) != CRYPT_OK) { goto ERR_MU; } + } else { + /* if not first, add from table */ + if ((err = ltc_mp.ecc_ptadd(C, precomp[nA + (nB<<2)], C, modulus, mp)) != CRYPT_OK) { goto ERR_MU; } + } + } + } + + /* reduce to affine */ + err = ltc_ecc_map(C, modulus, mp); + + /* clean up */ +ERR_MU: + mp_clear(mu); +ERR_MP: + mp_montgomery_free(mp); +ERR_P: + for (x = 0; x < 16; x++) { + ltc_ecc_del_point(precomp[x]); + } +ERR_T: +#ifdef LTC_CLEAN_STACK + zeromem(tA, ECC_BUF_SIZE); + zeromem(tB, ECC_BUF_SIZE); +#endif + XFREE(tA); + XFREE(tB); + + return err; +} + +#endif +#endif + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ diff --git a/src/pk/ecc/ltc_ecc_mulmod.c b/src/pk/ecc/ltc_ecc_mulmod.c index 9d36add..3242207 100644 --- a/src/pk/ecc/ltc_ecc_mulmod.c +++ b/src/pk/ecc/ltc_ecc_mulmod.c @@ -54,6 +54,7 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map) return err; } if ((err = mp_init(&mu)) != CRYPT_OK) { + mp_montgomery_free(mp); return err; } if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) { @@ -90,6 +91,7 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map) if ((err = mp_mulmod(G->z, mu, modulus, tG->z)) != CRYPT_OK) { goto done; } } mp_clear(mu); + mu = NULL; /* calc the M tab, which holds kG for k==8..15 */ /* M[0] == 8G */ @@ -154,11 +156,11 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map) /* ok window is filled so double as required and add */ /* double first */ for (j = 0; j < WINSIZE; j++) { - if ((err = ltc_mp.ecc_ptdbl(R, R, modulus, mp)) != CRYPT_OK) { goto done; } + if ((err = ltc_mp.ecc_ptdbl(R, R, modulus, mp)) != CRYPT_OK) { goto done; } } /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranteed */ - if ((err = ltc_mp.ecc_ptadd(R, M[bitbuf-8], R, modulus, mp)) != CRYPT_OK) { goto done; } + if ((err = ltc_mp.ecc_ptadd(R, M[bitbuf-8], R, modulus, mp)) != CRYPT_OK) { goto done; } } /* empty window and reset */ bitcpy = bitbuf = 0; @@ -172,7 +174,7 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map) for (j = 0; j < bitcpy; j++) { /* only double if we have had at least one add first */ if (first == 0) { - if ((err = ltc_mp.ecc_ptdbl(R, R, modulus, mp)) != CRYPT_OK) { goto done; } + if ((err = ltc_mp.ecc_ptdbl(R, R, modulus, mp)) != CRYPT_OK) { goto done; } } bitbuf <<= 1; @@ -185,7 +187,7 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map) first = 0; } else { /* then add */ - if ((err = ltc_mp.ecc_ptadd(R, tG, R, modulus, mp)) != CRYPT_OK) { goto done; } + if ((err = ltc_mp.ecc_ptadd(R, tG, R, modulus, mp)) != CRYPT_OK) { goto done; } } } } @@ -198,6 +200,9 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map) err = CRYPT_OK; } done: + if (mu != NULL) { + mp_clear(mu); + } mp_montgomery_free(mp); ltc_ecc_del_point(tG); for (i = 0; i < 8; i++) { diff --git a/src/pk/ecc/ltc_ecc_mulmod_timing.c b/src/pk/ecc/ltc_ecc_mulmod_timing.c index 1169c1b..8eb35ca 100644 --- a/src/pk/ecc/ltc_ecc_mulmod_timing.c +++ b/src/pk/ecc/ltc_ecc_mulmod_timing.c @@ -52,11 +52,12 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map) return err; } if ((err = mp_init(&mu)) != CRYPT_OK) { + mp_montgomery_free(mp); return err; } if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) { - mp_montgomery_free(mp); mp_clear(mu); + mp_montgomery_free(mp); return err; } @@ -67,8 +68,8 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map) for (j = 0; j < i; j++) { ltc_ecc_del_point(M[j]); } - mp_montgomery_free(mp); mp_clear(mu); + mp_montgomery_free(mp); return CRYPT_MEM; } } @@ -82,6 +83,7 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map) if ((err = mp_mulmod(G->y, mu, modulus, tG->y)) != CRYPT_OK) { goto done; } if ((err = mp_mulmod(G->z, mu, modulus, tG->z)) != CRYPT_OK) { goto done; } mp_clear(mu); + mu = NULL; /* calc the M tab */ /* M[0] == G */ @@ -146,6 +148,9 @@ int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map) err = CRYPT_OK; } done: + if (mu != NULL) { + mp_clear(mu); + } mp_montgomery_free(mp); ltc_ecc_del_point(tG); for (i = 0; i < 3; i++) { diff --git a/src/pk/ecc/ltc_ecc_points.c b/src/pk/ecc/ltc_ecc_points.c index 07d003b..fa92876 100644 --- a/src/pk/ecc/ltc_ecc_points.c +++ b/src/pk/ecc/ltc_ecc_points.c @@ -30,7 +30,7 @@ ecc_point *ltc_ecc_new_point(void) { ecc_point *p; - p = XMALLOC(sizeof(*p)); + p = XCALLOC(1, sizeof(*p)); if (p == NULL) { return NULL; } diff --git a/src/pk/ecc/ltc_ecc_projective_add_point.c b/src/pk/ecc/ltc_ecc_projective_add_point.c index 1cf4880..d2a5476 100644 --- a/src/pk/ecc/ltc_ecc_projective_add_point.c +++ b/src/pk/ecc/ltc_ecc_projective_add_point.c @@ -35,7 +35,7 @@ int ltc_ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *mp) { void *t1, *t2, *x, *y, *z; - int err; + int err; LTC_ARGCHK(P != NULL); LTC_ARGCHK(Q != NULL); @@ -183,7 +183,6 @@ int ltc_ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, void if ((err = mp_copy(z, R->z)) != CRYPT_OK) { goto done; } err = CRYPT_OK; - goto done; done: mp_clear_multi(t1, t2, x, y, z, NULL); return err; diff --git a/src/pk/ecc/ltc_ecc_projective_dbl_point.c b/src/pk/ecc/ltc_ecc_projective_dbl_point.c index 1f4d348..d4577ea 100644 --- a/src/pk/ecc/ltc_ecc_projective_dbl_point.c +++ b/src/pk/ecc/ltc_ecc_projective_dbl_point.c @@ -34,7 +34,7 @@ int ltc_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *modulus, void *mp) { void *t1, *t2; - int err; + int err; LTC_ARGCHK(P != NULL); LTC_ARGCHK(R != NULL); @@ -46,9 +46,9 @@ int ltc_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *modulus, void } if (P != R) { - if ((err = mp_copy(P->x, R->x)) != CRYPT_OK) { goto done; } - if ((err = mp_copy(P->y, R->y)) != CRYPT_OK) { goto done; } - if ((err = mp_copy(P->z, R->z)) != CRYPT_OK) { goto done; } + if ((err = mp_copy(P->x, R->x)) != CRYPT_OK) { goto done; } + if ((err = mp_copy(P->y, R->y)) != CRYPT_OK) { goto done; } + if ((err = mp_copy(P->z, R->z)) != CRYPT_OK) { goto done; } } /* t1 = Z * Z */ @@ -136,7 +136,6 @@ int ltc_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *modulus, void } err = CRYPT_OK; - goto done; done: mp_clear_multi(t1, t2, NULL); return err; diff --git a/src/pk/pkcs1/pkcs_1_pss_decode.c b/src/pk/pkcs1/pkcs_1_pss_decode.c index 34ccc11..49dcc7e 100644 --- a/src/pk/pkcs1/pkcs_1_pss_decode.c +++ b/src/pk/pkcs1/pkcs_1_pss_decode.c @@ -82,7 +82,7 @@ int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, /* ensure the 0xBC byte */ if (sig[siglen-1] != 0xBC) { - err = CRYPT_OK; + err = CRYPT_INVALID_PACKET; goto LBL_ERR; } @@ -97,7 +97,7 @@ int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, /* check the MSB */ if ((sig[0] & ~(0xFF >> ((modulus_len<<3) - (modulus_bitlen-1)))) != 0) { - err = CRYPT_OK; + err = CRYPT_INVALID_PACKET; goto LBL_ERR; } @@ -119,14 +119,14 @@ int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen, /* check for zeroes and 0x01 */ for (x = 0; x < modulus_len - saltlen - hLen - 2; x++) { if (DB[x] != 0x00) { - err = CRYPT_OK; + err = CRYPT_INVALID_PACKET; goto LBL_ERR; } } /* check for the 0x01 */ if (DB[x++] != 0x01) { - err = CRYPT_OK; + err = CRYPT_INVALID_PACKET; goto LBL_ERR; } diff --git a/src/pk/pkcs1/pkcs_1_v1_5_decode.c b/src/pk/pkcs1/pkcs_1_v1_5_decode.c index f8bd629..5d2a2f4 100644 --- a/src/pk/pkcs1/pkcs_1_v1_5_decode.c +++ b/src/pk/pkcs1/pkcs_1_v1_5_decode.c @@ -10,23 +10,24 @@ */ #include "tomcrypt.h" -/*! \file pkcs_1_v1_5_decode.c +/** @file pkcs_1_v1_5_decode.c * * PKCS #1 v1.5 Padding. (Andreas Lange) */ #ifdef PKCS_1 -/*! \brief PKCS #1 v1.5 decode. +/** @brief PKCS #1 v1.5 decode. * - * \param msg The encoded data to decode - * \param msglen The length of the encoded data (octets) - * \param block_type Block type to use in padding (\sa ltc_pkcs_1_v1_5_blocks) - * \param modulus_bitlen The bit length of the RSA modulus - * \param out [out] Destination of decoding - * \param outlen [in/out] The max size and resulting size of the decoding + * @param msg The encoded data to decode + * @param msglen The length of the encoded data (octets) + * @param block_type Block type to use in padding (\sa ltc_pkcs_1_v1_5_blocks) + * @param modulus_bitlen The bit length of the RSA modulus + * @param out [out] Destination of decoding + * @param outlen [in/out] The max size and resulting size of the decoding + * @param is_valid [out] Boolean whether the padding was valid * - * \return CRYPT_OK if successful (even if invalid) + * @return CRYPT_OK if successful (even if invalid) */ int pkcs_1_v1_5_decode(const unsigned char *msg, unsigned long msglen, diff --git a/src/pk/rsa/rsa_exptmod.c b/src/pk/rsa/rsa_exptmod.c index e751365..b4b1b3f 100644 --- a/src/pk/rsa/rsa_exptmod.c +++ b/src/pk/rsa/rsa_exptmod.c @@ -57,7 +57,7 @@ int rsa_exptmod(const unsigned char *in, unsigned long inlen, /* sanity check on the input */ if (mp_cmp(key->N, tmp) == LTC_MP_LT) { err = CRYPT_PK_INVALID_SIZE; - goto done; + goto error; } /* are we using the private exponent and is the key optimized? */ @@ -85,13 +85,13 @@ int rsa_exptmod(const unsigned char *in, unsigned long inlen, if (x > *outlen) { *outlen = x; err = CRYPT_BUFFER_OVERFLOW; - goto done; + goto error; } /* this should never happen ... */ if (mp_unsigned_bin_size(tmp) > mp_unsigned_bin_size(key->N)) { err = CRYPT_ERROR; - goto done; + goto error; } *outlen = x; @@ -101,9 +101,7 @@ int rsa_exptmod(const unsigned char *in, unsigned long inlen, /* clean up and return */ err = CRYPT_OK; - goto done; error: -done: mp_clear_multi(tmp, tmpa, tmpb, NULL); return err; } diff --git a/src/pk/rsa/rsa_free.c b/src/pk/rsa/rsa_free.c index b477fb9..3d0baf6 100644 --- a/src/pk/rsa/rsa_free.c +++ b/src/pk/rsa/rsa_free.c @@ -24,8 +24,7 @@ void rsa_free(rsa_key *key) { LTC_ARGCHKVD(key != NULL); - mp_clear_multi( key->e, key->d, key->N, key->dQ, key->dP, - key->qP, key->p, key->q, NULL); + mp_clear_multi(key->e, key->d, key->N, key->dQ, key->dP, key->qP, key->p, key->q, NULL); } #endif diff --git a/src/pk/rsa/rsa_import.c b/src/pk/rsa/rsa_import.c index 80df512..4a9f36c 100644 --- a/src/pk/rsa/rsa_import.c +++ b/src/pk/rsa/rsa_import.c @@ -33,8 +33,8 @@ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) ltc_asn1_list ssl_pubkey_hashoid[2]; ltc_asn1_list ssl_pubkey[2]; - LTC_ARGCHK(in != NULL); - LTC_ARGCHK(key != NULL); + LTC_ARGCHK(in != NULL); + LTC_ARGCHK(key != NULL); LTC_ARGCHK(ltc_mp.name != NULL); /* init key */ @@ -67,7 +67,7 @@ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) for (t = y = z = x = 0; x < ssl_pubkey[1].size; x++) { y = (y << 1) | tmpbuf[x]; if (++z == 8) { - tmpbuf[t++] = y; + tmpbuf[t++] = (unsigned char)y; y = 0; z = 0; } @@ -131,8 +131,7 @@ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) } return CRYPT_OK; LBL_ERR: - mp_clear_multi(key->d, key->e, key->N, key->dQ, key->dP, - key->qP, key->p, key->q, NULL); + mp_clear_multi(key->d, key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, NULL); return err; } diff --git a/src/pk/rsa/rsa_make_key.c b/src/pk/rsa/rsa_make_key.c index 879b34c..8caf83c 100644 --- a/src/pk/rsa/rsa_make_key.c +++ b/src/pk/rsa/rsa_make_key.c @@ -32,7 +32,7 @@ int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key) int err; LTC_ARGCHK(ltc_mp.name != NULL); - LTC_ARGCHK(key != NULL); + LTC_ARGCHK(key != NULL); if ((size < (MIN_RSA_SIZE/8)) || (size > (MAX_RSA_SIZE/8))) { return CRYPT_INVALID_KEYSIZE; @@ -51,60 +51,57 @@ int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key) } /* make primes p and q (optimization provided by Wayne Scott) */ - if ((err = mp_set_int(tmp3, e)) != CRYPT_OK) { goto error; } /* tmp3 = e */ + if ((err = mp_set_int(tmp3, e)) != CRYPT_OK) { goto errkey; } /* tmp3 = e */ /* make prime "p" */ do { - if ((err = rand_prime( p, size/2, prng, wprng)) != CRYPT_OK) { goto done; } - if ((err = mp_sub_d( p, 1, tmp1)) != CRYPT_OK) { goto error; } /* tmp1 = p-1 */ - if ((err = mp_gcd( tmp1, tmp3, tmp2)) != CRYPT_OK) { goto error; } /* tmp2 = gcd(p-1, e) */ - } while (mp_cmp_d( tmp2, 1) != 0); /* while e divides p-1 */ + if ((err = rand_prime( p, size/2, prng, wprng)) != CRYPT_OK) { goto errkey; } + if ((err = mp_sub_d( p, 1, tmp1)) != CRYPT_OK) { goto errkey; } /* tmp1 = p-1 */ + if ((err = mp_gcd( tmp1, tmp3, tmp2)) != CRYPT_OK) { goto errkey; } /* tmp2 = gcd(p-1, e) */ + } while (mp_cmp_d( tmp2, 1) != 0); /* while e divides p-1 */ /* make prime "q" */ do { - if ((err = rand_prime( q, size/2, prng, wprng)) != CRYPT_OK) { goto done; } - if ((err = mp_sub_d( q, 1, tmp1)) != CRYPT_OK) { goto error; } /* tmp1 = q-1 */ - if ((err = mp_gcd( tmp1, tmp3, tmp2)) != CRYPT_OK) { goto error; } /* tmp2 = gcd(q-1, e) */ - } while (mp_cmp_d( tmp2, 1) != 0); /* while e divides q-1 */ + if ((err = rand_prime( q, size/2, prng, wprng)) != CRYPT_OK) { goto errkey; } + if ((err = mp_sub_d( q, 1, tmp1)) != CRYPT_OK) { goto errkey; } /* tmp1 = q-1 */ + if ((err = mp_gcd( tmp1, tmp3, tmp2)) != CRYPT_OK) { goto errkey; } /* tmp2 = gcd(q-1, e) */ + } while (mp_cmp_d( tmp2, 1) != 0); /* while e divides q-1 */ /* tmp1 = lcm(p-1, q-1) */ - if ((err = mp_sub_d( p, 1, tmp2)) != CRYPT_OK) { goto error; } /* tmp2 = p-1 */ - /* tmp1 = q-1 (previous do/while loop) */ - if ((err = mp_lcm( tmp1, tmp2, tmp1)) != CRYPT_OK) { goto error; } /* tmp1 = lcm(p-1, q-1) */ + if ((err = mp_sub_d( p, 1, tmp2)) != CRYPT_OK) { goto errkey; } /* tmp2 = p-1 */ + /* tmp1 = q-1 (previous do/while loop) */ + if ((err = mp_lcm( tmp1, tmp2, tmp1)) != CRYPT_OK) { goto errkey; } /* tmp1 = lcm(p-1, q-1) */ /* make key */ - if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, - &key->qP, &key->p, &key->q, NULL)) != CRYPT_OK) { - goto error; + if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL)) != CRYPT_OK) { + goto errkey; } - if ((err = mp_set_int( key->e, e)) != CRYPT_OK) { goto error2; } /* key->e = e */ - if ((err = mp_invmod( key->e, tmp1, key->d)) != CRYPT_OK) { goto error2; } /* key->d = 1/e mod lcm(p-1,q-1) */ - if ((err = mp_mul( p, q, key->N)) != CRYPT_OK) { goto error2; } /* key->N = pq */ + if ((err = mp_set_int( key->e, e)) != CRYPT_OK) { goto errkey; } /* key->e = e */ + if ((err = mp_invmod( key->e, tmp1, key->d)) != CRYPT_OK) { goto errkey; } /* key->d = 1/e mod lcm(p-1,q-1) */ + if ((err = mp_mul( p, q, key->N)) != CRYPT_OK) { goto errkey; } /* key->N = pq */ /* optimize for CRT now */ /* find d mod q-1 and d mod p-1 */ - if ((err = mp_sub_d( p, 1, tmp1)) != CRYPT_OK) { goto error2; } /* tmp1 = q-1 */ - if ((err = mp_sub_d( q, 1, tmp2)) != CRYPT_OK) { goto error2; } /* tmp2 = p-1 */ - if ((err = mp_mod( key->d, tmp1, key->dP)) != CRYPT_OK) { goto error2; } /* dP = d mod p-1 */ - if ((err = mp_mod( key->d, tmp2, key->dQ)) != CRYPT_OK) { goto error2; } /* dQ = d mod q-1 */ - if ((err = mp_invmod( q, p, key->qP)) != CRYPT_OK) { goto error2; } /* qP = 1/q mod p */ + if ((err = mp_sub_d( p, 1, tmp1)) != CRYPT_OK) { goto errkey; } /* tmp1 = q-1 */ + if ((err = mp_sub_d( q, 1, tmp2)) != CRYPT_OK) { goto errkey; } /* tmp2 = p-1 */ + if ((err = mp_mod( key->d, tmp1, key->dP)) != CRYPT_OK) { goto errkey; } /* dP = d mod p-1 */ + if ((err = mp_mod( key->d, tmp2, key->dQ)) != CRYPT_OK) { goto errkey; } /* dQ = d mod q-1 */ + if ((err = mp_invmod( q, p, key->qP)) != CRYPT_OK) { goto errkey; } /* qP = 1/q mod p */ - if ((err = mp_copy( p, key->p)) != CRYPT_OK) { goto error2; } - if ((err = mp_copy( q, key->q)) != CRYPT_OK) { goto error2; } + if ((err = mp_copy( p, key->p)) != CRYPT_OK) { goto errkey; } + if ((err = mp_copy( q, key->q)) != CRYPT_OK) { goto errkey; } /* set key type (in this case it's CRT optimized) */ key->type = PK_PRIVATE; /* return ok and free temps */ err = CRYPT_OK; - goto done; -error2: - mp_clear_multi( key->d, key->e, key->N, key->dQ, key->dP, - key->qP, key->p, key->q, NULL); -error: -done: - mp_clear_multi( tmp3, tmp2, tmp1, p, q, NULL); + goto cleanup; +errkey: + mp_clear_multi(key->d, key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, NULL); +cleanup: + mp_clear_multi(tmp3, tmp2, tmp1, p, q, NULL); return err; } diff --git a/src/pk/rsa/rsa_verify_hash.c b/src/pk/rsa/rsa_verify_hash.c index 115bf4e..aec7135 100644 --- a/src/pk/rsa/rsa_verify_hash.c +++ b/src/pk/rsa/rsa_verify_hash.c @@ -86,6 +86,7 @@ int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen, /* make sure the output is the right size */ if (x != siglen) { + XFREE(tmpbuf); return CRYPT_INVALID_PACKET; } diff --git a/src/prngs/fortuna.c b/src/prngs/fortuna.c index 6aaa0d9..61365b4 100644 --- a/src/prngs/fortuna.c +++ b/src/prngs/fortuna.c @@ -143,8 +143,8 @@ int fortuna_start(prng_state *prng) return err; } } - prng->fortuna.pool_idx = prng->fortuna.pool0_len = prng->fortuna.reset_cnt = - prng->fortuna.wd = 0; + prng->fortuna.pool_idx = prng->fortuna.pool0_len = prng->fortuna.wd = 0; + prng->fortuna.reset_cnt = 0; /* reset bufs */ zeromem(prng->fortuna.K, 32); @@ -186,7 +186,7 @@ int fortuna_add_entropy(const unsigned char *in, unsigned long inlen, prng_state /* add s || length(in) || in to pool[pool_idx] */ tmp[0] = 0; - tmp[1] = inlen; + tmp[1] = (unsigned char)inlen; if ((err = sha256_process(&prng->fortuna.pool[prng->fortuna.pool_idx], tmp, 2)) != CRYPT_OK) { LTC_MUTEX_UNLOCK(&prng->fortuna.prng_lock); return err; diff --git a/src/prngs/rng_get_bytes.c b/src/prngs/rng_get_bytes.c index 5bf1d61..9041e35 100644 --- a/src/prngs/rng_get_bytes.c +++ b/src/prngs/rng_get_bytes.c @@ -50,7 +50,7 @@ static unsigned long rng_nix(unsigned char *buf, unsigned long len, #endif /* DEVRANDOM */ /* on ANSI C platforms with 100 < CLOCKS_PER_SEC < 10000 */ -#if defined(CLOCKS_PER_SEC) +#if defined(CLOCKS_PER_SEC) && !defined(WINCE) #define ANSI_RNG @@ -87,8 +87,12 @@ static unsigned long rng_ansic(unsigned char *buf, unsigned long len, #endif /* Try the Microsoft CSP */ -#ifdef WIN32 +#if defined(WIN32) || defined(WINCE) #define _WIN32_WINNT 0x0400 +#ifdef WINCE + #define UNDER_CE + #define ARM +#endif #include #include diff --git a/testprof/der_tests.c b/testprof/der_tests.c index 315ba98..0022902 100644 --- a/testprof/der_tests.c +++ b/testprof/der_tests.c @@ -532,6 +532,14 @@ int der_tests(void) static const unsigned char rsa_time1_der[] = { 0x17, 0x11, 0x39, 0x31, 0x30, 0x35, 0x30, 0x36, 0x31, 0x36, 0x34, 0x35, 0x34, 0x30, 0x2D, 0x30, 0x37, 0x30, 0x30 }; static const unsigned char rsa_time2_der[] = { 0x17, 0x0d, 0x39, 0x31, 0x30, 0x35, 0x30, 0x36, 0x32, 0x33, 0x34, 0x35, 0x34, 0x30, 0x5a }; + static const wchar_t utf8_1[] = { 0x0041, 0x2262, 0x0391, 0x002E }; + static const unsigned char utf8_1_der[] = { 0x0C, 0x07, 0x41, 0xE2, 0x89, 0xA2, 0xCE, 0x91, 0x2E }; + static const wchar_t utf8_2[] = { 0xD55C, 0xAD6D, 0xC5B4 }; + static const unsigned char utf8_2_der[] = { 0x0C, 0x09, 0xED, 0x95, 0x9C, 0xEA, 0xB5, 0xAD, 0xEC, 0x96, 0xB4 }; + + unsigned char utf8_buf[32]; + wchar_t utf8_out[32]; + DO(mp_init_multi(&a, &b, &c, &d, &e, &f, &g, NULL)); for (zz = 0; zz < 16; zz++) { #ifdef USE_TFM @@ -797,6 +805,42 @@ tmp_time.off_hh); return 1; } + /* UTF 8 */ + /* encode it */ + x = sizeof(utf8_buf); + DO(der_encode_utf8_string(utf8_1, sizeof(utf8_1) / sizeof(utf8_1[0]), utf8_buf, &x)); + if (x != sizeof(utf8_1_der) || memcmp(utf8_buf, utf8_1_der, x)) { + fprintf(stderr, "DER UTF8_1 encoded to %lu bytes\n", x); + for (y = 0; y < x; y++) fprintf(stderr, "%02x ", (unsigned)utf8_buf[y]); fprintf(stderr, "\n"); + return 1; + } + /* decode it */ + y = sizeof(utf8_out) / sizeof(utf8_out[0]); + DO(der_decode_utf8_string(utf8_buf, x, utf8_out, &y)); + if (y != (sizeof(utf8_1) / sizeof(utf8_1[0])) || memcmp(utf8_1, utf8_out, y * sizeof(wchar_t))) { + fprintf(stderr, "DER UTF8_1 decoded to %lu wchar_t\n", y); + for (x = 0; x < y; x++) fprintf(stderr, "%04lx ", (unsigned long)utf8_out[x]); fprintf(stderr, "\n"); + return 1; + } + + /* encode it */ + x = sizeof(utf8_buf); + DO(der_encode_utf8_string(utf8_2, sizeof(utf8_2) / sizeof(utf8_2[0]), utf8_buf, &x)); + if (x != sizeof(utf8_2_der) || memcmp(utf8_buf, utf8_2_der, x)) { + fprintf(stderr, "DER UTF8_2 encoded to %lu bytes\n", x); + for (y = 0; y < x; y++) fprintf(stderr, "%02x ", (unsigned)utf8_buf[y]); fprintf(stderr, "\n"); + return 1; + } + /* decode it */ + y = sizeof(utf8_out) / sizeof(utf8_out[0]); + DO(der_decode_utf8_string(utf8_buf, x, utf8_out, &y)); + if (y != (sizeof(utf8_2) / sizeof(utf8_2[0])) || memcmp(utf8_2, utf8_out, y * sizeof(wchar_t))) { + fprintf(stderr, "DER UTF8_2 decoded to %lu wchar_t\n", y); + for (x = 0; x < y; x++) fprintf(stderr, "%04lx ", (unsigned long)utf8_out[x]); fprintf(stderr, "\n"); + return 1; + } + + der_set_test(); der_flexi_test(); return der_choice_test(); diff --git a/testprof/ecc_test.c b/testprof/ecc_test.c index 579cf6e..58d7c07 100644 --- a/testprof/ecc_test.c +++ b/testprof/ecc_test.c @@ -29,6 +29,82 @@ static int sizes[] = { #endif }; +#ifdef LTC_ECC_SHAMIR +int ecc_test_shamir(void) +{ + void *modulus, *mp, *kA, *kB, *rA, *rB; + ecc_point *G, *A, *B, *C1, *C2; + int x, y, z; + unsigned char buf[ECC_BUF_SIZE]; + + DO(mp_init_multi(&kA, &kB, &rA, &rB, &modulus, NULL)); + LTC_ARGCHK((G = ltc_ecc_new_point()) != NULL); + LTC_ARGCHK((A = ltc_ecc_new_point()) != NULL); + LTC_ARGCHK((B = ltc_ecc_new_point()) != NULL); + LTC_ARGCHK((C1 = ltc_ecc_new_point()) != NULL); + LTC_ARGCHK((C2 = ltc_ecc_new_point()) != NULL); + + for (x = 0; x < (int)(sizeof(sizes)/sizeof(sizes[0])); x++) { + /* get the base point */ + for (z = 0; ltc_ecc_sets[z].name; z++) { + if (sizes[z] < ltc_ecc_sets[z].size) break; + } + LTC_ARGCHK(ltc_ecc_sets[z].name != NULL); + + /* load it */ + DO(mp_read_radix(G->x, ltc_ecc_sets[z].Gx, 16)); + DO(mp_read_radix(G->y, ltc_ecc_sets[z].Gy, 16)); + DO(mp_set(G->z, 1)); + DO(mp_read_radix(modulus, ltc_ecc_sets[z].prime, 16)); + DO(mp_montgomery_setup(modulus, &mp)); + + /* do 100 random tests */ + for (y = 0; y < 100; y++) { + /* pick a random r1, r2 */ + LTC_ARGCHK(yarrow_read(buf, sizes[x], &yarrow_prng) == sizes[x]); + DO(mp_read_unsigned_bin(rA, buf, sizes[x])); + LTC_ARGCHK(yarrow_read(buf, sizes[x], &yarrow_prng) == sizes[x]); + DO(mp_read_unsigned_bin(rB, buf, sizes[x])); + + /* compute rA * G = A */ + DO(ltc_mp.ecc_ptmul(rA, G, A, modulus, 1)); + + /* compute rB * G = B */ + DO(ltc_mp.ecc_ptmul(rB, G, B, modulus, 1)); + + /* pick a random kA, kB */ + LTC_ARGCHK(yarrow_read(buf, sizes[x], &yarrow_prng) == sizes[x]); + DO(mp_read_unsigned_bin(kA, buf, sizes[x])); + LTC_ARGCHK(yarrow_read(buf, sizes[x], &yarrow_prng) == sizes[x]); + DO(mp_read_unsigned_bin(kB, buf, sizes[x])); + + /* now, compute kA*A + kB*B = C1 using the older method */ + DO(ltc_mp.ecc_ptmul(kA, A, C1, modulus, 0)); + DO(ltc_mp.ecc_ptmul(kB, B, C2, modulus, 0)); + DO(ltc_mp.ecc_ptadd(C1, C2, C1, modulus, mp)); + DO(ltc_mp.ecc_map(C1, modulus, mp)); + + /* now compute using mul2add */ + DO(ltc_mp.ecc_mul2add(A, kA, B, kB, C2, modulus)); + + /* is they the sames? */ + if ((mp_cmp(C1->x, C2->x) != LTC_MP_EQ) || (mp_cmp(C1->y, C2->y) != LTC_MP_EQ) || (mp_cmp(C1->z, C2->z) != LTC_MP_EQ)) { + fprintf(stderr, "ECC failed shamir test: size=%d, testno=%d\n", sizes[x], y); + return 1; + } + } + mp_montgomery_free(mp); + } + ltc_ecc_del_point(C2); + ltc_ecc_del_point(C1); + ltc_ecc_del_point(B); + ltc_ecc_del_point(A); + ltc_ecc_del_point(G); + mp_clear_multi(kA, kB, rA, rB, modulus, NULL); + return 0; +} +#endif + int ecc_tests (void) { unsigned char buf[4][4096]; @@ -154,7 +230,11 @@ int ecc_tests (void) ecc_free (&pubKey); ecc_free (&privKey); } +#ifdef LTC_ECC_SHAMIR + return ecc_test_shamir(); +#else return 0; +#endif } #else diff --git a/testprof/pkcs_1_test.c b/testprof/pkcs_1_test.c index aabf30b..420fae0 100644 --- a/testprof/pkcs_1_test.c +++ b/testprof/pkcs_1_test.c @@ -5,7 +5,7 @@ int pkcs_1_test(void) { unsigned char buf[3][128]; - int res1, res2, res3, prng_idx, hash_idx; + int res1, res2, res3, prng_idx, hash_idx, err; unsigned long x, y, l1, l2, l3, i1, i2, lparamlen, saltlen, modlen; static const unsigned char lparam[] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 }; @@ -18,6 +18,7 @@ int pkcs_1_test(void) return 1; } + srand(time(NULL)); /* do many tests */ for (x = 0; x < 100; x++) { zeromem(buf, sizeof(buf)); @@ -26,9 +27,6 @@ int pkcs_1_test(void) l3 = (rand() & 31) + 8; for (y = 0; y < l3; y++) buf[0][y] = rand() & 255; - /* random modulus len (v1.5 must be multiple of 8 though arbitrary sizes seem to work) */ - modlen = 800 + 8 * (abs(rand()) % 28); - /* pick a random lparam len [0..16] */ lparamlen = abs(rand()) % 17; @@ -69,9 +67,8 @@ int pkcs_1_test(void) DO(pkcs_1_pss_decode(buf[0], l3, buf[1], l1, saltlen, hash_idx, modlen, &res2)); buf[0][i1] ^= 1; - buf[1][i2 = abs(rand()) % l1] ^= 1; - DO(pkcs_1_pss_decode(buf[0], l3, buf[1], l1, saltlen, hash_idx, modlen, &res3)); - + buf[1][i2 = abs(rand()) % (l1 - 1)] ^= 1; + pkcs_1_pss_decode(buf[0], l3, buf[1], l1, saltlen, hash_idx, modlen, &res3); if (!(res1 == 1 && res2 == 0 && res3 == 0)) { fprintf(stderr, "PSS failed: %d, %d, %d, %lu, %lu\n", res1, res2, res3, l3, saltlen); return 1; diff --git a/testprof/rsa_test.c b/testprof/rsa_test.c index aa3f0c3..a47ec7d 100644 --- a/testprof/rsa_test.c +++ b/testprof/rsa_test.c @@ -87,7 +87,7 @@ static int rsa_compat_test(void) len = sizeof(buf); DO(rsa_export(buf, &len, PK_PRIVATE, &key)); if (len != sizeof(openssl_private_rsa) || memcmp(buf, openssl_private_rsa, len)) { - fprintf(stderr, "RSA private export failed to match OpenSSL output, %lu, %lu\n", len, sizeof(openssl_private_rsa)); + fprintf(stderr, "RSA private export failed to match OpenSSL output, %lu, %lu\n", len, (unsigned long)sizeof(openssl_private_rsa)); return 1; } @@ -126,7 +126,7 @@ int rsa_test(void) { unsigned char in[1024], out[1024], tmp[1024]; rsa_key key, privKey, pubKey; - int hash_idx, prng_idx, stat, stat2, err; + int hash_idx, prng_idx, stat, stat2; unsigned long rsa_msgsize, len, len2, cnt; static unsigned char lparam[] = { 0x01, 0x02, 0x03, 0x04 }; diff --git a/testprof/x86_prof.c b/testprof/x86_prof.c index 30c9226..b9e9509 100644 --- a/testprof/x86_prof.c +++ b/testprof/x86_prof.c @@ -765,9 +765,8 @@ void time_dsa(void) { dsa_key key; ulong64 t1, t2; - unsigned char buf[2][2048]; - unsigned long x, y, z, zzz; - int err, zz, stat, i; + unsigned long x, y; + int err; static const struct { int group, modulus; } groups[] = { @@ -799,7 +798,7 @@ static const struct { } } t2 >>= 2; - fprintf(stderr, "DSA-(%lu, %lu) make_key took %15llu cycles\n", groups[x].group*8, groups[x].modulus*8, t2); + fprintf(stderr, "DSA-(%lu, %lu) make_key took %15llu cycles\n", (unsigned long)groups[x].group*8, (unsigned long)groups[x].modulus*8, t2); } } #endif diff --git a/updatemakes.sh b/updatemakes.sh index a6e1906..9b6cbde 100644 --- a/updatemakes.sh +++ b/updatemakes.sh @@ -11,6 +11,9 @@ mv -f tmp.delme makefile.icc perl filter.pl makefile.shared tmplist mv -f tmp.delme makefile.shared +perl filter.pl makefile.unix tmplist +mv -f tmp.delme makefile.unix + perl filter.pl makefile.msvc tmplist sed -e 's/\.o /.obj /g' < tmp.delme > makefile.msvc