diff options
Diffstat (limited to 'doc/manual')
-rw-r--r-- | doc/manual/aead.rst | 98 | ||||
-rw-r--r-- | doc/manual/contents.rst | 3 | ||||
-rw-r--r-- | doc/manual/hash.rst | 121 | ||||
-rw-r--r-- | doc/manual/lowlevel.rst | 169 | ||||
-rw-r--r-- | doc/manual/pubkey.rst | 190 | ||||
-rw-r--r-- | doc/manual/symmetric_crypto.rst | 570 |
6 files changed, 879 insertions, 272 deletions
diff --git a/doc/manual/aead.rst b/doc/manual/aead.rst deleted file mode 100644 index d216026bb..000000000 --- a/doc/manual/aead.rst +++ /dev/null @@ -1,98 +0,0 @@ -AEAD Modes -======================================== - -.. versionadded:: 1.11.3 - -AEAD (Authenticated Encryption with Associated Data) modes provide message -encryption, message authentication, and the ability to authenticate additional -data that is not included in the ciphertext (such as a sequence number or -header). It is a subclass of :cpp:class:`Symmetric_Algorithm`. - -The AEAD interface can be used directly, or as part of the filter system by -using :cpp:class:`AEAD_Filter` (a subclass of :cpp:class:`Keyed_Filter` which -will be returned by :cpp:func:`get_cipher` if the named cipher is an AEAD mode). - -AEAD modes currently available include GCM, OCB, EAX, SIV and CCM. All -support a 128-bit block cipher such as AES. EAX and SIV also support -256 and 512 bit block ciphers. - -.. cpp:class:: AEAD_Mode - - .. cpp:function:: void set_key(const SymmetricKey& key) - - Set the key - - .. cpp:function:: Key_Length_Specification key_spec() const - - Return the key length specification - - .. cpp:function:: void set_associated_data(const byte ad[], size_t ad_len) - - Set any associated data for this message. For maximum portability between - different modes, this must be called after :cpp:func:`set_key` and before - :cpp:func:`start`. - - If the associated data does not change, it is not necessary to call this - function more than once, even across multiple calls to :cpp:func:`start` - and :cpp:func:`finish`. - - .. cpp:function:: void start(const byte nonce[], size_t nonce_len) - - Start processing a message, using *nonce* as the unique per-message - value. - - .. cpp:function:: void update(secure_vector<byte>& buffer, size_t offset = 0) - - Continue processing a message. The *buffer* is an in/out parameter and - may be resized. In particular, some modes require that all input be - consumed before any output is produced; with these modes, *buffer* will - be returned empty. - - On input, the buffer must be sized in blocks of size - :cpp:func:`update_granularity`. For instance if the update granularity - was 64, then *buffer* could be 64, 128, 192, ... bytes. - - The first *offset* bytes of *buffer* will be ignored (this allows in - place processing of a buffer that contains an initial plaintext header) - - .. cpp:function:: void finish(secure_vector<byte>& buffer, size_t offset = 0) - - Complete processing a message with a final input of *buffer*, which is - treated the same as with :cpp:func:`update`. It must contain at least - :cpp:func:`final_minimum_size` bytes. - - Note that if you have the entire message in hand, calling finish without - ever calling update is both efficient and convenient. - - .. note:: - During decryption, finish will throw an instance of Integrity_Failure - if the MAC does not validate. If this occurs, all plaintext previously - output via calls to update must be destroyed and not used in any - way that an attacker could observe the effects of. - - One simply way to assure this could never happen is to never - call update, and instead always marshall the entire message - into a single buffer and call finish on it when decrypting. - - .. cpp:function:: size_t update_granularity() const - - The AEAD interface requires :cpp:func:`update` be called with blocks of - this size. This will be 1, if the mode can process any length inputs. - - .. cpp:function:: size_t final_minimum_size() const - - The AEAD interface requires :cpp:func:`finish` be called with at least - this many bytes (which may be zero, or greater than - :cpp:func:`update_granularity`) - - .. cpp:function:: bool valid_nonce_length(size_t nonce_len) const - - Returns true if *nonce_len* is a valid nonce length for this scheme. For - EAX and GCM, any length nonces are allowed. OCB allows any value between - 8 and 15 bytes. - - .. cpp:function:: size_t default_nonce_length() const - - Returns a reasonable length for the nonce, typically either 96 - bits, or the only supported length for modes which don't - support 96 bit nonces. diff --git a/doc/manual/contents.rst b/doc/manual/contents.rst index f69b7d77e..e2d88a35c 100644 --- a/doc/manual/contents.rst +++ b/doc/manual/contents.rst @@ -11,13 +11,14 @@ Contents secmem rng filters + hash + symmetric_crypto pubkey mceliece x509 ocsp tls credentials_manager - aead bigint lowlevel kdf diff --git a/doc/manual/hash.rst b/doc/manual/hash.rst new file mode 100644 index 000000000..12266207d --- /dev/null +++ b/doc/manual/hash.rst @@ -0,0 +1,121 @@ +Hash Functions and Checksums +============================= +Hash functions are one-way functions, which map data of arbitrary size +to a fixed output length. The class :cpp:class:`HashFunction` is derived from +the base class :cpp:class:`BufferedComputation` and defined in `botan/hash.h`. +A Botan :cpp:class:`BufferedComputation` is split into three stages: + +1. Instantiation. +2. Data processing. +3. Finalization. + +.. cpp:class:: BufferedComputation + + .. cpp:function:: size_t output_length() + + Return the size of the output of this function. + + .. cpp:function:: void update(const byte* input, size_t length) + + .. cpp:function:: void update(byte input) + + .. cpp:function:: void update(const std::string& input) + + Updates the computation with *input*. + + .. cpp:function:: void final(byte* out) + + .. cpp:function:: secure_vector<byte> final() + + Finalize the calculation and place the result into ``out``. + For the argument taking an array, exactly ``output_length`` bytes will + be written. After you call ``final``, the algorithm is reset to + its initial state, so it may be reused immediately. + + The second method of using final is to call it with no arguments at + all, as shown in the second prototype. It will return the result + value in a memory buffer. + + There is also a pair of functions called ``process``. They are a + combination of a single ``update``, and ``final``. Both versions + return the final value, rather than placing it an array. Calling + ``process`` with a single byte value isn't available, mostly because + it would rarely be useful. + +Botan implements the following hash algorithms: + +1. Checksums: + - Adler32 + - CRC24 + - CRC32 +#. Cryptographic hash functions: + - BLAKE2 + - GOST-34.11 + - Keccak-1600 + - MD4 + - MD5 + - RIPEMD-160 + - SHA-1 + - SHA-2 (SHA-224, SHA-256, SHA-384, SHA-512-256) + - SHA-3 + - SHAKE (SHAKE-128, SHAKE-256) + - Skein-512 + - Tiger + - Whirlpool + +.. note:: Checksums are not suitable for cryptographic use, but can be used for error checking purposes. + +CLI +--- +The Botan command line interface allows the user to compute hash digests of files or datastreams. ``botan hash --algo=SHA-256 --buf-size=4096 *files`` can be used to invoke a hash computation. + +CLI Example +^^^^^^^^^^^^^ +.. code-block:: sh + + $ echo -n randombit | botan hash --algo=SHA-3 + 783A78B369AA0DE71A6155180EA9D544E7A1834CC4951548C3CE7D5E012C8C6B7EAE1C27DBDFA4DA58EE7B79B5CF07E7E6691AE39BEC1A7DDC501249266BB050`` + +Code Example +------------ +Assume we want to calculate the SHA-1, Whirlpool and SHA-3 hash digests of the STDIN stream using the Botan library. + +.. code-block:: cpp + + #include <botan/hash.h> + #include <botan/hex.h> + #include <iostream> + int main () + { + std::unique_ptr<Botan::HashFunction> hash1(Botan::HashFunction::create("SHA-1")); + std::unique_ptr<Botan::HashFunction> hash2(Botan::HashFunction::create("Whirlpool")); + std::unique_ptr<Botan::HashFunction> hash3(Botan::HashFunction::create("SHA-3")); + std::vector<uint8_t> buf(2048); + + while(std::cin.good()) + { + //read STDIN to buffer + std::cin.read(reinterpret_cast<char*>(buf.data()), buf.size()); + size_t readcount = std::cin.gcount(); + //update hash computations with read data + hash1->update(buf.data(),readcount); + hash2->update(buf.data(),readcount); + hash3->update(buf.data(),readcount); + } + std::cout << "SHA-1: " << Botan::hex_encode(hash1->final()) << std::endl; + std::cout << "Whirlpool: " << Botan::hex_encode(hash2->final()) << std::endl; + std::cout << "SHA-3: " << Botan::hex_encode(hash3->final()) << std::endl; + return 0; + } + + +A Note on Checksums +-------------------- + +Checksums are very similar to hash functions, and in fact share the +same interface. But there are some significant differences, the major +ones being that the output size is very small (usually in the range of +2 to 4 bytes), and is not cryptographically secure. But for their +intended purpose (error checking), they perform very well. Some +examples of checksums included in Botan are the Adler32 and CRC32 +checksums.
\ No newline at end of file diff --git a/doc/manual/lowlevel.rst b/doc/manual/lowlevel.rst index ae7337c4e..5d5fbea7b 100644 --- a/doc/manual/lowlevel.rst +++ b/doc/manual/lowlevel.rst @@ -70,172 +70,3 @@ Both symmetric keys and initialization values can be considered byte .. cpp:function:: as_string() const Returns the hex representation of the key or IV - -Symmetrically Keyed Algorithms ---------------------------------- - -Block ciphers, stream ciphers, and MACs are all keyed operations; to -be useful, they have to be set to use a particular key, which is a -randomly chosen string of bits of a specified length. The length -required by any particular algorithm may vary, depending on both the -algorithm specification and the implementation. You can query any -botan object to find out what key length(s) it supports. - -To make this similarity in terms of keying explicit, all algorithms of -those types are derived from the :cpp:class`SymmetricAlgorithm` base. -This type provides functions for setting the key, and querying -restrictions on the size of the key. - -.. cpp:class:: SymmetricAlgorithm - - .. cpp:function:: void set_key(const byte* key, size_t length) - - .. cpp:function:: void set_key(const SymmetricKey& key) - - This sets the key to the value specified. Most algorithms only - accept keys of certain lengths. If you attempt to call - ``set_key`` with a key length that is not supported, the - exception ``Invalid_Key_Length`` will be thrown. - - In all cases, ``set_key`` must be called on an object before any - data processing (encryption, decryption, etc) is done by that - object. If this is not done, the results are undefined. - - .. cpp:function:: bool valid_keylength(size_t length) const - - This function returns true if and only if *length* is a valid - keylength for the algorithm. - - .. cpp:function:: size_t minimum_keylength() const - - Return the smallest key length (in bytes) that is acceptible for the - algorithm. - - .. cpp:function:: size_t maximum_keylength() const - - Return the largest key length (in bytes) that is acceptible for the - algorithm - -Block Ciphers ---------------------------------- - -All block ciphers classes in botan are subclasses of - -.. cpp:class:: BlockCipher - - Which subclasses the :cpp:class:`SymmetricAlgorithm` interface. - - .. cpp:function:: size_t block_size() const - - Returns the block size of the cipher in bytes - - .. cpp:function:: void encrypt_n(const byte* in, \ - byte* out, size_t n) const - - Encrypt *n* blocks of data, taking the input from the array *in* - and placing the ciphertext into *out*. The two pointers may be - identical, but should not overlap ranges. - - .. cpp:function:: void encrypt(const byte* in, byte* out) const - - Encrypt a single block, taking the input from *in* and placing - it in *out*. Acts like :cpp:func:`encrypt_n`\ (in, out, 1). - - .. cpp:function:: void encrypt(byte* block) const - - Identical to :cpp:func:`encrypt`\ (block, block) - - .. cpp:function:: void decrypt_n(const byte* in, byte out, size_t n) const - - Decrypt *n* blocks of data, taking the input from *in* and - placing the plaintext in *out*. The two pointers may be - identical, but should not overlap ranges. - - .. cpp:function:: void decrypt(const byte* in, byte* out) const - - Decrypt a single block, taking the input from *in* and placing it - in *out*. Acts like :cpp:func:`decrypt_n`\ (in, out, 1). - - .. cpp:function:: void decrypt(byte* block) const - - Identical to :cpp:func:`decrypt`\ (block, block) - - .. cpp:function:: size_t parallelism() const - - Returns the native parallelism of this implementation, ie how - many blocks can be processed in parallel if sufficient data is - passed to :cpp:func:`encrypt_n` or :cpp:func:`decrypt_n`. - -Stream Ciphers ---------------------------------- - -Stream ciphers are somewhat different from block ciphers, in that -encrypting data results in changing the internal state of the -cipher. Also, you may encrypt any length of data in one go (in byte -amounts). - -.. cpp:function:: void StreamCipher::encrypt(const byte* in, byte* out, size_t length) - -.. cpp:function:: void StreamCipher::encrypt(byte* data, size_t length) - -Stream ciphers implement the ``SymmetricAlgorithm`` interface. - -Hash Functions / Message Authentication Codes ----------------------------------------------- - -Hash functions take their input without producing any output, only -producing anything when all input has already taken place. MACs are -very similar, but are additionally keyed. Both of these are derived -from the base class ``BufferedComputation``, which has the following -functions. - -.. cpp:function:: size_t BufferedComputation::output_length() - -Return the size of the output of this function. - -.. cpp:function:: void BufferedComputation::update(const byte* input, size_t length) - -.. cpp:function:: void BufferedComputation::update(byte input) - -.. cpp:function:: void BufferedComputation::update(const std::string& input) - -Updates the hash/mac calculation with *input*. - -.. cpp:function:: void BufferedComputation::final(byte* out) - -.. cpp:function:: secure_vector<byte> BufferedComputation::final() - -Complete the hash/MAC calculation and place the result into ``out``. -For the argument taking an array, exactly ``output_length`` bytes will -be written. After you call ``final``, the hash function is reset to -its initial state, so it may be reused immediately. - -The second method of using final is to call it with no arguments at -all, as shown in the second prototype. It will return the hash/mac -value in a memory buffer. - -There is also a pair of functions called ``process``. They are a -combination of a single ``update``, and ``final``. Both versions -return the final value, rather than placing it an array. Calling -``process`` with a single byte value isn't available, mostly because -it would rarely be useful. - -A MAC can be viewed (in most cases) as a keyed hash function, so -classes that are derived from ``MessageAuthenticationCode`` have -``update`` and ``final`` classes just like a ``HashFunction`` (and -like a ``HashFunction``, after ``final`` is called, it can be used to -make a new MAC right away; the key is kept around). - -A MAC has the ``SymmetricAlgorithm`` interface in addition to the -``BufferedComputation`` interface. - -Checksums -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Checksums are very similar to hash functions, and in fact share the -same interface. But there are some significant differences, the major -ones being that the output size is very small (usually in the range of -2 to 4 bytes), and is not cryptographically secure. But for their -intended purpose (error checking), they perform very well. Some -examples of checksums included in Botan are the Adler32 and CRC32 -checksums. diff --git a/doc/manual/pubkey.rst b/doc/manual/pubkey.rst index fdce35853..e1f9d53ad 100644 --- a/doc/manual/pubkey.rst +++ b/doc/manual/pubkey.rst @@ -20,7 +20,7 @@ reference to a ``Public_Key``, it can take any public key or private key, and similiarly for ``Private_Key``. Types of ``Public_Key`` include ``RSA_PublicKey``, ``DSA_PublicKey``, -``ECDSA_PublicKey``, ``DH_PublicKey``, ``ECDH_PublicKey``, ``RW_PublicKey``, +``ECDSA_PublicKey``, ``ECKCDSA_PublicKey``, ``ECGDSA_PublicKey``, ``DH_PublicKey``, ``ECDH_PublicKey``, ``RW_PublicKey``, ``NR_PublicKey``,, and ``GOST_3410_PublicKey``. There are cooresponding ``Private_Key`` classes for each of these algorithms. @@ -41,7 +41,7 @@ call A constructor that creates a new random RSA private key with a modulus of length *bits*. -Algorithms based on the discrete-logarithm problem uses what is called a +Algorithms based on the discrete-logarithm problem use what is called a *group*; a group can safely be used with many keys, and for some operations, like key agreement, the two keys *must* use the same group. There are currently two kinds of discrete logarithm groups supported in botan: the @@ -77,6 +77,12 @@ ECDH, or GOST 34.10-2001 private key with .. cpp:function:: ECDSA_PrivateKey::ECDSA_PrivateKey(RandomNumberGenerator& rng, \ const EC_Group& domain, const BigInt& x = 0) +.. cpp:function:: ECKCDSA_PrivateKey::ECKCDSA_PrivateKey(RandomNumberGenerator& rng, \ + const EC_Group& domain, const BigInt& x = 0) + +.. cpp:function:: ECGDSA_PrivateKey::ECGDSA_PrivateKey(RandomNumberGenerator& rng, \ + const EC_Group& domain, const BigInt& x = 0) + .. cpp:function:: ECDH_PrivateKey::ECDH_PrivateKey(RandomNumberGenerator& rng, \ const EC_Group& domain, const BigInt& x = 0) @@ -282,6 +288,31 @@ You can reload a serialized group using .. cpp:function:: void DL_Group::PEM_decode(DataSource& source) +Code Example +""""""""""""""""" +The example below creates a new 2048 bit ``DL_Group``, prints the generated +parameters and ANSI_X9_42 encodes the created group for further usage with DH. + +.. code-block:: cpp + + #include <botan/dl_group.h> + #include <botan/auto_rng.h> + #include <botan/rng.h> + #include <iostream> + + int main() + { + std::unique_ptr<Botan::RandomNumberGenerator> rng(new Botan::AutoSeeded_RNG); + std::unique_ptr<Botan::DL_Group> group(new Botan::DL_Group(*rng.get(), Botan::DL_Group::Strong, 2048)); + std::cout << std::endl << "p: " << group->get_p(); + std::cout << std::endl << "q: " << group->get_q(); + std::cout << std::endl << "g: " << group->get_q(); + std::cout << std::endl << "ANSI_X9_42: " << std::endl << group->PEM_encode(Botan::DL_Group::ANSI_X9_42); + + return 0; + } + + .. _ec_group: EC_Group @@ -373,6 +404,19 @@ The decryption classes are named ``PK_Decryptor``, ``PK_Decryptor_EME``, and the private key, and the processing function is named ``decrypt``. +Botan implements the following encryption algorithms and padding schemes: + +1. RSA + - "PKCS1v15" || "EME-PKCS1-v1_5" + - "OAEP" || "EME-OAEP" || "EME1" || "EME1(SHA-1)" || "EME1(SHA-256)" + + +Code Example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +TODO: Example for "EME1(SHA-256)" + + Signatures --------------------------------- @@ -386,7 +430,7 @@ Signature generation is performed using Constructs a new signer object for the private key *key* using the signature format *emsa*. The key must support signature operations. In - the current version of the library, this includes RSA, DSA, ECDSA, GOST + the current version of the library, this includes RSA, DSA, ECDSA, ECKCDSA, ECGDSA, GOST 34.10-2001, Nyberg-Rueppel, and Rabin-Williams. Other signature schemes may be supported in the future. @@ -399,7 +443,7 @@ Signature generation is performed using For RSA, use EMSA4 (also called PSS) unless you need compatibility with software that uses the older PKCS #1 v1.5 standard, in which case use - EMSA3 (also called "EMSA-PKCS1-v1_5"). For DSA, ECDSA, GOST 34.10-2001, + EMSA3 (also called "EMSA-PKCS1-v1_5"). For DSA, ECDSA, ECKCDSA, ECGDSA GOST 34.10-2001, and Nyberg-Rueppel, you should use EMSA1. The *format* defaults to ``IEEE_1363`` which is the only available @@ -467,6 +511,56 @@ Signatures are verified using on *msg* and then calling :cpp:func:`PK_Verifier::check_signature` on *sig*. + +Botan implements the following signature algorithms: + +1. RSA +#. DSA +#. ECDSA +#. ECGDSA +#. ECKDSA +#. GOST 34.10-2001 +#. Nyberg-Rueppel +#. Rabin-Williams + + +Code Example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The following Code generates a ECDSA keypair and signs the provided data using EMSA1 with SHA-256. +Subsequently the signature is verified. + +.. code-block:: cpp + + #include "botan/botan.h" + #include "botan/auto_rng.h" + #include "botan/ecdsa.h" + #include <botan/ec_group.h> + #include <botan/pubkey.h> + #include "botan/hex.h" + #include <iostream> + + int main() + { + Botan::AutoSeeded_RNG rng; + + Botan::ECDSA_PrivateKey key(rng, Botan::EC_Group("secp521r1")); + Botan::ECDSA_PublicKey pkey(key); + + std::string text("This is a tasty burger!"); + std::vector<uint8_t> data(text.data(),text.data()+text.length()); + + Botan::PK_Signer signer(key, rng, "EMSA1(SHA-256)"); + signer.update(data); + std::vector<uint8_t> signature = signer.signature(rng); + std::cout << "Signature:" << std::endl << Botan::hex_encode(signature); + + Botan::PK_Verifier verifier(pkey, "EMSA1(SHA-256)"); + verifier.update(data); + std::cout << std::endl << "is " << (verifier.check_signature(signature)? "valid" : "invalid"); + return 0; + } + + Key Agreement --------------------------------- @@ -507,3 +601,91 @@ key agreement algorithm. It returns a ``secure_vector<byte>``. in new applications. The X9.42 algorithm may be useful in some circumstances, but unless you need X9.42 compatibility, KDF2 is easier to use. + + +Botan implements the following key agreement methods: + +1. ECDH +#. DH +#. DLIES +#. ECIES + + +Code Example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +TODO: ECDH key exchange example + + +eXtended Merkle Signature Scheme (XMSS) +---------------------------------------- + +Botan implements the single tree version of the eXtended Merkle Signature +Scheme (XMSS) using Winternitz One Time Signatures+ (WOTS+). The implementation +is based on IETF Internet-Draft "XMSS: Extended Hash-Based Signatures". + +XMSS uses the Botan interfaces for public key cryptography. +The following algorithms are implemented: + +1. XMSS_SHA2-256_W16_H10 +#. XMSS_SHA2-256_W16_H16 +#. XMSS_SHA2-256_W16_H20 +#. XMSS_SHA2-512_W16_H10 +#. XMSS_SHA2-512_W16_H16 +#. XMSS_SHA2-512_W16_H20 +#. XMSS_SHAKE128_W16_H10 +#. XMSS_SHAKE128_W16_H10 +#. XMSS_SHAKE128_W16_H10 +#. XMSS_SHAKE256_W16_H10 +#. XMSS_SHAKE256_W16_H10 +#. XMSS_SHAKE256_W16_H10 + + +Code Example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following code snippet shows a minimum example on how to create an XMSS +public/private key pair and how to use these keys to create and verify a signature: + +.. code-block:: cpp + + #include "botan/botan.h" + #include "botan/auto_rng.h" + #include "botan/xmss.h" + + int main() + { + // Create a random number generator used for key generation. + Botan::AutoSeeded_RNG rng; + + // create a new public/private key pair using SHA2 256 as hash + // function and a tree height of 10. + Botan::XMSS_PrivateKey private_key( + Botan::XMSS_Parameters::xmss_algorithm_t::XMSS_SHA2_256_W16_H10, + rng); + Botan::XMSS_PublicKey public_key(private_key); + + // create signature operation using the private key. + std::unique_ptr<Botan::PK_Ops::Signature> sig_op = + private_key.create_signature_op(rng, "", ""); + + // create and sign a message using the signature operation. + Botan::secure_vector<byte> msg { 0x01, 0x02, 0x03, 0x04 }; + sig_op->update(msg.data(), msg.size()); + Botan::secure_vector<byte> sig = sig_op->sign(rng); + + // create verification operation using the public key + std::unique_ptr<Botan::PK_Ops::Verification> ver_op = + public_key.create_verification_op("", ""); + + // verify the signature for the previously generated message. + ver_op->update(msg.data(), msg.size()); + if(ver_op->is_valid_signature(sig.data(), sig.size())) + { + std::cout << "Success." << std::endl; + } + else + { + std::cout << "Error." << std::endl; + } + } diff --git a/doc/manual/symmetric_crypto.rst b/doc/manual/symmetric_crypto.rst new file mode 100644 index 000000000..6afb05322 --- /dev/null +++ b/doc/manual/symmetric_crypto.rst @@ -0,0 +1,570 @@ +Symmetric Key Cryptography +=========================================== +Block ciphers, stream ciphers and MACs are all keyed operations. +They require a particular key, which is a chosen, sampled or computed +string of bits of a specified length. The length required by any particular algorithm +may vary, depending on both the algorithm specification and the implementation. +You can query any Botan object to find out what key length(s) it supports. + +To make this similarity in terms of keying explicit, all algorithms of +those types are derived from the :cpp:class:`SymmetricAlgorithm` base. +This type provides functions for setting the key, and querying +restrictions on the size of the key. + +.. cpp:class:: SymmetricAlgorithm + + .. cpp:function:: void set_key(const byte* key, size_t length) + + .. cpp:function:: void set_key(const SymmetricKey& key) + + This sets the key to the value specified. Most algorithms only + accept keys of certain lengths. If you attempt to call + ``set_key`` with a key length that is not supported, the + exception ``Invalid_Key_Length`` will be thrown. + + In all cases, ``set_key`` must be called on an object before any + data processing (encryption, decryption, etc) is done by that + object. If this is not done, the results are undefined. + + .. cpp:function:: bool valid_keylength(size_t length) const + + This function returns true if and only if *length* is a valid + keylength for the algorithm. + + .. cpp:function:: size_t minimum_keylength() const + + Return the smallest key length (in bytes) that is acceptible for the + algorithm. + + .. cpp:function:: size_t maximum_keylength() const + + Return the largest key length (in bytes) that is acceptible for the + algorithm. + +Block Ciphers +--------------------------------- +A block cipher is a deterministic symmetric encryption algorithm, which +encrypts data of a fixed length, called block size. All block ciphers classes +in Botan are subclasses of :cpp:class:`BlockCipher` defined in `botan/block_cipher.h`. +As a symmetrically keyed algorithm, it subclasses the :cpp:class:`SymmetricAlgorithm` interface. +Note that a block cipher by itself is only secure for plaintext with the length of a single block. +When processing data larger than a single block, a block cipher mode should be used for data processing. + +.. cpp:class:: BlockCipher + + .. cpp:function:: size_t block_size() const + + Returns the block size of the cipher in bytes. + + .. cpp:function:: void encrypt_n(const byte* in, \ + byte* out, size_t n) const + + Encrypt *n* blocks of data, taking the input from the array *in* + and placing the ciphertext into *out*. The two pointers may be + identical, but should not overlap ranges. + + .. cpp:function:: void encrypt(const byte* in, byte* out) const + + Encrypt a single block, taking the input from *in* and placing + it in *out*. Acts like :cpp:func:`encrypt_n`\ (in, out, 1). + + .. cpp:function:: void encrypt(const std::vector<byte> in, std::vector<byte> out) const + + Encrypt a single or multiple full blocks, taking the input from *in* and placing it in *out*. + Acts like :cpp:func:`encrypt_n`\ (in.data(), out.data(), in.size()/ block_size()). + + .. cpp:function:: void encrypt(std::vector<byte> inout) const + + Encrypt a single or multiple full blocks in place. + Acts like :cpp:func:`encrypt_n`\ (inout.data(), inout.data(), inout.size()/ block_size()). + + .. cpp:function:: void encrypt(byte* block) const + + Identical to :cpp:func:`encrypt`\ (block, block) + + .. cpp:function:: void decrypt_n(const byte* in, byte out, size_t n) const + + Decrypt *n* blocks of data, taking the input from *in* and + placing the plaintext in *out*. The two pointers may be + identical, but should not overlap ranges. + + .. cpp:function:: void decrypt(const byte* in, byte* out) const + + Decrypt a single block, taking the input from *in* and placing it + in *out*. Acts like :cpp:func:`decrypt_n`\ (in, out, 1). + + .. cpp:function:: void decrypt(const std::vector<byte> in, std::vector<byte> out) const + + Decrypt a single or multiple full blocks, taking the input from *in* and placing it in *out*. + Acts like :cpp:func:`decrypt_n`\ (in.data(), out.data(), in.size()/ block_size()). + + .. cpp:function:: void decrypt(std::vector<byte> inout) const + + Decrypt a single or multiple full blocks in place. + Acts like :cpp:func:`decrypt_n`\ (inout.data(), inout.data(), inout.size()/ block_size()). + + .. cpp:function:: void decrypt(byte* block) const + + Identical to :cpp:func:`decrypt`\ (block, block) + + .. cpp:function:: size_t parallelism() const + + Returns the native parallelism of this implementation, ie how + many blocks can be processed in parallel if sufficient data is + passed to :cpp:func:`encrypt_n` or :cpp:func:`decrypt_n`. + +The following block ciphers are implemented in Botan: + +#. AES (AES-128, AES-192, AES-256) +#. Serpent +#. Twofish +#. Threefish-512 +#. Blowfish +#. Camellia (Camellia-128, Camellia-192, Camellia-256) +#. DES +#. 3DES +#. DESX +#. Noekeon +#. CAST (CAST-128, CAST-256) +#. IDEA +#. Kasumi +#. MISTY1 +#. SEED +#. XTEA +#. GOST-28147-89 +#. Cascade +#. Lion + +Code Example +""""""""""""""" +For sheer demonstrative purposes, the following code encrypts a provided single block of +plaintext with AES-256 using two different keys. + +.. code-block:: cpp + + #include <botan/block_cipher.h> + #include <botan/hex.h> + #include <iostream> + int main () + { + std::vector<uint8_t> key = Botan::hex_decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + std::vector<uint8_t> block = Botan::hex_decode("00112233445566778899AABBCCDDEEFF"); + std::unique_ptr<Botan::BlockCipher> cipher(Botan::BlockCipher::create("AES-256")); + cipher->set_key(key); + cipher->encrypt(block); + std::cout << std::endl <<cipher->name() << "single block encrypt: " << Botan::hex_encode(block); + + //clear cipher for 2nd encryption with other key + cipher->clear(); + key = Botan::hex_decode("1337133713371337133713371337133713371337133713371337133713371337"); + cipher->set_key(key); + cipher->encrypt(block); + + std::cout << std::endl << cipher->name() << "single block encrypt: " << Botan::hex_encode(block); + return 0; + } + +Modes of Operation +--------------------------- +A block cipher by itself, is only able to securely encrypt a single data block. +To be able to securely encrypt data of arbitrary length, a mode of operation applies +the block cipher's single block operation repeatedly on a padded plaintext. +Botan implements the following block cipher padding schemes + +PKCS#7 [RFC5652] + The last byte in the padded block defines the padding length p, the remaining padding bytes are set to p as well. +ANSI X9.23 + The last byte in the padded block defines the padding length, the remaining padding is filled with 0x00. +ISO/IEC 7816-4 + The first padding byte is set to 0x80, the remaining padding bytes are set to 0x00. + +and offers the following unauthenticated modes of operation: + +#. ECB (Electronic Codebook Mode) +#. CBC (Cipher Block Chaining Mode) +#. CFB (Cipher Feedback Mode) +#. XTS (XEX-based tweaked-codebook mode with ciphertext stealing) +#. OFB (Output Feedback Mode) +#. CTR (Counter Mode) + +The classes :cpp:class:`ECB_Mode`, :cpp:class:`CBC_Mode`, :cpp:class:`CFB_Mode` and :cpp:class:`XTS_Mode` are +are derived from the base class :cpp:class:`Cipher_Mode`, which is declared in ``botan/cipher_mode.h``. + +.. cpp:class:: Cipher_Mode + + .. cpp:function:: void set_key(const SymmetricKey& key) + .. cpp:function:: void set_key(const byte* key, size_t length) + + Set the symmetric key to be used. + + .. cpp:function:: void start_msg(const byte* nonce, size_t nonce_len) + + Set the IV (unique per-message nonce) of the mode of operation and prepare for message processing. + + .. cpp:function:: void start(const std::vector<byte> nonce) + + Acts like :cpp:func:`start_msg`\ (nonce.data(), nonce.size()). + + .. cpp:function:: void start(const byte* nonce, size_t nonce_len) + + Acts like :cpp:func:`start_msg`\ (nonce, nonce_len). + + .. cpp:function:: virtual size_t update_granularity() const + + The :cpp:class:`Cipher_Mode` interface requires message processing in multiples of the block size. + Returns size of required blocks to update and 1, if the mode can process messages of any length. + + .. cpp:function:: virtual size_t process(byte* msg, size_t msg_len) + + Process msg in place and returns bytes written. msg must be a multiple of :cpp:func:`update_granularity`. + + .. cpp:function:: void update(secure_vector<byte>& buffer, size_t offset = 0) + + Continue processing a message in the buffer in place. The passed buffer's size must be a multiple of :cpp:func:`update_granularity`. + The first *offset* bytes of the buffer will be ignored. + + .. cpp:function:: size_t minimum_final_size() const + + Returns the minimum size needed for :cpp:func:`finish`. + + .. cpp:function:: void finish(secure_vector<byte>& final_block, size_t offset = 0) + + Finalize the message processing with a final block of at least :cpp:func:`minimum_final_size` size. + The first *offset* bytes of the passed final block will be ignored. + +Note that :cpp:class:`CTR_BE` and :cpp:class:`OFB` are derived from the base class :cpp:class:`StreamCipher` and thus act like a stream cipher. +The class :cpp:class:`StreamCipher` is described in the respective section. + + +Code Example +""""""""""""""""""""" +The following code encrypts the specified plaintext using AES-128/CBC with PKCS#7 padding. + +.. code-block:: cpp + + #include <botan/rng.h> + #include <botan/auto_rng.h> + #include <botan/cipher_mode.h> + #include <botan/hex.h> + #include <iostream> + + int main() + { + std::string plaintext("Your great-grandfather gave this watch to your granddad for good luck. Unfortunately, Dane's luck wasn't as good as his old man's."); + Botan::secure_vector<uint8_t> pt(plaintext.data(),plaintext.data()+plaintext.length()); + const std::vector<uint8_t> key = Botan::hex_decode("2B7E151628AED2A6ABF7158809CF4F3C"); + std::unique_ptr<Botan::Cipher_Mode> enc(Botan::get_cipher_mode("AES-128/CBC/PKCS7", Botan::ENCRYPTION)); + enc->set_key(key); + + //generate fresh nonce (IV) + std::unique_ptr<Botan::RandomNumberGenerator> rng(new Botan::AutoSeeded_RNG); + std::vector<uint8_t> iv(enc->default_nonce_length()); + rng->randomize(iv.data(),iv.size()); + enc->start(iv); + enc->finish(pt); + std::cout << std::endl << enc->name() << " with iv " << Botan::hex_encode(iv) << std::endl << Botan::hex_encode(pt); + return 0; + } + + +AEAD Modes of Operation +--------------------------- + +.. versionadded:: 1.11.3 + +AEAD (Authenticated Encryption with Associated Data) modes provide message +encryption, message authentication, and the ability to authenticate additional +data that is not included in the ciphertext (such as a sequence number or +header). It is a subclass of :cpp:class:`Symmetric_Algorithm`. + +The AEAD interface can be used directly, or as part of the filter system by +using :cpp:class:`AEAD_Filter` (a subclass of :cpp:class:`Keyed_Filter` which +will be returned by :cpp:func:`get_cipher` if the named cipher is an AEAD mode). + +AEAD modes currently available include GCM, OCB, EAX, SIV and CCM. All +support a 128-bit block cipher such as AES. EAX and SIV also support +256 and 512 bit block ciphers. + +.. cpp:class:: AEAD_Mode + + .. cpp:function:: void set_key(const SymmetricKey& key) + + Set the key + + .. cpp:function:: Key_Length_Specification key_spec() const + + Return the key length specification + + .. cpp:function:: void set_associated_data(const byte ad[], size_t ad_len) + + Set any associated data for this message. For maximum portability between + different modes, this must be called after :cpp:func:`set_key` and before + :cpp:func:`start`. + + If the associated data does not change, it is not necessary to call this + function more than once, even across multiple calls to :cpp:func:`start` + and :cpp:func:`finish`. + + .. cpp:function:: void start(const byte nonce[], size_t nonce_len) + + Start processing a message, using *nonce* as the unique per-message + value. + + .. cpp:function:: void update(secure_vector<byte>& buffer, size_t offset = 0) + + Continue processing a message. The *buffer* is an in/out parameter and + may be resized. In particular, some modes require that all input be + consumed before any output is produced; with these modes, *buffer* will + be returned empty. + + On input, the buffer must be sized in blocks of size + :cpp:func:`update_granularity`. For instance if the update granularity + was 64, then *buffer* could be 64, 128, 192, ... bytes. + + The first *offset* bytes of *buffer* will be ignored (this allows in + place processing of a buffer that contains an initial plaintext header) + + .. cpp:function:: void finish(secure_vector<byte>& buffer, size_t offset = 0) + + Complete processing a message with a final input of *buffer*, which is + treated the same as with :cpp:func:`update`. It must contain at least + :cpp:func:`final_minimum_size` bytes. + + Note that if you have the entire message in hand, calling finish without + ever calling update is both efficient and convenient. + + .. note:: + During decryption, finish will throw an instance of Integrity_Failure + if the MAC does not validate. If this occurs, all plaintext previously + output via calls to update must be destroyed and not used in any + way that an attacker could observe the effects of. + + One simply way to assure this could never happen is to never + call update, and instead always marshall the entire message + into a single buffer and call finish on it when decrypting. + + .. cpp:function:: size_t update_granularity() const + + The AEAD interface requires :cpp:func:`update` be called with blocks of + this size. This will be 1, if the mode can process any length inputs. + + .. cpp:function:: size_t final_minimum_size() const + + The AEAD interface requires :cpp:func:`finish` be called with at least + this many bytes (which may be zero, or greater than + :cpp:func:`update_granularity`) + + .. cpp:function:: bool valid_nonce_length(size_t nonce_len) const + + Returns true if *nonce_len* is a valid nonce length for this scheme. For + EAX and GCM, any length nonces are allowed. OCB allows any value between + 8 and 15 bytes. + + .. cpp:function:: size_t default_nonce_length() const + + Returns a reasonable length for the nonce, typically either 96 + bits, or the only supported length for modes which don't + support 96 bit nonces. + +Stream Ciphers +--------------------------------- +In contrast to block ciphers, stream ciphers operate on a plaintext stream instead +of blocks. Thus encrypting data results in changing the internal state of the +cipher and encryption of plaintext with arbitrary length is possible in one go (in byte +amounts). All implemented stream ciphers derive from the base class :cpp:class:`StreamCipher` (`botan/stream_cipher.h`), which +implements the :cpp:class:`SymmetricAlgorithm` interface. Note that some of the implemented +stream ciphers require a fresh initialisation vector. + +.. cpp:class:: StreamCipher + + .. cpp:function:: bool valid_iv_length(size_t iv_len) const + + This function returns true if and only if *length* is a valid + IV length for the stream cipher. + + .. cpp:function:: void set_iv(const byte*, size_t len) + + Load IV into the stream cipher state. This should happen after the key is + set and before any operation (encrypt/decrypt/seek) is called. + + .. cpp:function:: void seek(u64bit offset) + + Sets the state of the stream cipher and keystream according to the passed *offset*. + Therefore the key and the IV (if required) have to be set beforehand. + + .. cpp:function:: void cipher(const byte* in, byte* out, size_t n) + + Processes *n* bytes plain/ciphertext from *in* and writes the result to *out*. + + .. cpp:function:: void cipher1(byte* inout, size_t n) + + Processes *n* bytes plain/ciphertext in place. Acts like :cpp:func:`cipher`\ (inout, inout, n). + + .. cpp:function:: void encipher(std::vector<byte> inout) + .. cpp:function:: void encrypt(std::vector<byte> inout) + .. cpp:function:: void decrypt(std::vector<byte> inout) + + Processes plain/ciphertext *inout* in place. Acts like :cpp:func:`cipher`\ (inout.data(), inout.data(), inout.size()). + +Botan provides the following stream ciphers: + +#. ChaCha +#. Salsa20 +#. SHAKE-128 +#. RC4 + +Code Example +"""""""""""""" +The following code encrypts a provided plaintext using ChaCha20. + +.. code-block:: cpp + + #include <botan/stream_cipher.h> + #include <botan/rng.h> + #include <botan/auto_rng.h> + #include <botan/hex.h> + #include <iostream> + + + int main() + { + std::string plaintext("This is a tasty burger!"); + std::vector<uint8_t> pt(plaintext.data(),plaintext.data()+plaintext.length()); + const std::vector<uint8_t> key = Botan::hex_decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + std::unique_ptr<Botan::StreamCipher> cipher(Botan::StreamCipher::create("ChaCha")); + + //generate fresh nonce (IV) + std::unique_ptr<Botan::RandomNumberGenerator> rng(new Botan::AutoSeeded_RNG); + std::vector<uint8_t> iv(8); + rng->randomize(iv.data(),iv.size()); + + //set key and IV + cipher->set_key(key); + cipher->set_iv(iv.data(),iv.size()); + std::cout << std::endl << cipher->name() << " with iv " << Botan::hex_encode(iv) << std::endl; + cipher->encipher(pt); + std::cout << Botan::hex_encode(pt); + + return 0; + } + + + +Message Authentication Codes (MAC) +---------------------------------- +A Message Authentication Code algorithm computes a tag over a message utilizing a shared secret key. +Thus a valid tag confirms the authenticity and integrity of the associated data. +Only entities in possesion of the shared secret key are able to verify the tag. +The base class ``MessageAuthenticationCode`` (in ``botan/mac.h``) implements the interfaces +:cpp:class:`SymmetricAlgorithm` and :cpp:class:`BufferedComputation` (see Hash). + +.. note:: + Avoid MAC-then-encrypt if possible and use encrypt-then-MAC. + +Currently the following MAC algorithms are available in Botan: + +- CBC-MAC (with AES-128/DES) +- CMAC / OMAC (with AES-128/AES-192/AES-256/Blowfish/Threefish-512) +- GMAC (with AES-128/AES-192/AES-256) +- HMAC (with MD5, RIPEMD-160, SHA-1, SHA-256) +- Poly1305 +- SipHash +- x9.19-MAC + +The Botan MAC computation is split into five stages. + +#. Instantiate the MAC algorithm. +#. Set the secret key. +#. Process IV. +#. Process data. +#. Finalize the MAC computation. + +.. cpp:class:: MessageAuthenticationCode + + .. cpp:function:: void set_key(const byte* key, size_t length) + + Set the shared MAC key for the calculation. This function has to be called before the data is processed. + + .. cpp:function:: void start(const byte* nonce, size_t nonce_len) + + Set the IV for the MAC calculation. Note that not all MAC algorithms require an IV. + If an IV is required, the function has to be called before the data is processed. + + .. cpp:function:: void update(const byte* input, size_t length) + .. cpp:function:: void update(const secure_vector<byte>& in) + + Process the passed data. + + .. cpp:function:: void update(byte in) + + Process a single byte. + + .. cpp:function:: void final(byte* out) + + Complete the MAC computation and write the calculated tag to the passed byte array. + + .. cpp:function:: secure_vector<byte> final() + + Complete the MAC computation and return the calculated tag. + + .. cpp:function:: bool verify_mac(const byte* mac, size_t length) + + Finalize the current MAC computation and compare the result to the passed ``mac``. Returns ``true``, if the verification is successfull and false otherwise. + + +Code Example +"""""""""""""""""""""" +The following example code computes a AES-256 GMAC and subsequently verifies the tag. + +.. code-block:: cpp + + #include <botan/mac.h> + #include <botan/hex.h> + #include <iostream> + + int main() + { + const std::vector<uint8_t> key = Botan::hex_decode("1337133713371337133713371337133713371337133713371337133713371337"); + const std::vector<uint8_t> iv = Botan::hex_decode("FFFFFFFFFFFFFFFFFFFFFFFF"); + const std::vector<uint8_t> data = Botan::hex_decode("6BC1BEE22E409F96E93D7E117393172A"); + std::unique_ptr<Botan::MessageAuthenticationCode> mac(Botan::MessageAuthenticationCode::create("GMAC(AES-256)")); + if(!mac) + return 1; + mac->set_key(key); + mac->start(iv); + mac->update(data); + Botan::secure_vector<uint8_t> tag = mac->final(); + std::cout << mac->name() << ": " << Botan::hex_encode(tag) << std::endl; + + //Verify created MAC + mac->start(iv); + mac->update(data); + std::cout << "Verification: " << (mac->verify_mac(tag) ? "success" : "failure"); + return 0; + } + +The following example code computes a valid AES-128 CMAC tag and modifies the data to demonstrate a MAC verification failure. + +.. code-block:: cpp + + #include <botan/mac.h> + #include <botan/hex.h> + #include <iostream> + + int main() + { + const std::vector<uint8_t> key = Botan::hex_decode("2B7E151628AED2A6ABF7158809CF4F3C"); + std::vector<uint8_t> data = Botan::hex_decode("6BC1BEE22E409F96E93D7E117393172A"); + std::unique_ptr<Botan::MessageAuthenticationCode> mac(Botan::MessageAuthenticationCode::create("CMAC(AES-128)")); + if(!mac) + return 1; + mac->set_key(key); + mac->update(data); + Botan::secure_vector<uint8_t> tag = mac->final(); + //Corrupting data + data.back()++; + //Verify with corrupted data + mac->update(data); + std::cout << "Verification with malformed data: " << (mac->verify_mac(tag) ? "success" : "failure"); + return 0; + } |