aboutsummaryrefslogtreecommitdiffstats
path: root/doc/manual/symmetric_crypto.rst
diff options
context:
space:
mode:
Diffstat (limited to 'doc/manual/symmetric_crypto.rst')
-rw-r--r--doc/manual/symmetric_crypto.rst570
1 files changed, 570 insertions, 0 deletions
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;
+ }