Cryptographic functions

Often used cryptographic functions. More...

Modules

 Hashing functions
 

Common cryptographic hash functions.


 Encryption functions
 

Common ciphers.


 Public key cryptography
 

Public key cryptography.


 Natural numbers module
 

Natural numbers processing.



Detailed Description

Often used cryptographic functions.

This library contains implementations of often used cryptographic functions. These include various hash functions, encryption and decryption functions.

The library is reasonably portable. It is intended for 32-bit targets (or possibly 16-bit ones that have some HW support for 32-bit operations). Thus, the library assumes that a short is 16 bits wide, an int is a 32-bit type while long long is 64 bits. This is the default for most 32-bit processors for which gcc compiles and for 16-bit targets you can tell gcc to treat int as a 32-bit quantity.
There are no assumptions on the endianness of the processor or other architectural features. Very few gcc specific features are used, thus it should not be an issue to port this library to any other 32-bit architecture and/or a different C compiler. To facilitate that, the library is entirely self-contained, it does not call any external functions, not even memcpy() or memset(). The only ARM specific part is a bunch of assembly functions in the natural numbers submodule, involved mostly in modular exponentiation, but those functions are also provided in pure C form.

IMPORTANT:
The cryptographic library is re-entrant but isn't strictly thread safe.
As long as all threads use different state descriptors (i.e. different blocks of memory), they can call the cryptographic functions simultaneously (that is, the library itself does not use any static data). However, if two threads share a single state descriptor then you must guarantee that only one of them calls a function operating on that state at any given time. That is, if you have two separate data streams, each processed by a separate thread and each thread has its own hash state, both threads can call the hash functions (passing their own hash state descriptors) without any mutual exclusivity protection. However, if there are two threads working on a single hash state (i.e. they calculate a single hash of their collective data), then you must guarantee that if one thread called a hash function, passing the shared state to it, the other thread will not call a hash function with the same shared state until the first invocation returns.
In other words, the functions are re-entrant but the state descriptors are not. If you share descriptors between threads, you must guarantee mutual exlusivity protection (just like for any other shared data item).
The implementation of such protection is entirely your responsibility. If you call into the library simultaneously from different threads, using the same state descriptor object, then if you are lucky you get messed up results, if you are unlucky, you will end up with misterious memory corruptions and possibly a crash.
Note that for DES and AES the key schedule data, as far as encryption and decryption is concerned, is constant, so you can run two instances of AES in parallel using the same key schedule. In the case of ARC4, however, it is a state, which changes with every invocation of the function, therefore you can not use the same key descriptor for two parallel instances. I tried to be consistent in the wording and if you see that a function has a state parameter, you know that that parameter can not be shared by two simultaneous instances. Parameters that are invariant are called by other names and they are declared const in the function prototype.
Conformance:
The implementations are based on the following specifications:
  • RFC-1321 for MD5
  • RFC-3174 for SHA-1
  • RFC-2104 for HMAC
  • NIST-SP-800-67 (includes FIPS-46-3) for DES and TDEA (a.k.a. triple-DES)
  • NIST-SP-800-38A for the block cipher modes
  • FIPS-197 for AES
  • PKCS#1-1.5 for RSA (and ASN.1 for the key conversion tool)
  • There is no formal spec for ARC4, but it's described at many places, including Applied Cryptography (a must!) and various IETS documents, most prominently the ARCFOUR internet draft from 1999.
General advice:
I am not a cryptography expert. Chances are, neither are you. Do not try to be clever. Do not try to invent cunning tricks to hide your data even better. More often than not the result is less secure than it was before you added your clever twist. Follow the basic rules that those who are experts of the field repeat over and over:
  • Security by obscurity does not work. If you try to protect data by using a cryptographically unsafe function that you keep secret and hope that your adversaries can't figure it out, you might as well not bother at all. See the entertainment industry's futile attempt to encrypt DVDs (CSS). They had a much larger budget than you do, they worked on it a lot, figured that it was safe and they managed to keep it secret. Well, a Norwegian teenager broke that crown jewel of the copyright lobby, because he wanted to watch DVDs on his computer (which Hollywood did not consider to be an "endorsed player").
  • Using security but then exposing your keys is just straight dumb. Having your key stored in an external EEPROM is equivalent to writing them on the box with fluoro texter. If the device has to hold a key, store it in a secure location. The only place you can consider secure is inside the controller chip and only if you can guarantee that it is not possible to read from the chip or to execute malicious code on the chip. Anything external, anything that can be accessed by desoldering the chip and putting it into a debug environment - you might as well not waste your time with it because it will be broken. A notable exception from this rule is the public key for RSA. Using RSA you can establish a secure channel (to a secure server) using ephemeral keys - after all, that's what RSA is for.
  • Assume that your adversary has every bit of information about your system, including schematics, source code, deployment configuration etc. The only thing (s)he doesn't have is your key(s). If assuming the above makes your system vulnerable, then you are using the security by obscurity model, which is flawed.
  • Follow the standards. Don't tweak them. Innocent looking changes may result in dramatic loss of security.
  • Do not try to invent authentication and key establishment schemes. Even if you use a fairly safe cryptographic core function, a badly designed method around it can render it useless. The spectacular disaster called WEP for 802.11 is a prominent example of that.
  • Do not give away information. If in a multiple step security verification the first step fails, keep on going. Declare failure only at the end. That way on the one hand you wasted the resources of your adversary and on the other you did not tell him/her what step failed. Do not specify the reason of failure, only the fact that the process was not successful. Note that 'keep on going' means to actually perform all calculations even if you know that the results will be thrown away - otherwise your adversary can monitor your power consumption, for example, and realise that you do not really do anything, even if you pretend to be busy calculating something.
Note:
Cryptographic functions are big, need a lot of memory and CPU cycles. Most state descriptors are large (several tens or even hundreds of bytes), and the functions require up to several hundred bytes of stack space. You need reasonably beefy chips to use the cryptographic library.
Generated on Fri Aug 13 12:02:25 2010 by  doxygen 1.6.3