diff options
author | Jack Lloyd <[email protected]> | 2019-05-31 23:08:48 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2019-05-31 23:34:34 -0400 |
commit | 924bb1a52ec3dad476a5f8567a7411b18a3e7056 (patch) | |
tree | be6ecc03c2cf7b6da23f51c85ab3d5170566d150 /doc/api_ref | |
parent | c610d318d37c899260a2d3f3e3692970c6f8d9ba (diff) |
Reorg documentation layout. Rename manual to handbook.
Diffstat (limited to 'doc/api_ref')
31 files changed, 11260 insertions, 0 deletions
diff --git a/doc/api_ref/bigint.rst b/doc/api_ref/bigint.rst new file mode 100644 index 000000000..364844fb5 --- /dev/null +++ b/doc/api_ref/bigint.rst @@ -0,0 +1,279 @@ +BigInt +======================================== + +``BigInt`` is Botan's implementation of a multiple-precision integer. Thanks to +C++'s operator overloading features, using ``BigInt`` is often quite similar to +using a native integer type. The number of functions related to ``BigInt`` is +quite large, and not all of them are documented here. You can find the complete +declarations in ``botan/bigint.h`` and ``botan/numthry.h``. + +.. cpp:class:: BigInt + + .. cpp:function:: BigInt() + + Create a BigInt with value zero + + .. cpp:function:: BigInt(uint64_t n) + + Create a BigInt with value *n* + + .. cpp:function:: BigInt(const std::string& str) + + Create a BigInt from a string. By default decimal is expected. With an 0x + prefix instead it is treated as hexadecimal. + + .. cpp:function:: BigInt(const uint8_t buf[], size_t length) + + Create a BigInt from a binary array (big-endian encoding). + + .. cpp:function:: BigInt(RandomNumberGenerator& rng, size_t bits, bool set_high_bit = true) + + Create a random BigInt of the specified size. + + .. cpp:function:: BigInt operator+(const BigInt& x, const BigInt& y) + + Add ``x`` and ``y`` and return result. + + .. cpp:function:: BigInt operator+(const BigInt& x, word y) + + Add ``x`` and ``y`` and return result. + + .. cpp:function:: BigInt operator+(word x, const BigInt& y) + + Add ``x`` and ``y`` and return result. + + .. cpp:function:: BigInt operator-(const BigInt& x, const BigInt& y) + + Subtract ``y`` from ``x`` and return result. + + .. cpp:function:: BigInt operator-(const BigInt& x, word y) + + Subtract ``y`` from ``x`` and return result. + + .. cpp:function:: BigInt operator*(const BigInt& x, const BigInt& y) + + Multiply ``x`` and ``y`` and return result. + + .. cpp:function:: BigInt operator/(const BigInt& x, const BigInt& y) + + Divide ``x`` by ``y`` and return result. + + .. cpp:function:: BigInt operator%(const BigInt& x, const BigInt& y) + + Divide ``x`` by ``y`` and return remainder. + + .. cpp:function:: word operator%(const BigInt& x, word y) + + Divide ``x`` by ``y`` and return remainder. + + .. cpp:function:: word operator<<(const BigInt& x, size_t n) + + Left shift ``x`` by ``n`` and return result. + + .. cpp:function:: word operator>>(const BigInt& x, size_t n) + + Right shift ``x`` by ``n`` and return result. + + .. cpp:function:: BigInt& operator+=(const BigInt& y) + + Add y to ``*this`` + + .. cpp:function:: BigInt& operator+=(word y) + + Add y to ``*this`` + + .. cpp:function:: BigInt& operator-=(const BigInt& y) + + Subtract y from ``*this`` + + .. cpp:function:: BigInt& operator-=(word y) + + Subtract y from ``*this`` + + .. cpp:function:: BigInt& operator*=(const BigInt& y) + + Multiply ``*this`` with y + + .. cpp:function:: BigInt& operator*=(word y) + + Multiply ``*this`` with y + + .. cpp:function:: BigInt& operator/=(const BigInt& y) + + Divide ``*this`` by y + + .. cpp:function:: BigInt& operator%=(const BigInt& y) + + Divide ``*this`` by y and set ``*this`` to the remainder. + + .. cpp:function:: word operator%=(word y) + + Divide ``*this`` by y and set ``*this`` to the remainder. + + .. cpp:function:: word operator<<=(size_t shift) + + Left shift ``*this`` by *shift* bits + + .. cpp:function:: word operator>>=(size_t shift) + + Right shift ``*this`` by *shift* bits + + .. cpp:function:: BigInt& operator++() + + Increment ``*this`` by 1 + + .. cpp:function:: BigInt& operator--() + + Decrement ``*this`` by 1 + + .. cpp:function:: BigInt operator++(int) + + Postfix increment ``*this`` by 1 + + .. cpp:function:: BigInt operator--(int) + + Postfix decrement ``*this`` by 1 + + .. cpp:function:: BigInt operator-() const + + Negation operator + + .. cpp:function:: bool operator !() const + + Return true unless ``*this`` is zero + + .. cpp:function:: void clear() + + Set ``*this`` to zero + + .. cpp:function:: size_t bytes() const + + Return number of bytes need to represent value of ``*this`` + + .. cpp:function:: size_t bits() const + + Return number of bits need to represent value of ``*this`` + + .. cpp:function:: bool is_even() const + + Return true if ``*this`` is even + + .. cpp:function:: bool is_odd() const + + Return true if ``*this`` is odd + + .. cpp:function:: bool is_nonzero() const + + Return true if ``*this`` is not zero + + .. cpp:function:: bool is_zero() const + + Return true if ``*this`` is zero + + .. cpp:function:: void set_bit(size_t n) + + Set bit *n* of ``*this`` + + .. cpp:function:: void clear_bit(size_t n) + + Clear bit *n* of ``*this`` + + .. cpp:function:: bool get_bit(size_t n) const + + Get bit *n* of ``*this`` + + .. cpp:function:: uint32_t to_u32bit() const + + Return value of ``*this`` as a 32-bit integer, if possible. + If the integer is negative or not in range, an exception is thrown. + + .. cpp:function:: bool is_negative() const + + Return true if ``*this`` is negative + + .. cpp:function:: bool is_positive() const + + Return true if ``*this`` is negative + + .. cpp:function:: BigInt abs() const + + Return absolute value of ``*this`` + + .. cpp:function:: void binary_encode(uint8_t buf[]) const + + Encode this BigInt as a big-endian integer. The sign is ignored. + + .. cpp:function:: void binary_encode(uint8_t buf[], size_t len) const + + Encode this BigInt as a big-endian integer. The sign is ignored. + If ``len`` is less than ``bytes()`` then only the low ``len`` + bytes are output. If ``len`` is greater than ``bytes()`` then + the output is padded with leading zeros. + + .. cpp:function:: void binary_decode(uint8_t buf[]) + + Decode this BigInt as a big-endian integer. + + .. cpp:function:: std::string to_dec_string() const + + Encode the integer as a decimal string. + + .. cpp:function:: std::string to_hex_string() const + + Encode the integer as a hexadecimal string. + +Number Theory +---------------------------------------- + +Number theoretic functions available include: + +.. cpp:function:: BigInt gcd(BigInt x, BigInt y) + + Returns the greatest common divisor of x and y + +.. cpp:function:: BigInt lcm(BigInt x, BigInt y) + + Returns an integer z which is the smallest integer such that z % x + == 0 and z % y == 0 + +.. cpp:function:: BigInt jacobi(BigInt a, BigInt n) + + Return Jacobi symbol of (a|n). + +.. cpp:function:: BigInt inverse_mod(BigInt x, BigInt m) + + Returns the modular inverse of x modulo m, that is, an integer + y such that (x*y) % m == 1. If no such y exists, returns zero. + +.. cpp:function:: BigInt power_mod(BigInt b, BigInt x, BigInt m) + + Returns b to the xth power modulo m. If you are doing many + exponentiations with a single fixed modulus, it is faster to use a + ``Power_Mod`` implementation. + +.. cpp:function:: BigInt ressol(BigInt x, BigInt p) + + Returns the square root modulo a prime, that is, returns a number y + such that (y*y) % p == x. Returns -1 if no such integer exists. + +.. cpp:function:: bool is_prime(BigInt n, RandomNumberGenerator& rng, \ + size_t prob = 56, double is_random = false) + + Test *n* for primality using a probabilistic algorithm (Miller-Rabin). With + this algorithm, there is some non-zero probability that true will be returned + even if *n* is actually composite. Modifying *prob* allows you to decrease the + chance of such a false positive, at the cost of increased runtime. Sufficient + tests will be run such that the chance *n* is composite is no more than 1 in + 2\ :sup:`prob`. Set *is_random* to true if (and only if) *n* was randomly + chosen (ie, there is no danger it was chosen maliciously) as far fewer tests + are needed in that case. + +.. cpp:function:: BigInt random_prime(RandomNumberGenerator& rng, \ + size_t bits, \ + BigInt coprime = 1, \ + size_t equiv = 1, \ + size_t equiv_mod = 2) + + Return a random prime number of ``bits`` bits long that is + relatively prime to ``coprime``, and equivalent to ``equiv`` modulo + ``equiv_mod``. diff --git a/doc/api_ref/block_cipher.rst b/doc/api_ref/block_cipher.rst new file mode 100644 index 000000000..578235a2d --- /dev/null +++ b/doc/api_ref/block_cipher.rst @@ -0,0 +1,347 @@ +Block Ciphers +======================= + +Block ciphers are a n-bit permutation for some small n, typically 64 or 128 +bits. They are a cryptographic primitive used to generate higher level +operations such as authenticated encryption. + +.. warning:: + + In almost all cases, a bare block cipher is not what you should be using. + You probably want an authenticated cipher mode instead (see :ref:`cipher_modes`) + This interface is used to build higher level operations (such as cipher + modes or MACs), or in the very rare situation where ECB is required, + eg for compatibility with an existing system. + +.. cpp:class:: BlockCipher + + .. cpp:function:: static std::unique_ptr<BlockCipher> create(const std::string& algo_spec, \ + const std::string& provider = "") + + Create a new block cipher object, or else return null. + + .. cpp:function:: static std::unique_ptr<BlockCipher> create_or_throw(const std::string& algo_spec, \ + const std::string& provider = "") + + Like ``create``, except instead of returning null an exception is thrown + if the cipher is not known. + + .. cpp:function:: void set_key(const uint8_t* key, size_t length) + + 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, an exception will be thrown. + thrown. + + .. cpp:function:: bool valid_keylength(size_t length) const + + This function returns true if and only if *length* is a valid keylength for + this algorithm. + + .. cpp:function:: size_t minimum_keylength() const + + Return the smallest key length (in bytes) that is acceptable for the + algorithm. + + .. cpp:function:: size_t maximum_keylength() const + + Return the largest key length (in bytes) that is acceptable for the + algorithm. + + .. cpp:function:: std::string name() const + + Return a human readable name for this algorithm. This is guaranteed to round-trip with + ``create`` and ``create_or_throw`` calls, ie create("Foo")->name() == "Foo" + + .. cpp:function:: void clear() + + Zero out the key. The key must be reset before the cipher object can be used. + + .. cpp:function:: BlockCipher* clone() const + + Return a newly allocated BlockCipher object of the same type as this one. + + .. cpp:function:: size_t block_size() const + + Return the size (in *bytes*) of the cipher. + + .. cpp:function:: size_t parallelism() const + + Return the parallelism underlying this implementation of the cipher. This + value can vary across versions and machines. A return value of N means that + encrypting or decrypting with N blocks can operate in parallel. + + .. cpp:function:: size_t parallel_bytes() const + + Returns ``parallelism`` multiplied by the block size as well as a small + fudge factor. That's because even ciphers that have no implicit parallelism + typically see a small speedup for being called with several blocks due to + caching effects. + + .. cpp:function:: std::string provider() const + + Return the provider type. Default value is "base" but can be any arbitrary string. + Other example values are "sse2", "avx2", "openssl". + + .. cpp:function:: void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + + Encrypt *blocks* 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 decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const + + Decrypt *blocks* blocks of data, taking the input from the array *in* and + placing the plaintext into *out*. The two pointers may be identical, but + should not overlap ranges. + + .. cpp:function:: void encrypt(const uint8_t in[], uint8_t out[]) const + + Encrypt a single block. Equivalent to :cpp:func:`encrypt_n`\ (in, out, 1). + + .. cpp:function:: void encrypt(uint8_t block[]) const + + Encrypt a single block. Equivalent to :cpp:func:`encrypt_n`\ (block, block, 1) + + .. cpp:function:: void decrypt(const uint8_t in[], uint8_t out[]) const + + Decrypt a single block. Equivalent to :cpp:func:`decrypt_n`\ (in, out, 1) + + .. cpp:function:: void decrypt(uint8_t block[]) const + + Decrypt a single block. Equivalent to :cpp:func:`decrypt_n`\ (block, block, 1) + + .. cpp:function:: template<typename Alloc> void encrypt(std::vector<uint8_t, Alloc>& block) const + + Assumes ``block`` is of a multiple of the block size. + + .. cpp:function:: template<typename Alloc> void decrypt(std::vector<uint8_t, Alloc>& block) const + + Assumes ``block`` is of a multiple of the block size. + +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; + } + +Available Ciphers +--------------------- + +Botan includes a number of block ciphers that are specific to particular +countries, as well as a few that are included mostly due to their use in +specific protocols such as PGP but not widely used elsewhere. The ciphers that +seem best for new code are AES, Serpent, and Threefish-512. If you are +developing new code and have no particular opinion, pick AES-256. + +.. warning:: Avoid any 64-bit block cipher in new designs. There are + combinatoric issues that affect any 64-bit cipher that render it + insecure when large amounts of data are processed. + +AES +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Comes in three variants, AES-128, AES-192, and AES-256. + +The standard 128-bit block cipher. Many modern platforms offer hardware +acceleration. However, on platforms without hardware support, AES +implementations typically are vulnerable to side channel attacks. For x86 +systems with SSSE3 but without AES-NI, Botan has an implementation which avoids +known side channels. + +Available if ``BOTAN_HAS_AES`` is defined. + +ARIA +~~~~~~ + +South Korean cipher used in industry there. No reason to use it otherwise. + +Available if ``BOTAN_HAS_ARIA`` is defined. + +Blowfish +~~~~~~~~~ + +A 64-bit cipher popular in the pre-AES era. Very slow key setup. Also used (with +bcrypt) for password hashing. + +Available if ``BOTAN_HAS_BLOWFISH`` is defined. + +CAST-128 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 64-bit cipher, commonly used in OpenPGP. + +Available if ``BOTAN_HAS_CAST128`` is defined. + +CAST-256 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 128-bit cipher that was a contestant in the NIST AES competition. +Rarely used, and now deprecated in Botan. Use AES or Serpent instead. + +Available if ``BOTAN_HAS_CAST256`` is defined. + +Camellia +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Comes in three variants, Camellia-128, Camellia-192, and Camellia-256. + +A Japanese design standardized by ISO, NESSIE and CRYPTREC. Somewhat common. +Prefer AES or Serpent in new designs. + +Available if ``BOTAN_HAS_CAMELLIA`` is defined. + +Cascade +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Creates a block cipher cascade, where each block is encrypted by two ciphers +with independent keys. Useful if you're very paranoid. In practice any single +good cipher (such as Serpent, SHACAL2, or AES-256) is more than sufficient. + +Available if ``BOTAN_HAS_CASCADE`` is defined. + +DES, 3DES, DESX +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Originally designed by IBM and NSA in the 1970s. Today, DES's 56-bit key renders +it insecure to any well-resourced attacker. DESX and 3DES extend the key length, +and are still thought to be secure, modulo the limitation of a 64-bit block. +All are somewhat common in some industries such as finance. Avoid in new code. + +Available if ``BOTAN_HAS_DES`` is defined. + +GOST-28147-89 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A old 64-bit Russian cipher. Possible security issues. Avoid unless +compatibility is needed. + +Available if ``BOTAN_HAS_GOST_28147_89`` is defined. + +IDEA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An older but still unbroken 64-bit cipher with a 128-bit key. Somewhat common +due to its use in PGP. Avoid in new designs. + +Available if ``BOTAN_HAS_IDEA`` is defined. + +Kasumi +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 64-bit cipher used in 3GPP mobile phone protocols. There is no reason to use +it outside of this context. + +Available if ``BOTAN_HAS_KASUMI`` is defined. + +Lion +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A "block cipher construction" which can encrypt blocks of nearly arbitrary +length. Built from a stream cipher and a hash function. Useful in certain +protocols where being able to encrypt large or arbitrary length blocks is +necessary. + +Available if ``BOTAN_HAS_LION`` is defined. + +MISTY1 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 64-bit Japanese cipher standardized by NESSIE and ISO. Seemingly secure, but +quite slow and saw little adoption. No reason to use it in new code. The +implementation in Botan is deprecated, and it is likely to be removed in a +future release. + +Available if ``BOTAN_HAS_MISTY1`` is defined. + +Noekeon +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A fast 128-bit cipher by the designers of AES. Easily secured against side +channels. + +Available if ``BOTAN_HAS_NOEKEON`` is defined. + +SEED +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A older South Korean cipher, widely used in industry there. + +Available if ``BOTAN_HAS_SEED`` is defined. + +SHACAL2 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The 256-bit block cipher used inside SHA-256. Accepts up to a 512-bit key. +Fast, especially when SIMD or SHA-2 acceleration instructions are available. +Standardized by NESSIE but otherwise obscure. + +Available if ``BOTAN_HAS_SHACAL2`` is defined. + +SM4 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 128-bit Chinese national cipher, required for use in certain commercial +applications in China. Quite slow. Probably no reason to use it outside of legal +requirements. + +Available if ``BOTAN_HAS_SM4`` is defined. + +Serpent +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An AES contender. Widely considered the most conservative design. Fairly slow, +especially if no SIMD instruction set is available. + +Available if ``BOTAN_HAS_SERPENT`` is defined. + +Threefish-512 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 512-bit tweakable block cipher that was used in the Skein hash function. +Very fast on 64-bit processors. + +Available if ``BOTAN_HAS_THREEFISH_512`` is defined. + +Twofish +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An AES contender. Somewhat complicated key setup and a "kitchen sink" design. + +Available if ``BOTAN_HAS_TWOFISH`` is defined. + +XTEA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A 64-bit cipher popular for its simple implementation. Avoid in new code. + +Available if ``BOTAN_HAS_XTEA`` is defined. diff --git a/doc/api_ref/cipher_modes.rst b/doc/api_ref/cipher_modes.rst new file mode 100644 index 000000000..6e78a2c1b --- /dev/null +++ b/doc/api_ref/cipher_modes.rst @@ -0,0 +1,388 @@ +.. _cipher_modes: + +Cipher Modes +===================== + +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 to encrypt +an entire message. + +All cipher mode implementations are are derived from the base class +:cpp:class:`Cipher_Mode`, which is declared in ``botan/cipher_mode.h``. + +.. warning:: + Using an unauthenticted cipher mode without combining it with a + :ref:`mac` is insecure. Prefer using an :ref:`aead`. + +.. cpp:class:: Cipher_Mode + + .. cpp:function:: void set_key(const uint8_t* key, size_t length) + + Set the symmetric key to be used. + + .. 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 acceptable for the + algorithm. + + .. cpp:function:: size_t maximum_keylength() const + + Return the largest key length (in bytes) that is acceptable for the + algorithm. + + .. cpp:function:: size_t default_nonce_length() const + + Return the default (preferable) nonce size for this cipher mode. + + .. cpp:function:: bool valid_nonce_length(size_t nonce_len) const + + Return true if *nonce_len* is a valid length for a nonce with this + algorithm. + + .. cpp:function:: bool authenticated() const + + Return true if this cipher mode is authenticated + + .. cpp:function:: size_t tag_size() const + + Return the length in bytes of the authentication tag this algorithm + generates. If the mode is not authenticated, this will return 0. If the mode + is authenticated, it will return some positive value (typically somewhere + between 8 and 16). + + .. cpp:function:: void clear() + + Clear all internal state. The object will act exactly like one which was + just allocated. + + .. cpp:function:: void reset() + + Reset all message state. For example if you called :cpp:func:`start_msg`, + then :cpp:func:`process` to process some ciphertext, but then encounter an + IO error and must abandon the current message, you can call `reset`. The + object will retain the key (unlike calling :cpp:func:`clear` which also + resets the key) but the nonce and current message state will be erased. + + .. cpp:function:: void start_msg(const uint8_t* nonce, size_t nonce_len) + + Set up for processing a new message. This function must be called with a new + random value for each message. For almost all modes (excepting SIV), if the + same nonce is ever used twice with the same key, the encryption scheme loses + its confidentiality and/or authenticity properties. + + .. cpp:function:: void start(const std::vector<uint8_t> nonce) + + Acts like :cpp:func:`start_msg`\ (nonce.data(), nonce.size()). + + .. cpp:function:: void start(const uint8_t* 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(uint8_t* msg, size_t msg_len) + + Process msg in place and returns the number of bytes written. *msg* must + be a multiple of :cpp:func:`update_granularity`. + + .. cpp:function:: void update(secure_vector<uint8_t>& 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<uint8_t>& 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. + +Code Example +--------------------- + +The following code encrypts the specified plaintext using AES-128/CBC +with PKCS#7 padding. + +.. warning:: + This example ignores the requirement to authenticate the ciphertext + +.. note:: + Simply replacing the string "AES-128/CBC/PKCS7" string in the example below + with "AES-128/GCM" suffices to use authenticated encryption. + +.. 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() + { + Botan::AutoSeeded_RNG rng; + + const 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."); + const std::vector<uint8_t> key = Botan::hex_decode("2B7E151628AED2A6ABF7158809CF4F3C"); + + std::unique_ptr<Botan::Cipher_Mode> enc = Botan::Cipher_Mode::create("AES-128/CBC/PKCS7", Botan::ENCRYPTION); + enc->set_key(key); + + //generate fresh nonce (IV) + Botan::secure_vector<uint8_t> iv = rng.random_vec(enc->default_nonce_length()); + + // Copy input data to a buffer that will be encrypted + Botan::secure_vector<uint8_t> pt(plaintext.data(), plaintext.data()+plaintext.length()); + + enc->start(iv); + enc->finish(pt); + + std::cout << enc->name() << " with iv " << Botan::hex_encode(iv) << " " << Botan::hex_encode(pt) << "\n"; + return 0; + } + + +Available Unauthenticated Cipher Modes +----------------------------------------- + +.. note:: + CTR and OFB modes are also implemented, but these are treated as + :cpp:class:`Stream_Cipher`\s instead. + +CBC +~~~~~~~~~~~~ + +Available if ``BOTAN_HAS_MODE_CBC`` is defined. + +CBC requires the plaintext be padded using a reversible rule. The following +padding schemes are implemented + +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. +OneAndZeros (ISO/IEC 7816-4) + The first padding byte is set to 0x80, the remaining padding bytes are set to 0x00. + +Ciphertext stealing (CTS) is also implemented. This scheme allows the +ciphertext to have the same length as the plaintext, however using CTS +requires the input be at least one full block plus one byte. It is +also less commonly implemented. + +CFB +~~~~~~~~~~~~ + +Available if ``BOTAN_HAS_MODE_CFB`` is defined. + +CFB uses a block cipher to create a self-synchronizing stream cipher. It is used +for example in the OpenPGP protocol. There is no reason to prefer it, as it has +worse performance characteristics than modes such as CTR or CBC. + +XTS +~~~~~~~~~ + +Available if ``BOTAN_HAS_MODE_XTS`` is defined. + +XTS is a mode specialized for encrypting disk or database storage +where ciphertext expansion is not possible. XTS requires all inputs be +at least one full block (16 bytes for AES), however for any acceptable +input length, there is no ciphertext expansion. + +.. _aead: + +AEAD Mode +--------------------------- + +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:`Cipher_Mode`. + +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). + +.. 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 uint8_t 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 uint8_t nonce[], size_t nonce_len) + + Start processing a message, using *nonce* as the unique per-message + value. It does not need to be random, simply unique (per key). + + .. warning:: + With almost all AEADs, if the same nonce is ever used to encrypt two + different messages under the same key, all security is lost. If + reliably generating unique nonces is difficult in your environment, + use SIV mode which retains security even if nonces are repeated. + + .. cpp:function:: void update(secure_vector<uint8_t>& 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<uint8_t>& 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, if the supplied authentication tag does not + validate, finish will throw an instance of Invalid_Authentication_Tag + (aka Integrity_Failure, which was the name for this exception in + versions before 2.10, a typedef is included for compatability). + + 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. This could be anything from echoing the + plaintext back (perhaps in an error message), or by making an external + RPC whose destination or contents depend on the plaintext. The only + thing you can do is buffer it, and in the event of an invalid tag, + erase the previously decrypted content from memory. + + One simply way to assure this could never happen is to never + call update, and instead always marshal 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. + + +Available AEAD Modes +------------------------- + +If in doubt about what to use, pick ChaCha20Poly1305, AES-256/GCM, or AES-256/SIV. +Both ChaCha20Poly1305 and AES with GCM are widely implemented. SIV is somewhat +more obscure (and is slower than either GCM or ChaCha20Poly1305), but has +excellent security properties. + +ChaCha20Poly1305 +~~~~~~~~~~~~~~~~~~ + +Available if ``BOTAN_HAS_AEAD_CHACHA20_POLY1305`` is defined. + +Unlike the other AEADs which are based on block ciphers, this mode is based on +the ChaCha stream cipher and the Poly1305 authentication code. It is very fast +on all modern platforms. + +ChaCha20Poly1305 supports 64-bit, 96-bit, and (since 2.8) 192-bit nonces. 64-bit nonces +are the "classic" ChaCha20Poly1305 design. 96-bit nonces are used by the IETF standard +version of ChaCha20Poly1305. And 192-bit nonces is the XChaCha20Poly1305 construction, +which is somewhat less common. + +For best interop use the IETF version with 96-bit nonces. However 96 bits is small enough +that it can be dangerous to generate nonces randomly if more than ~ 2^32 messages are +encrypted under a single key, since if a nonce is ever reused ChaCha20Poly1305 becomes +insecure. It is better to use a counter for the nonce in this case. + +If you are encrypting many messages under a single key and cannot maintain a counter for +the nonce, prefer XChaCha20Poly1305 since a 192 bit nonce is large enough that randomly +chosen nonces are extremely unlikely to repeat. + +GCM +~~~~~ + +Available if ``BOTAN_HAS_AEAD_GCM`` is defined. + +NIST standard, commonly used. Requires a 128-bit block cipher. Fairly slow, +unless hardware support for carryless multiplies is available. + +OCB +~~~~~ + +Available if ``BOTAN_HAS_AEAD_OCB`` is defined. + +A block cipher based AEAD. Supports 128-bit, 256-bit and 512-bit block ciphers. +This mode is very fast and easily secured against side channels. Adoption has +been poor because it is patented in the United States, though a license is +available allowing it to be freely used by open source software. + +EAX +~~~~~ + +Available if ``BOTAN_HAS_AEAD_EAX`` is defined. + +A secure composition of CTR mode and CMAC. Supports 128-bit, 256-bit and 512-bit +block ciphers. + +SIV +~~~~~~ + +Available if ``BOTAN_HAS_AEAD_SIV`` is defined. + +Requires a 128-bit block cipher. Unlike other AEADs, SIV is "misuse resistant"; +if a nonce is repeated, SIV retains security, with the exception that if the +same nonce is used to encrypt the same message multiple times, an attacker can +detect the fact that the message was duplicated (this is simply because if both +the nonce and the message are reused, SIV will output identical ciphertexts). + +CCM +~~~~~ + +Available if ``BOTAN_HAS_AEAD_CCM`` is defined. + +A composition of CTR mode and CBC-MAC. Requires a 128-bit block cipher. This is +a NIST standard mode, but that is about all to recommend it. Prefer EAX. diff --git a/doc/api_ref/compression.rst b/doc/api_ref/compression.rst new file mode 100644 index 000000000..5637a5a68 --- /dev/null +++ b/doc/api_ref/compression.rst @@ -0,0 +1,90 @@ +Lossless Data Compression +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some lossless data compression algorithms are available in botan, currently all +via third party libraries - these include zlib (including deflate and gzip +formats), bzip2, and lzma. Support for these must be enabled at build time; +you can check for them using the macros ``BOTAN_HAS_ZLIB``, ``BOTAN_HAS_BZIP2``, +and ``BOTAN_HAS_LZMA``. + +.. note:: + You should always compress *before* you encrypt, because encryption seeks to + hide the redundancy that compression is supposed to try to find and remove. + +Compression is done through the ``Compression_Algorithm`` and +``Decompression_Algorithm`` classes, both defined in `compression.h` + +Compression and decompression both work in three stages: starting a +message (``start``), continuing to process it (``update``), and then +finally completing processing the stream (``finish``). + +.. cpp:class:: Compression_Algorithm + + .. cpp:function:: void start(size_t level) + + Initialize the compression engine. This must be done before calling + ``update`` or ``finish``. The meaning of the `level` parameter varies by + the algorithm but generally takes a value between 1 and 9, with higher + values implying typically better compression from and more memory and/or + CPU time consumed by the compression process. The decompressor can always + handle input from any compressor. + + .. cpp:function:: void update(secure_vector<uint8_t>& buf, \ + size_t offset = 0, bool flush = false) + + Compress the material in the in/out parameter ``buf``. The leading + ``offset`` bytes of ``buf`` are ignored and remain untouched; this can be + useful for ignoring packet headers. If ``flush`` is true, the + compression state is flushed, allowing the decompressor to recover the + entire message up to this point without having the see the rest of the + compressed stream. + + .. cpp::function:: void finish(secure_vector<uint8_t>& buf, size_t offset = 0) + + Finish compressing a message. The ``buf`` and ``offset`` parameters are + treated as in ``update``. It is acceptable to call ``start`` followed by + ``finish`` with the entire message, without any intervening call to + ``update``. + +.. cpp:class:: Decompression_Algorithm + + .. cpp:function:: void start() + + Initialize the decompression engine. This must be done before calling + ``update`` or ``finish``. No level is provided here; the decompressor + can accept input generated by any compression parameters. + + .. cpp:function:: void update(secure_vector<uint8_t>& buf, \ + size_t offset = 0) + + Decompress the material in the in/out parameter ``buf``. The leading + ``offset`` bytes of ``buf`` are ignored and remain untouched; this can be + useful for ignoring packet headers. + + This function may throw if the data seems to be invalid. + + .. cpp::function:: void finish(secure_vector<uint8_t>& buf, size_t offset = 0) + + Finish decompressing a message. The ``buf`` and ``offset`` parameters are + treated as in ``update``. It is acceptable to call ``start`` followed by + ``finish`` with the entire message, without any intervening call to + ``update``. + + This function may throw if the data seems to be invalid. + +The easiest way to get a compressor is via the functions + +.. cpp:function:: Compression_Algorithm* make_compressor(std::string type) +.. cpp:function:: Decompression_Algorithm* make_decompressor(std::string type) + +Supported values for `type` include `zlib` (raw zlib with no checksum), +`deflate` (zlib's deflate format), `gzip`, `bz2`, and `lzma`. A null pointer +will be returned if the algorithm is unavailable. + +To use a compression algorithm in a `Pipe` use the adapter types +`Compression_Filter` and `Decompression_Filter` from `comp_filter.h`. The +constructors of both filters take a `std::string` argument (passed to +`make_compressor` or `make_decompressor`), the compression filter also takes a +`level` parameter. Finally both constructors have a parameter `buf_sz` which +specifies the size of the internal buffer that will be used - inputs will be +broken into blocks of this size. The default is 4096. diff --git a/doc/api_ref/contents.rst b/doc/api_ref/contents.rst new file mode 100644 index 000000000..2cdfbc4d9 --- /dev/null +++ b/doc/api_ref/contents.rst @@ -0,0 +1,37 @@ + +API Reference +=================== + +.. toctree:: + :maxdepth: 1 + + versions + secmem + rng + hash + block_cipher + stream_ciphers + message_auth_codes + cipher_modes + pubkey + x509 + tls + credentials_manager + bigint + kdf + pbkdf + keywrap + passhash + cryptobox + srp + psk_db + filters + fpe + tss + ecc + compression + pkcs11 + tpm + otp + ffi + python diff --git a/doc/api_ref/credentials_manager.rst b/doc/api_ref/credentials_manager.rst new file mode 100644 index 000000000..bc18c5d8e --- /dev/null +++ b/doc/api_ref/credentials_manager.rst @@ -0,0 +1,148 @@ + +Credentials Manager +================================================== + +A ``Credentials_Manager`` is a way to abstract how the application +stores credentials in a way that is usable by protocol +implementations. Currently the main user is the :doc:`tls` +implementation. + +.. cpp:class:: Credentials_Manager + + .. cpp:function:: std::vector<X509_Certificate> \ + trusted_certificate_authorities( \ + const std::string& type, \ + const std::string& context) + + Return the list of trusted certificate authorities. + + When *type* is "tls-client", *context* will be the hostname of + the server, or empty if the hostname is not known. + + When *type* is "tls-server", the *context* will again be the + hostname of the server, or empty if the client did not send a + server name indicator. For TLS servers, these CAs are the ones + trusted for signing of client certificates. If you do not want + the TLS server to ask for a client cert, + ``trusted_certificate_authorities`` should return an empty list + for *type* "tls-server". + + The default implementation returns an empty list. + + .. cpp:function:: std::vector<X509_Certificate> find_cert_chain( \ + const std::vector<std::string>& cert_key_types, \ + const std::vector<X509_DN>& acceptable_CAs, \ + const std::string& type, \ + const std::string& context) + + Return the certificate chain to use to identify ourselves. The + ``acceptable_CAs`` parameter gives a list of CAs the peer trusts. + This may be empty. + + .. cpp:function:: std::vector<X509_Certificate> cert_chain( \ + const std::vector<std::string>& cert_key_types, \ + const std::string& type, \ + const std::string& context) + + Return the certificate chain to use to identify ourselves. Starting in + 2.5, prefer ``find_cert_chain`` which additionally provides the CA list. + + .. cpp:function:: std::vector<X509_Certificate> cert_chain_single_type( \ + const std::string& cert_key_type, \ + const std::string& type, \ + const std::string& context) + + Return the certificate chain to use to identifier ourselves, if + we have one of type *cert_key_type* and we would like to use a + certificate in this *type*/*context*. + + .. cpp:function:: Private_Key* private_key_for(const X509_Certificate& cert, \ + const std::string& type, \ + const std::string& context) + + Return the private key for this certificate. The *cert* will be + the leaf cert of a chain returned previously by ``cert_chain`` + or ``cert_chain_single_type``. + +In versions before 1.11.34, there was an additional function on `Credentials_Manager` + + .. cpp::function:: void verify_certificate_chain( \ + const std::string& type, \ + const std::string& hostname, \ + const std::vector<X509_Certificate>& cert_chain) + +This function has been replaced by `TLS::Callbacks::tls_verify_cert_chain`. + +SRP Authentication +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +``Credentials_Manager`` contains the hooks used by TLS clients and +servers for SRP authentication. + +.. cpp:function:: bool attempt_srp(const std::string& type, \ + const std::string& context) + + Returns if we should consider using SRP for authentication + +.. cpp:function:: std::string srp_identifier(const std::string& type, \ + const std::string& context) + + Returns the SRP identifier we'd like to use (used by client) + +.. cpp:function:: std::string srp_password(const std::string& type, \ + const std::string& context, \ + const std::string& identifier) + + Returns the password for *identifier* (used by client) + +.. cpp:function:: bool srp_verifier(const std::string& type, \ + const std::string& context, \ + const std::string& identifier, \ + std::string& group_name, \ + BigInt& verifier, \ + std::vector<uint8_t>& salt, \ + bool generate_fake_on_unknown) + + Returns the SRP verifier information for *identifier* (used by server) + +Preshared Keys +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +TLS and some other protocols support the use of pre shared keys for +authentication. + +.. cpp:function:: SymmetricKey psk(const std::string& type, \ + const std::string& context, \ + const std::string& identity) + + Return a symmetric key for use with *identity* + + One important special case for ``psk`` is where *type* is + "tls-server", *context* is "session-ticket" and *identity* is an + empty string. If a key is returned for this case, a TLS server + will offer session tickets to clients who can use them, and the + returned key will be used to encrypt the ticket. The server is + allowed to change the key at any time (though changing the key + means old session tickets can no longer be used for resumption, + forcing a full re-handshake when the client next connects). One + simple approach to add support for session tickets in your server + is to generate a random key the first time ``psk`` is called to + retrieve the session ticket key, cache it for later use in the + ``Credentials_Manager``, and simply let it be thrown away when the + process terminates. + + See :rfc:`4507` for more information about TLS session tickets. + +.. cpp:function:: std::string psk_identity_hint(const std::string& type, \ + const std::string& context) + + Returns an identity hint which may be provided to the client. This + can help a client understand what PSK to use. + +.. cpp:function:: std::string psk_identity(const std::string& type, \ + const std::string& context, \ + const std::string& identity_hint) + + Returns the identity we would like to use given this *type* and + *context* and the optional *identity_hint*. Not all servers or + protocols will provide a hint. diff --git a/doc/api_ref/cryptobox.rst b/doc/api_ref/cryptobox.rst new file mode 100644 index 000000000..dbade88af --- /dev/null +++ b/doc/api_ref/cryptobox.rst @@ -0,0 +1,32 @@ + +Cryptobox +======================================== + +Encryption using a passphrase +---------------------------------------- + +.. versionadded:: 1.8.6 + +This is a set of simple routines that encrypt some data using a +passphrase. There are defined in the header `cryptobox.h`, inside +namespace `Botan::CryptoBox`. + +It generates cipher and MAC keys using 8192 iterations of PBKDF2 with +HMAC(SHA-512), then encrypts using Serpent in CTR mode and authenticates using a +HMAC(SHA-512) mac of the ciphertext, truncated to 160 bits. + + .. cpp:function:: std::string encrypt(const uint8_t input[], size_t input_len, \ + const std::string& passphrase, \ + RandomNumberGenerator& rng) + + Encrypt the contents using *passphrase*. + + .. cpp:function:: std::string decrypt(const uint8_t input[], size_t input_len, \ + const std::string& passphrase) + + Decrypts something encrypted with encrypt. + + .. cpp:function:: std::string decrypt(const std::string& input, \ + const std::string& passphrase) + + Decrypts something encrypted with encrypt. diff --git a/doc/api_ref/ecc.rst b/doc/api_ref/ecc.rst new file mode 100644 index 000000000..f522bbe3d --- /dev/null +++ b/doc/api_ref/ecc.rst @@ -0,0 +1,284 @@ +Elliptic Curve Operations +============================ + +In addition to high level operations for signatures, key agreement, +and message encryption using elliptic curve cryptography, the library +contains lower level interfaces for performing operations such as +elliptic curve point multiplication. + +Only curves over prime fields are supported. + +Many of these functions take a workspace, either a vector of words or +a vector of BigInts. These are used to minimize memory allocations +during common operations. + +.. warning:: + You should only use these interfaces if you know what you are doing. + +.. cpp:class:: EC_Group + + .. cpp:function:: EC_Group(const OID& oid) + + Initialize an ``EC_Group`` using an OID referencing the curve + parameters. + + .. cpp:function:: EC_Group(const std::string& name) + + Initialize an ``EC_Group`` using a name or OID (for example + "secp256r1", or "1.2.840.10045.3.1.7") + + .. cpp:function:: EC_Group(const BigInt& p, \ + const BigInt& a, \ + const BigInt& b, \ + const BigInt& base_x, \ + const BigInt& base_y, \ + const BigInt& order, \ + const BigInt& cofactor, \ + const OID& oid = OID()) + + Initialize an elliptic curve group from the relevant parameters. This + is used for example to create custom (application-specific) curves. + + .. cpp:function:: EC_Group(const std::vector<uint8_t>& ber_encoding) + + Initialize an ``EC_Group`` by decoding a DER encoded parameter block. + + .. cpp:function:: std::vector<uint8_t> DER_encode(EC_Group_Encoding form) const + + Return the DER encoding of this group. + + .. cpp:function:: std::string PEM_encode() const + + Return the PEM encoding of this group (base64 of DER encoding plus + header/trailer). + + .. cpp:function:: bool a_is_minus_3() const + + Return true if the ``a`` parameter is congruent to -3 mod p. + + .. cpp:function:: bool a_is_zero() const + + Return true if the ``a`` parameter is congruent to 0 mod p. + + .. cpp:function:: size_t get_p_bits() const + + Return size of the prime in bits. + + .. cpp:function:: size_t get_p_bytes() const + + Return size of the prime in bytes. + + .. cpp:function:: size_t get_order_bits() const + + Return size of the group order in bits. + + .. cpp:function:: size_t get_order_bytes() const + + Return size of the group order in bytes. + + .. cpp:function:: const BigInt& get_p() const + + Return the prime modulus. + + .. cpp:function:: const BigInt& get_a() const + + Return the ``a`` parameter of the elliptic curve equation. + + .. cpp:function:: const BigInt& get_b() const + + Return the ``b`` parameter of the elliptic curve equation. + + .. cpp:function:: const PointGFp& get_base_point() const + + Return the groups base point element. + + .. cpp:function:: const BigInt& get_g_x() const + + Return the x coordinate of the base point element. + + .. cpp:function:: const BigInt& get_g_y() const + + Return the y coordinate of the base point element. + + .. cpp:function:: const BigInt& get_order() const + + Return the order of the group generated by the base point. + + .. cpp:function:: const BigInt& get_cofactor() const + + Return the cofactor of the curve. In most cases this will be 1. + + .. cpp:function:: BigInt mod_order(const BigInt& x) const + + Reduce argument ``x`` modulo the curve order. + + .. cpp:function:: BigInt inverse_mod_order(const BigInt& x) const + + Return inverse of argument ``x`` modulo the curve order. + + .. cpp:function:: BigInt multiply_mod_order(const BigInt& x, const BigInt& y) const + + Multiply ``x`` and ``y`` and reduce the result modulo the curve order. + + .. cpp:function:: bool verify_public_element(const PointGFp& y) const + + Return true if ``y`` seems to be a valid group element. + + .. cpp:function:: const OID& get_curve_oid() const + + Return the OID used to identify the curve. May be empty. + + .. cpp:function:: PointGFp point(const BigInt& x, const BigInt& y) const + + Create and return a point with affine elements ``x`` and ``y``. Note + this function *does not* verify that ``x`` and ``y`` satisfy the curve + equation. + + .. cpp:function:: PointGFp point_multiply(const BigInt& x, const PointGFp& pt, const BigInt& y) const + + Multi-exponentiation. Returns base_point*x + pt*y. Not constant time. + (Ordinarily used for signature verification.) + + .. cpp:function:: PointGFp blinded_base_point_multiply(const BigInt& k, \ + RandomNumberGenerator& rng, \ + std::vector<BigInt>& ws) const + + Return ``base_point*k`` in a way that attempts to resist side channels. + + .. cpp:function:: BigInt blinded_base_point_multiply_x(const BigInt& k, \ + RandomNumberGenerator& rng, \ + std::vector<BigInt>& ws) const + + Like `blinded_base_point_multiply` but returns only the x coordinate. + + .. cpp:function:: PointGFp blinded_var_point_multiply(const PointGFp& point, \ + const BigInt& k, \ + RandomNumberGenerator& rng, \ + std::vector<BigInt>& ws) const + + Return ``point*k`` in a way that attempts to resist side channels. + + .. cpp:function:: BigInt random_scalar(RandomNumberGenerator& rng) const + + Return a random scalar (ie an integer between 1 and the group order). + + .. cpp:function:: PointGFp zero_point() const + + Return the zero point (aka the point at infinity). + + .. cpp:function:: PointGFp OS2ECP(const uint8_t bits[], size_t len) const + + Decode a point from the binary encoding. This function verifies that + the decoded point is a valid element on the curve. + + .. cpp:function:: bool verify_group(RandomNumberGenerator& rng, bool strong = false) const + + Attempt to verify the group seems valid. + + .. cpp:function:: static const std::set<std::string>& known_named_groups() + + Return a list of known groups, ie groups for which ``EC_Group(name)`` + will succeed. + +.. cpp:class:: PointGFp + + Stores elliptic curve points in Jacobian representation. + + .. cpp:function:: std::vector<uint8_t> encode(PointGFp::Compression_Type format) const + + Encode a point in a way that can later be decoded with `EC_Group::OS2ECP`. + + .. cpp:function:: PointGFp& operator+=(const PointGFp& rhs) + + Point addition. + + .. cpp:function:: PointGFp& operator-=(const PointGFp& rhs) + + Point subtraction. + + .. cpp:function:: PointGFp& operator*=(const BigInt& scalar) + + Point multiplication using Montgomery ladder. + + .. warning:: + Prefer the blinded functions in ``EC_Group`` + + .. cpp:function:: PointGFp& negate() + + Negate this point. + + .. cpp:function:: BigInt get_affine_x() const + + Return the affine ``x`` coordinate of the point. + + .. cpp:function:: BigInt get_affine_y() const + + Return the affine ``y`` coordinate of the point. + + .. cpp:function:: void force_affine() + + Convert the point to its equivalent affine coordinates. Throws + if this is the point at infinity. + + .. cpp:function:: static void force_all_affine(std::vector<PointGFp>& points, \ + secure_vector<word>& ws) + + Force several points to be affine at once. Uses Montgomery's + trick to reduce number of inversions required, so this is much + faster than calling ``force_affine`` on each point in sequence. + + .. cpp:function:: bool is_affine() const + + Return true if this point is in affine coordinates. + + .. cpp:function:: bool is_zero() const + + Return true if this point is zero (aka point at infinity). + + .. cpp:function:: bool on_the_curve() const + + Return true if this point is on the curve. + + .. cpp:function:: void randomize_repr(RandomNumberGenerator& rng) + + Randomize the point representation. + + .. cpp:function:: bool operator==(const PointGFp& other) const + + Point equality. This compares the affine representations. + + .. cpp:function:: void add(const PointGFp& other, std::vector<BigInt>& workspace) + + Point addition, taking a workspace. + + .. cpp:function:: void add_affine(const PointGFp& other, std::vector<BigInt>& workspace) + + Mixed (Jacobian+affine) addition, taking a workspace. + + .. warning:: + + This function assumes that ``other`` is affine, if this is + not correct the result will be invalid. + + .. cpp:function:: void mult2(std::vector<BigInt>& workspace) + + Point doubling. + + .. cpp:function:: void mult2i(size_t i, std::vector<BigInt>& workspace) + + Repeated point doubling. + + .. cpp:function:: PointGFp plus(const PointGFp& other, std::vector<BigInt>& workspace) const + + Point addition, returning the result. + + .. cpp:function:: PointGFp double_of(std::vector<BigInt>& workspace) const + + Point doubling, returning the result. + + .. cpp:function:: PointGFp zero() const + + Return the point at infinity + + + diff --git a/doc/api_ref/ffi.rst b/doc/api_ref/ffi.rst new file mode 100644 index 000000000..84f729837 --- /dev/null +++ b/doc/api_ref/ffi.rst @@ -0,0 +1,1140 @@ + +FFI (C Binding) +======================================== + +.. versionadded:: 1.11.14 + +Botan's ffi module provides a C89 binding intended to be easily usable with other +language's foreign function interface (FFI) libraries. For instance the included +Python wrapper uses Python's ``ctypes`` module and the C89 API. This API is of +course also useful for programs written directly in C. + +Code examples can be found in +`the tests <https://github.com/randombit/botan/blob/master/src/tests/test_ffi.cpp>`_. + +Return Codes +--------------- + +Almost all functions in the Botan C interface return an ``int`` error code. The +only exceptions are a handful of functions (like +:cpp:func:`botan_ffi_api_version`) which cannot fail in any circumstances. + +The FFI functions return a non-negative integer (usually 0) to indicate success, +or a negative integer to represent an error. A few functions (like +:cpp:func:`botan_block_cipher_block_size`) return positive integers instead of +zero on success. + +The error codes returned in certain error situations may change over time. This +especially applies to very generic errors like +:cpp:enumerator:`BOTAN_FFI_ERROR_EXCEPTION_THROWN` and +:cpp:enumerator:`BOTAN_FFI_ERROR_UNKNOWN_ERROR`. For instance, before 2.8, setting +an invalid key length resulted in :cpp:enumerator:`BOTAN_FFI_ERROR_EXCEPTION_THROWN` +but now this is specially handled and returns +:cpp:enumerator:`BOTAN_FFI_ERROR_INVALID_KEY_LENGTH` instead. + +The following enum values are defined in the FFI header: + +.. cpp:enumerator:: BOTAN_FFI_SUCCESS = 0 + + Generally returned to indicate success + +.. cpp:enumerator:: BOTAN_FFI_INVALID_VERIFIER = 1 + + Note this value is positive, but still represents an error condition. In + indicates that the function completed successfully, but the value provided + was not correct. For example :cpp:func:`botan_bcrypt_is_valid` returns this + value if the password did not match the hash. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_INVALID_INPUT = -1 + + The input was invalid. (Currently this error return is not used.) + +.. cpp:enumerator:: BOTAN_FFI_ERROR_BAD_MAC = -2 + + While decrypting in an AEAD mode, the tag failed to verify. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE = -10 + + Functions which write a variable amount of space return this if the indicated + buffer length was insufficient to write the data. In that case, the output + length parameter is set to the size that is required. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_EXCEPTION_THROWN = -20 + + An exception was thrown while processing this request, but no further + details are available. + + .. note:: + + If the environment variable ``BOTAN_FFI_PRINT_EXCEPTIONS`` is + set, then any exception which is caught by the FFI layer will + first print the exception message to stderr before returning an + error. This is sometimes useful for debugging. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_OUT_OF_MEMORY = -21 + + Memory allocation failed + +.. cpp:enumerator:: BOTAN_FFI_ERROR_BAD_FLAG = -30 + + A value provided in a `flag` variable was unknown. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_NULL_POINTER = -31 + + A null pointer was provided as an argument where that is not allowed. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_BAD_PARAMETER = -32 + + An argument did not match the function. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_KEY_NOT_SET = -33 + + An object that requires a key normally must be keyed before use (eg before + encrypting or MACing data). If this is not done, the operation will fail and + return this error code. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_INVALID_KEY_LENGTH = -34 + + An invalid key length was provided with a call to ``x_set_key``. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_NOT_IMPLEMENTED = -40 + + This is returned if the functionality is not available for some reason. For + example if you call :cpp:func:`botan_hash_init` with a named hash function + which is not enabled, this error is returned. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_INVALID_OBJECT = -50 + + This is used if an object provided did not match the function. For example + calling :cpp:func:`botan_hash_destroy` on a ``botan_rng_t`` object will cause + this return. + +.. cpp:enumerator:: BOTAN_FFI_ERROR_UNKNOWN_ERROR = -100 + + Something bad happened, but we are not sure why or how. + +Versioning +---------------------------------------- + +.. cpp:function:: uint32_t botan_ffi_api_version() + + Returns the version of the currently supported FFI API. This is + expressed in the form YYYYMMDD of the release date of this version + of the API. + +.. cpp:function:: int botan_ffi_supports_api(uint32_t version) + + Returns 0 iff the FFI version specified is supported by this + library. Otherwise returns -1. The expression + botan_ffi_supports_api(botan_ffi_api_version()) will always + evaluate to 0. A particular version of the library may also support + other (older) versions of the FFI API. + +.. cpp:function:: const char* botan_version_string() + + Returns a free-form string describing the version. The return + value is a statically allocated string. + +.. cpp:function:: uint32_t botan_version_major() + + Returns the major version of the library + +.. cpp:function:: uint32_t botan_version_minor() + + Returns the minor version of the library + +.. cpp:function:: uint32_t botan_version_patch() + + Returns the patch version of the library + +.. cpp:function:: uint32_t botan_version_datestamp() + + Returns the date this version was released as an integer YYYYMMDD, + or 0 if an unreleased version + + +FFI Versions +^^^^^^^^^^^^^ + +This maps the FFI API version to the first version of the library that +supported it. + +============== =================== +FFI Version Supported Starting +============== =================== +20180713 2.8.0 +20170815 2.3.0 +20170327 2.1.0 +20150515 2.0.0 +============== =================== + +Utility Functions +---------------------------------------- + +.. const char* botan_error_description(int err) + + Return a string representation of the provided error code. If the error code + is unknown, returns the string "Unknown error". The return values are static + constant strings and should not be freed. + +.. cpp:function:: int botan_same_mem(const uint8_t* x, const uint8_t* y, size_t len) + + Returns 0 if `x[0..len] == y[0..len]`, -1 otherwise. + +.. cpp:function:: int botan_hex_encode(const uint8_t* x, size_t len, char* out, uint32_t flags) + + Performs hex encoding of binary data in *x* of size *len* bytes. + The output buffer *out* must be of at least *x*2* bytes in size. + If *flags* contains ``BOTAN_FFI_HEX_LOWER_CASE``, hex encoding + will only contain lower-case letters, upper-case letters otherwise. + Returns 0 on success, 1 otherwise. + +.. cpp:function:: int botan_hex_decode(const char* hex_str, size_t in_len, uint8_t* out, size_t* out_len) + + Hex decode some data + +Random Number Generators +---------------------------------------- + +.. cpp:type:: opaque* botan_rng_t + + An opaque data type for a random number generator. Don't mess with it. + +.. cpp:function:: int botan_rng_init(botan_rng_t* rng, const char* rng_type) + + Initialize a random number generator object from the given + *rng_type*: "system" (or ``nullptr``): ``System_RNG``, + "user": ``AutoSeeded_RNG``, + "user-threadsafe": serialized ``AutoSeeded_RNG``, + "null": ``Null_RNG`` (always fails), + "rdrand": ``RDRAND_RNG`` (if available) + +.. cpp:function:: int botan_rng_get(botan_rng_t rng, uint8_t* out, size_t out_len) + + Get random bytes from a random number generator. + +.. cpp:function:: int botan_rng_reseed(botan_rng_t rng, size_t bits) + + Reseeds the random number generator with *bits* number of bits + from the `System_RNG`. + +.. cpp:function:: int botan_rng_reseed_from_rng(botan_rng_t rng, botan_rng_t src, size_t bits) + + Reseeds the random number generator with *bits* number of bits + taken from the given source RNG. + +.. cpp:function:: int botan_rng_add_entropy(botan_rng_t rng, const uint8_t seed[], size_t len) + + Adds the provided seed material to the internal RNG state. + + This call may be ignored by certain RNG instances (such as RDRAND + or, on some systems, the system RNG). + +.. cpp:function:: int botan_rng_destroy(botan_rng_t rng) + + Destroy the object created by :cpp:func:`botan_rng_init`. + +Block Ciphers +---------------------------------------- + +.. versionadded:: 2.1.0 + +This is a 'raw' interface to ECB mode block ciphers. Most applications +want the higher level cipher API which provides authenticated +encryption. This API exists as an escape hatch for applications which +need to implement custom primitives using a PRP. + +.. cpp:type:: opaque* botan_block_cipher_t + + An opaque data type for a block cipher. Don't mess with it. + +.. cpp:function:: int botan_block_cipher_init(botan_block_cipher_t* bc, const char* cipher_name) + + Create a new cipher mode object, `cipher_name` should be for example "AES-128" or "Threefish-512" + +.. cpp:function:: int botan_block_cipher_block_size(botan_block_cipher_t bc) + + Return the block size of this cipher. + +.. cpp:function:: int botan_block_cipher_name(botan_block_cipher_t cipher, \ + char* name, size_t* name_len) + + Return the name of this block cipher algorithm, which may nor may not exactly + match what was passed to :cpp:func:`botan_block_cipher_init`. + +.. cpp:function:: int botan_block_cipher_get_keyspec(botan_block_cipher_t cipher, \ + size_t* out_minimum_keylength, \ + size_t* out_maximum_keylength, \ + size_t* out_keylength_modulo) + + Return the limits on the key which can be provided to this cipher. If any of the + parameters are null, no output is written to that field. This allows retrieving only + (say) the maximum supported keylength, if that is the only information needed. + +.. cpp:function:: int botan_block_cipher_clear(botan_block_cipher_t bc) + + Clear the internal state (such as keys) of this cipher object, but do not deallocate it. + +.. cpp:function:: int botan_block_cipher_set_key(botan_block_cipher_t bc, const uint8_t key[], size_t key_len) + + Set the cipher key, which is required before encrypting or decrypting. + +.. cpp:function:: int botan_block_cipher_encrypt_blocks(botan_block_cipher_t bc, const uint8_t in[], uint8_t out[], size_t blocks) + + The key must have been set first with :cpp:func:`botan_block_cipher_set_key`. + Encrypt *blocks* blocks of data stored in *in* and place the ciphertext into *out*. + The two parameters may be the same buffer, but must not overlap. + +.. cpp:function:: int botan_block_cipher_decrypt_blocks(botan_block_cipher_t bc, const uint8_t in[], uint8_t out[], size_t blocks) + + The key must have been set first with :cpp:func:`botan_block_cipher_set_key`. + Decrypt *blocks* blocks of data stored in *in* and place the ciphertext into *out*. + The two parameters may be the same buffer, but must not overlap. + +.. cpp:function:: int botan_block_cipher_destroy(botan_block_cipher_t rng) + + Destroy the object created by :cpp:func:`botan_block_cipher_init`. + + +Hash Functions +---------------------------------------- + +.. cpp:type:: opaque* botan_hash_t + + An opaque data type for a hash. Don't mess with it. + +.. cpp:function:: botan_hash_t botan_hash_init(const char* hash, uint32_t flags) + + Creates a hash of the given name, e.g., "SHA-384". + Returns null on failure. Flags should always be zero in this version of the API. + +.. cpp:function:: int botan_hash_destroy(botan_hash_t hash) + + Destroy the object created by :cpp:func:`botan_hash_init`. + +.. cpp:function:: int botan_hash_name(botan_hash_t hash, char* name, size_t* name_len) + + Write the name of the hash function to the provided buffer. + +.. cpp:function:: int botan_hash_copy_state(botan_hash_t* dest, const botan_hash_t source) + + Copies the state of the hash object to a new hash object. + +.. cpp:function:: int botan_hash_clear(botan_hash_t hash) + + Reset the state of this object back to clean, as if no input has + been supplied. + +.. cpp:function:: size_t botan_hash_output_length(botan_hash_t hash) + + Return the output length of the hash function. + +.. cpp:function:: int botan_hash_update(botan_hash_t hash, const uint8_t* input, size_t len) + + Add input to the hash computation. + +.. cpp:function:: int botan_hash_final(botan_hash_t hash, uint8_t out[]) + + Finalize the hash and place the output in out. Exactly + :cpp:func:`botan_hash_output_length` bytes will be written. + +Message Authentication Codes +---------------------------------------- +.. cpp:type:: opaque* botan_mac_t + + An opaque data type for a MAC. Don't mess with it, but do remember + to set a random key first. + +.. cpp:function:: botan_mac_t botan_mac_init(const char* mac, uint32_t flags) + + Creates a MAC of the given name, e.g., "HMAC(SHA-384)". + Returns null on failure. Flags should always be zero in this version of the API. + +.. cpp:function:: int botan_mac_destroy(botan_mac_t mac) + + Destroy the object created by :cpp:func:`botan_mac_init`. + +.. cpp:function:: int botan_mac_clear(botan_mac_t mac) + + Reset the state of this object back to clean, as if no key and input have + been supplied. + +.. cpp:function:: size_t botan_mac_output_length(botan_mac_t mac) + + Return the output length of the MAC. + +.. cpp:function:: int botan_mac_set_key(botan_mac_t mac, const uint8_t* key, size_t key_len) + + Set the random key. + +.. cpp:function:: int botan_mac_update(botan_mac_t mac, uint8_t buf[], size_t len) + + Add input to the MAC computation. + +.. cpp:function:: int botan_mac_final(botan_mac_t mac, uint8_t out[], size_t* out_len) + + Finalize the MAC and place the output in out. Exactly + :cpp:func:`botan_mac_output_length` bytes will be written. + +Symmetric Ciphers +---------------------------------------- + +.. cpp:type:: opaque* botan_cipher_t + + An opaque data type for a symmetric cipher object. Don't mess with it, but do remember + to set a random key first. And please use an AEAD. + +.. cpp:function:: botan_cipher_t botan_cipher_init(const char* cipher_name, uint32_t flags) + + Create a cipher object from a name such as "AES-256/GCM" or "Serpent/OCB". + + Flags is a bitfield; the low bitof ``flags`` specifies if encrypt or decrypt, + ie use 0 for encryption and 1 for decryption. + +.. cpp:function:: int botan_cipher_destroy(botan_cipher_t cipher) + +.. cpp:function:: int botan_cipher_clear(botan_cipher_t hash) + +.. cpp:function:: int botan_cipher_set_key(botan_cipher_t cipher, \ + const uint8_t* key, size_t key_len) + +.. cpp:function:: int botan_cipher_is_authenticated(botan_cipher_t cipher) + +.. cpp:function:: size_t botan_cipher_get_tag_length(botan_cipher_t cipher, size_t* tag_len) + + Write the tag length of the cipher to ``tag_len``. This will be zero for non-authenticated + ciphers. + +.. cpp:function:: int botan_cipher_valid_nonce_length(botan_cipher_t cipher, size_t nl) + + Returns 1 if the nonce length is valid, or 0 otherwise. Returns -1 on error (such as + the cipher object being invalid). + +.. cpp:function:: size_t botan_cipher_get_default_nonce_length(botan_cipher_t cipher, size_t* nl) + + Return the default nonce length + +.. cpp:function:: int botan_cipher_set_associated_data(botan_cipher_t cipher, \ + const uint8_t* ad, size_t ad_len) + + Set associated data. Will fail unless the cipher is an AEAD. + +.. cpp:function:: int botan_cipher_start(botan_cipher_t cipher, \ + const uint8_t* nonce, size_t nonce_len) + + Start processing a message using the provided nonce. + +.. cpp:function:: int botan_cipher_update(botan_cipher_t cipher, \ + uint32_t flags, \ + uint8_t output[], \ + size_t output_size, \ + size_t* output_written, \ + const uint8_t input_bytes[], \ + size_t input_size, \ + size_t* input_consumed) + + Encrypt or decrypt data. + +PBKDF +---------------------------------------- + +.. cpp:function:: int botan_pbkdf(const char* pbkdf_algo, \ + uint8_t out[], size_t out_len, \ + const char* passphrase, \ + const uint8_t salt[], size_t salt_len, \ + size_t iterations) + + Derive a key from a passphrase for a number of iterations + using the given PBKDF algorithm, e.g., "PBKDF2". + +.. cpp:function:: int botan_pbkdf_timed(const char* pbkdf_algo, \ + uint8_t out[], size_t out_len, \ + const char* passphrase, \ + const uint8_t salt[], size_t salt_len, \ + size_t milliseconds_to_run, \ + size_t* out_iterations_used) + + Derive a key from a passphrase using the given PBKDF algorithm, + e.g., "PBKDF2". If *out_iterations_used* is zero, instead the + PBKDF is run until *milliseconds_to_run* milliseconds have passed. + In this case, the number of iterations run will be written to + *out_iterations_used*. + +KDF +---------------------------------------- + +.. cpp:function:: int botan_kdf(const char* kdf_algo, \ + uint8_t out[], size_t out_len, \ + const uint8_t secret[], size_t secret_len, \ + const uint8_t salt[], size_t salt_len, \ + const uint8_t label[], size_t label_len) + + Derive a key using the given KDF algorithm, e.g., "SP800-56C". + The derived key of length *out_len* bytes will be placed in *out*. + +Multiple Precision Integers +---------------------------------------- + +.. versionadded: 2.1.0 + +.. cpp:type:: opaque* botan_mp_t + + An opaque data type for a multiple precision integer. Don't mess with it. + +.. cpp:function:: int botan_mp_init(botan_mp_t* mp) + + Initialize a ``botan_mp_t``. Initial value is zero, use `botan_mp_set_X` to load a value. + +.. cpp:function:: int botan_mp_destroy(botan_mp_t mp) + + Free a ``botan_mp_t`` + +.. cpp:function:: int botan_mp_to_hex(botan_mp_t mp, char* out) + + Writes exactly ``botan_mp_num_bytes(mp)*2 + 1`` bytes to out + +.. cpp:function:: int botan_mp_to_str(botan_mp_t mp, uint8_t base, char* out, size_t* out_len) + + Base can be either 10 or 16. + +.. cpp:function:: int botan_mp_set_from_int(botan_mp_t mp, int initial_value) + + Set ``botan_mp_t`` from an integer value. + +.. cpp:function:: int botan_mp_set_from_mp(botan_mp_t dest, botan_mp_t source) + + Set ``botan_mp_t`` from another MP. + +.. cpp:function:: int botan_mp_set_from_str(botan_mp_t dest, const char* str) + + Set ``botan_mp_t`` from a string. Leading prefix of "0x" is accepted. + +.. cpp:function:: int botan_mp_num_bits(botan_mp_t n, size_t* bits) + + Return the size of ``n`` in bits. + +.. cpp:function:: int botan_mp_num_bytes(botan_mp_t n, size_t* uint8_ts) + + Return the size of ``n`` in bytes. + +.. cpp:function:: int botan_mp_to_bin(botan_mp_t mp, uint8_t vec[]) + + Writes exactly ``botan_mp_num_bytes(mp)`` to ``vec``. + +.. cpp:function:: int botan_mp_from_bin(botan_mp_t mp, const uint8_t vec[], size_t vec_len) + + Loads ``botan_mp_t`` from a binary vector (as produced by ``botan_mp_to_bin``). + +.. cpp:function:: int botan_mp_is_negative(botan_mp_t mp) + + Return 1 if ``mp`` is negative, otherwise 0. + +.. cpp:function:: int botan_mp_flip_sign(botan_mp_t mp) + + Flip the sign of ``mp``. + +.. cpp:function:: int botan_mp_add(botan_mp_t result, botan_mp_t x, botan_mp_t y) + + Add two ``botan_mp_t``s and store the output in ``result``. + +.. cpp:function:: int botan_mp_sub(botan_mp_t result, botan_mp_t x, botan_mp_t y) + + Subtract two ``botan_mp_t``s and store the output in ``result``. + +.. cpp:function:: int botan_mp_mul(botan_mp_t result, botan_mp_t x, botan_mp_t y) + + Multiply two ``botan_mp_t``s and store the output in ``result``. + +.. cpp:function:: int botan_mp_div(botan_mp_t quotient, botan_mp_t remainder, \ + botan_mp_t x, botan_mp_t y) + + Divide ``x`` by ``y`` and store the output in ``quotient`` and ``remainder``. + +.. cpp:function:: int botan_mp_mod_mul(botan_mp_t result, botan_mp_t x, botan_mp_t y, botan_mp_t mod) + + Set ``result`` to ``x`` times ``y`` modulo ``mod``. + +.. cpp:function:: int botan_mp_equal(botan_mp_t x, botan_mp_t y) + + Return 1 if ``x`` is equal to ``y``, 0 if ``x`` is not equal to ``y`` + +.. cpp:function:: int botan_mp_is_zero(const botan_mp_t x) + + Return 1 if ``x`` is equal to zero, otherwise 0. + +.. cpp:function:: int botan_mp_is_odd(const botan_mp_t x) + + Return 1 if ``x`` is odd, otherwise 0. + +.. cpp:function:: int botan_mp_is_even(const botan_mp_t x) + + Return 1 if ``x`` is even, otherwise 0. + +.. cpp:function:: int botan_mp_is_positive(const botan_mp_t x) + + Return 1 if ``x`` is greater than or equal to zero. + +.. cpp:function:: int botan_mp_is_negative(const botan_mp_t x) + + Return 1 if ``x`` is less than zero. + +.. cpp:function:: int botan_mp_to_uint32(const botan_mp_t x, uint32_t* val) + + If x fits in a 32-bit integer, set val to it and return 0. If x is out of + range an error is returned. + +.. cpp:function:: int botan_mp_cmp(int* result, botan_mp_t x, botan_mp_t y) + + Three way comparison: set result to -1 if ``x`` is less than ``y``, + 0 if ``x`` is equal to ``y``, and 1 if ``x`` is greater than ``y``. + +.. cpp:function:: int botan_mp_swap(botan_mp_t x, botan_mp_t y) + + Swap two ``botan_mp_t`` values. + +.. cpp:function:: int botan_mp_powmod(botan_mp_t out, botan_mp_t base, botan_mp_t exponent, botan_mp_t modulus) + + Modular exponentiation. + +.. cpp:function:: int botan_mp_lshift(botan_mp_t out, botan_mp_t in, size_t shift) + + Left shift by specified bit count, place result in ``out``. + +.. cpp:function:: int botan_mp_rshift(botan_mp_t out, botan_mp_t in, size_t shift) + + Right shift by specified bit count, place result in ``out``. + +.. cpp:function:: int botan_mp_mod_inverse(botan_mp_t out, botan_mp_t in, botan_mp_t modulus) + + Compute modular inverse. If no modular inverse exists (for instance because ``in`` and + ``modulus`` are not relatively prime), then sets ``out`` to -1. + +.. cpp:function:: int botan_mp_rand_bits(botan_mp_t rand_out, botan_rng_t rng, size_t bits) + + Create a random ``botan_mp_t`` of the specified bit size. + +.. cpp:function:: int botan_mp_rand_range(botan_mp_t rand_out, botan_rng_t rng, \ + botan_mp_t lower_bound, botan_mp_t upper_bound) + + Create a random ``botan_mp_t`` within the provided range. + +.. cpp:function:: int botan_mp_gcd(botan_mp_t out, botan_mp_t x, botan_mp_t y) + + Compute the greatest common divisor of ``x`` and ``y``. + +.. cpp:function:: int botan_mp_is_prime(botan_mp_t n, botan_rng_t rng, size_t test_prob) + + Test if ``n`` is prime. The algorithm used (Miller-Rabin) is probabilistic, + set ``test_prob`` to the desired assurance level. For example if + ``test_prob`` is 64, then sufficient Miller-Rabin iterations will run to + assure there is at most a ``1/2**64`` chance that ``n`` is composite. + +.. cpp:function:: int botan_mp_get_bit(botan_mp_t n, size_t bit) + + Returns 0 if the specified bit of ``n`` is not set, 1 if it is set. + +.. cpp:function:: int botan_mp_set_bit(botan_mp_t n, size_t bit) + + Set the specified bit of ``n`` + +.. cpp:function:: int botan_mp_clear_bit(botan_mp_t n, size_t bit) + + Clears the specified bit of ``n`` + + +Password Hashing +---------------------------------------- + +.. cpp:function:: int botan_bcrypt_generate(uint8_t* out, size_t* out_len, \ + const char* password, \ + botan_rng_t rng, \ + size_t work_factor, \ + uint32_t flags) + + Create a password hash using Bcrypt. + The output buffer *out* should be of length 64 bytes. + The output is formatted bcrypt $2a$... + +.. cpp:function:: int botan_bcrypt_is_valid(const char* pass, const char* hash) + + Check a previously created password hash. Returns + :cpp:enumerator:`BOTAN_SUCCESS` if if this password/hash + combination is valid, :cpp:enumerator:`BOTAN_FFI_INVALID_VERIFIER` + if the combination is not valid (but otherwise well formed), + negative on error. + +Public Key Creation, Import and Export +---------------------------------------- + +.. cpp:type:: opaque* botan_privkey_t + + An opaque data type for a private key. Don't mess with it. + +.. cpp:function:: int botan_privkey_create(botan_privkey_t* key, \ + const char* algo_name, \ + const char* algo_params, \ + botan_rng_t rng) + +.. cpp:function:: int botan_privkey_create_rsa(botan_privkey_t* key, botan_rng_t rng, size_t n_bits) + +.. cpp:function:: int botan_privkey_create_ecdsa(botan_privkey_t* key, botan_rng_t rng, const char* params) + +.. cpp:function:: int botan_privkey_create_ecdh(botan_privkey_t* key, botan_rng_t rng, const char* params) + +.. cpp:function:: int botan_privkey_create_mceliece(botan_privkey_t* key, botan_rng_t rng, size_t n, size_t t) + +.. cpp:function:: int botan_privkey_create_dh(botan_privkey_t* key, botan_rng_t rng, const char* params) + +.. cpp:function:: int botan_privkey_load(botan_privkey_t* key, botan_rng_t rng, \ + const uint8_t bits[], size_t len, \ + const char* password) + +.. cpp:function:: int botan_privkey_destroy(botan_privkey_t key) + +.. cpp:function:: int botan_privkey_export(botan_privkey_t key, \ + uint8_t out[], size_t* out_len, \ + uint32_t flags) + +.. cpp:function:: int botan_privkey_export_encrypted(botan_privkey_t key, \ + uint8_t out[], size_t* out_len, \ + botan_rng_t rng, \ + const char* passphrase, \ + const char* encryption_algo, \ + uint32_t flags) + + Deprecated, use ``botan_privkey_export_encrypted_msec`` or ``botan_privkey_export_encrypted_iter`` + +.. cpp::function:: int botan_privkey_export_encrypted_pbkdf_msec(botan_privkey_t key, + uint8_t out[], size_t* out_len, \ + botan_rng_t rng, \ + const char* passphrase, \ + uint32_t pbkdf_msec_runtime, \ + size_t* pbkdf_iterations_out, \ + const char* cipher_algo, \ + const char* pbkdf_algo, \ + uint32_t flags); + + Encrypt a key, running the key derivation function for ``pbkdf_msec_runtime`` milliseconds. + Returns the number of iterations used in ``pbkdf_iterations_out``. + + ``cipher_algo`` must specify a CBC mode cipher (such as "AES-128/CBC") or as + a Botan-specific extension a GCM mode may be used. + +.. cpp::function:: int botan_privkey_export_encrypted_pbkdf_iter(botan_privkey_t key, \ + uint8_t out[], size_t* out_len, \ + botan_rng_t rng, \ + const char* passphrase, \ + size_t pbkdf_iterations, \ + const char* cipher_algo, \ + const char* pbkdf_algo, \ + uint32_t flags); + + Encrypt a private key. The PBKDF function runs for the specified number of iterations. + At least 100,000 is recommended. + +.. cpp:type:: opaque* botan_pubkey_t + + An opaque data type for a public key. Don't mess with it. + +.. cpp:function:: int botan_pubkey_load(botan_pubkey_t* key, const uint8_t bits[], size_t len) + +.. cpp:function:: int botan_privkey_export_pubkey(botan_pubkey_t* out, botan_privkey_t in) + +.. cpp:function:: int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) + +.. cpp:function:: int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len) + +.. cpp:function:: int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate) + +.. cpp:function:: int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash, \ + uint8_t out[], size_t* out_len) + +.. cpp:function:: int botan_pubkey_destroy(botan_pubkey_t key) + +.. cpp:function:: int botan_pubkey_get_field(botan_mp_t output, \ + botan_pubkey_t key, \ + const char* field_name) + + Read an algorithm specific field from the public key object, placing it into output. + For example "n" or "e" for RSA keys or "p", "q", "g", and "y" for DSA keys. + +.. cpp:function:: int botan_privkey_get_field(botan_mp_t output, \ + botan_privkey_t key, \ + const char* field_name) + + Read an algorithm specific field from the private key object, placing it into output. + For example "p" or "q" for RSA keys, or "x" for DSA keys or ECC keys. + + +RSA specific functions +---------------------------------------- + +.. cpp:function:: int botan_privkey_rsa_get_p(botan_mp_t p, botan_privkey_t rsa_key) + + Set ``p`` to the first RSA prime. + +.. cpp:function:: int botan_privkey_rsa_get_q(botan_mp_t q, botan_privkey_t rsa_key) + + Set ``q`` to the second RSA prime. + +.. cpp:function:: int botan_privkey_rsa_get_d(botan_mp_t d, botan_privkey_t rsa_key) + + Set ``d`` to the RSA private exponent. + +.. cpp:function:: int botan_privkey_rsa_get_n(botan_mp_t n, botan_privkey_t rsa_key) + + Set ``n`` to the RSA modulus. + +.. cpp:function:: int botan_privkey_rsa_get_e(botan_mp_t e, botan_privkey_t rsa_key) + + Set ``e`` to the RSA public exponent. + +.. cpp:function:: int botan_pubkey_rsa_get_e(botan_mp_t e, botan_pubkey_t rsa_key) + + Set ``e`` to the RSA public exponent. + +.. cpp:function:: int botan_pubkey_rsa_get_n(botan_mp_t n, botan_pubkey_t rsa_key) + + Set ``n`` to the RSA modulus. + +.. cpp:function:: int botan_privkey_load_rsa(botan_privkey_t* key, \ + botan_mp_t p, botan_mp_t q, botan_mp_t e) + + Initialize a private RSA key using parameters p, q, and e. + +.. cpp:function:: int botan_pubkey_load_rsa(botan_pubkey_t* key, \ + botan_mp_t n, botan_mp_t e) + + Initialize a public RSA key using parameters n and e. + +DSA specific functions +---------------------------------------- + +.. cpp:function:: int botan_privkey_load_dsa(botan_privkey_t* key, \ + botan_mp_t p, botan_mp_t q, botan_mp_t g, botan_mp_t x) + + Initialize a private DSA key using group parameters p, q, and g and private key x. + +.. cpp:function:: int botan_pubkey_load_dsa(botan_pubkey_t* key, \ + botan_mp_t p, botan_mp_t q, botan_mp_t g, botan_mp_t y) + + Initialize a private DSA key using group parameters p, q, and g and public key y. + +ElGamal specific functions +---------------------------------------- + +.. cpp:function:: int botan_privkey_load_elgamal(botan_privkey_t* key, \ + botan_mp_t p, botan_mp_t g, botan_mp_t x) + + Initialize a private ElGamal key using group parameters p and g and private key x. + +.. cpp:function:: int botan_pubkey_load_elgamal(botan_pubkey_t* key, \ + botan_mp_t p, botan_mp_t g, botan_mp_t y) + + Initialize a public ElGamal key using group parameters p and g and public key y. + +Diffie-Hellman specific functions +---------------------------------------- + +.. cpp:function:: int botan_privkey_load_dh(botan_privkey_t* key, \ + botan_mp_t p, botan_mp_t g, botan_mp_t x) + + Initialize a private Diffie-Hellman key using group parameters p and g and private key x. + +.. cpp:function:: int botan_pubkey_load_dh(botan_pubkey_t* key, \ + botan_mp_t p, botan_mp_t g, botan_mp_t y) + + Initialize a public Diffie-Hellman key using group parameters p and g and public key y. + +Public Key Encryption/Decryption +---------------------------------------- + +.. cpp:type:: opaque* botan_pk_op_encrypt_t + + An opaque data type for an encryption operation. Don't mess with it. + +.. cpp:function:: int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op, \ + botan_pubkey_t key, \ + const char* padding, \ + uint32_t flags) + + Create a new operation object which can be used to encrypt using the provided + key and the specified padding scheme (such as "OAEP(SHA-256)" for use with + RSA). Flags should be 0 in this version. + +.. cpp:function:: int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op) + + Destroy the object. + +.. cpp:function:: int botan_pk_op_encrypt_output_length(botan_pk_op_encrypt_t op, \ + size_t ptext_len, size_t* ctext_len) + + Returns an upper bound on the output length if a plaintext of length ``ptext_len`` + is encrypted with this key/parameter setting. This allows correctly sizing the + buffer that is passed to :cpp:func:`botan_pk_op_encrypt`. + +.. cpp:function:: int botan_pk_op_encrypt(botan_pk_op_encrypt_t op, \ + botan_rng_t rng, \ + uint8_t out[], size_t* out_len, \ + const uint8_t plaintext[], size_t plaintext_len) + + Encrypt the provided data using the key, placing the output in `out`. If + `out` is NULL, writes the length of what the ciphertext would have been to + `*out_len`. However this is computationally expensive (the encryption + actually occurs, then the result is discarded), so it is better to use + :cpp:func:`botan_pk_op_encrypt_output_length` to correctly size the buffer. + +.. cpp:type:: opaque* botan_pk_op_decrypt_t + + An opaque data type for a decryption operation. Don't mess with it. + +.. cpp:function:: int botan_pk_op_decrypt_create(botan_pk_op_decrypt_t* op, \ + botan_privkey_t key, \ + const char* padding, \ + uint32_t flags) + +.. cpp:function:: int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op) + +.. cpp:function:: int botan_pk_op_decrypt_output_length(botan_pk_op_decrypt_t op, \ + size_t ctext_len, size_t* ptext_len) + + For a given ciphertext length, returns the upper bound on the size of the + plaintext that might be enclosed. This allows properly sizing the output + buffer passed to :cpp:func:`botan_pk_op_decrypt`. + +.. cpp:function:: int botan_pk_op_decrypt(botan_pk_op_decrypt_t op, \ + uint8_t out[], size_t* out_len, \ + uint8_t ciphertext[], size_t ciphertext_len) + +Signature Generation +---------------------------------------- + +.. cpp:type:: opaque* botan_pk_op_sign_t + + An opaque data type for a signature generation operation. Don't mess with it. + +.. cpp:function:: int botan_pk_op_sign_create(botan_pk_op_sign_t* op, \ + botan_privkey_t key, \ + const char* hash_and_padding, \ + uint32_t flags) + + Create a signature operator for the provided key. The padding string + specifies what hash function and padding should be used, for example + "PKCS1v15(SHA-256)" or "EMSA1(SHA-384)". + +.. cpp:function:: int botan_pk_op_sign_destroy(botan_pk_op_sign_t op) + + Destroy an object created by :cpp:func:`botan_pk_op_sign_create`. + +.. cpp:function:: int botan_pk_op_sign_output_length(botan_pk_op_sign_t op, size_t* sig_len) + + Writes the length of the signatures that this signer will produce. This + allows properly sizing the buffer passed to + :cpp:func:`botan_pk_op_sign_finish`. + +.. cpp:function:: int botan_pk_op_sign_update(botan_pk_op_sign_t op, \ + const uint8_t in[], size_t in_len) + + Add bytes of the message to be signed. + +.. cpp:function:: int botan_pk_op_sign_finish(botan_pk_op_sign_t op, botan_rng_t rng, \ + uint8_t sig[], size_t* sig_len) + + Produce a signature over all of the bytes passed to :cpp:func:`botan_pk_op_sign_update`. + Afterwards, the sign operator is reset and may be used to sign a new message. + +Signature Verification +---------------------------------------- + +.. cpp:type:: opaque* botan_pk_op_verify_t + + An opaque data type for a signature verification operation. Don't mess with it. + +.. cpp:function:: int botan_pk_op_verify_create(botan_pk_op_verify_t* op, \ + botan_pubkey_t key, \ + const char* hash_and_padding, \ + uint32_t flags) + +.. cpp:function:: int botan_pk_op_verify_destroy(botan_pk_op_verify_t op) + +.. cpp:function:: int botan_pk_op_verify_update(botan_pk_op_verify_t op, \ + const uint8_t in[], size_t in_len) + + Add bytes of the message to be verified + +.. cpp:function:: int botan_pk_op_verify_finish(botan_pk_op_verify_t op, \ + const uint8_t sig[], size_t sig_len) + + Verify if the signature provided matches with the message provided as calls + to :cpp:func:`botan_pk_op_verify_update`. + +Key Agreement +---------------------------------------- + +.. cpp:type:: opaque* botan_pk_op_ka_t + + An opaque data type for a key agreement operation. Don't mess with it. + +.. cpp:function:: int botan_pk_op_key_agreement_create(botan_pk_op_ka_t* op, \ + botan_privkey_t key, \ + const char* kdf, \ + uint32_t flags) + +.. cpp:function:: int botan_pk_op_key_agreement_destroy(botan_pk_op_ka_t op) + +.. cpp:function:: int botan_pk_op_key_agreement_export_public(botan_privkey_t key, \ + uint8_t out[], size_t* out_len) + +.. cpp:function:: int botan_pk_op_key_agreement(botan_pk_op_ka_t op, \ + uint8_t out[], size_t* out_len, \ + const uint8_t other_key[], size_t other_key_len, \ + const uint8_t salt[], size_t salt_len) + +.. cpp:function:: int botan_mceies_encrypt(botan_pubkey_t mce_key, \ + botan_rng_t rng, \ + const char* aead, \ + const uint8_t pt[], size_t pt_len, \ + const uint8_t ad[], size_t ad_len, \ + uint8_t ct[], size_t* ct_len) + +.. cpp:function:: int botan_mceies_decrypt(botan_privkey_t mce_key, \ + const char* aead, \ + const uint8_t ct[], size_t ct_len, \ + const uint8_t ad[], size_t ad_len, \ + uint8_t pt[], size_t* pt_len) + +X.509 Certificates +---------------------------------------- + +.. cpp:type:: opaque* botan_x509_cert_t + + An opaque data type for an X.509 certificate. Don't mess with it. + +.. cpp:function:: int botan_x509_cert_load(botan_x509_cert_t* cert_obj, \ + const uint8_t cert[], size_t cert_len) + + Load a certificate from the DER or PEM representation + +.. cpp:function:: int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* filename) + + Load a certificate from a file. + +.. cpp:function:: int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) + + Create a new object that refers to the same certificate. + +.. cpp:function:: int botan_x509_cert_destroy(botan_x509_cert_t cert) + + Destroy the certificate object + +.. cpp:function:: int botan_x509_cert_gen_selfsigned(botan_x509_cert_t* cert, \ + botan_privkey_t key, \ + botan_rng_t rng, \ + const char* common_name, \ + const char* org_name) + +.. cpp:function:: int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) + + Return the time the certificate becomes valid, as a string in form + "YYYYMMDDHHMMSSZ" where Z is a literal character reflecting that this time is + relative to UTC. Prefer :cpp:func:`botan_x509_cert_not_before`. + +.. cpp:function:: int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) + + Return the time the certificate expires, as a string in form + "YYYYMMDDHHMMSSZ" where Z is a literal character reflecting that this time is + relative to UTC. Prefer :cpp:func:`botan_x509_cert_not_after`. + +.. cpp:function:: int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) + + Return the time the certificate becomes valid, as seconds since epoch. + +.. cpp:function:: int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) + + Return the time the certificate expires, as seconds since epoch. + +.. cpp:function:: int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len) + +.. cpp:function:: int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) + + Return the serial number of the certificate. + +.. cpp:function:: int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) + + Return the authority key ID set in the certificate, which may be empty. + +.. cpp:function:: int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) + + Return the subject key ID set in the certificate, which may be empty. + +.. cpp:function:: int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, \ + uint8_t out[], size_t* out_len) + + Get the serialized representation of the public key included in this certificate + +.. cpp:function:: int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) + + Get the public key included in this certificate as a newly allocated object + +.. cpp:function:: int botan_x509_cert_get_issuer_dn(botan_x509_cert_t cert, \ + const char* key, size_t index, \ + uint8_t out[], size_t* out_len) + + Get a value from the issuer DN field. + +.. cpp:function:: int botan_x509_cert_get_subject_dn(botan_x509_cert_t cert, \ + const char* key, size_t index, \ + uint8_t out[], size_t* out_len) + + Get a value from the subject DN field. + +.. cpp:function:: int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) + + Format the certificate as a free-form string. + +.. cpp:enum:: botan_x509_cert_key_constraints + + Certificate key usage constraints. Allowed values: `NO_CONSTRAINTS`, + `DIGITAL_SIGNATURE`, `NON_REPUDIATION`, `KEY_ENCIPHERMENT`, + `DATA_ENCIPHERMENT`, `KEY_AGREEMENT`, `KEY_CERT_SIGN`, + `CRL_SIGN`, `ENCIPHER_ONLY`, `DECIPHER_ONLY`. + +.. cpp:function:: int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) + + +.. cpp:function:: int botan_x509_cert_verify(int* validation_result, \ + botan_x509_cert_t cert, \ + const botan_x509_cert_t* intermediates, \ + size_t intermediates_len, \ + const botan_x509_cert_t* trusted, \ + size_t trusted_len, \ + const char* trusted_path, \ + size_t required_strength, \ + const char* hostname, \ + uint64_t reference_time) + + Verify a certificate. Returns 0 if validation was successful, 1 if + unsuccessful, or negative on error. + + Sets ``validation_result`` to a code that provides more information. + + If not needed, set ``intermediates`` to NULL and ``intermediates_len`` to + zero. + + If not needed, set ``trusted`` to NULL and ``trusted_len`` to zero. + + The ``trusted_path`` refers to a directory where one or more trusted CA + certificates are stored. It may be NULL if not needed. + + Set ``required_strength`` to indicate the minimum key and hash strength + that is allowed. For instance setting to 80 allows 1024-bit RSA and SHA-1. + Setting to 110 requires 2048-bit RSA and SHA-256 or higher. Set to zero + to accept a default. + + Set ``reference_time`` to be the time which the certificate chain is + validated against. Use zero to use the current system clock. + +.. cpp:function:: const char* botan_x509_cert_validation_status(int code) + + Return a (statically allocated) string associated with the verification + result. diff --git a/doc/api_ref/filters.rst b/doc/api_ref/filters.rst new file mode 100644 index 000000000..04baebf5d --- /dev/null +++ b/doc/api_ref/filters.rst @@ -0,0 +1,733 @@ + +Pipe/Filter Message Processing +======================================== + +.. note:: + + The system described below provides a message processing system with a + straightforward API. However it makes many extra memory copies and + allocations than would otherwise be required, and also tends to make + applications using it somewhat opaque because it is not obvious what this or + that Pipe& object actually does (type of operation, number of messages + output (if any!), and so on), whereas using say a HashFunction or AEAD_Mode + provides a much better idea in the code of what operation is occurring. + + This filter interface is no longer used within the library itself + (outside a few dusty corners) and will likely not see any further major + development. However it will remain included because the API is often + convenient and many applications use it. + +Many common uses of cryptography involve processing one or more +streams of data. Botan provides services that make setting up data +flows through various operations, such as compression, encryption, and +base64 encoding. Each of these operations is implemented in what are +called *filters* in Botan. A set of filters are created and placed into +a *pipe*, and information "flows" through the pipe until it reaches +the end, where the output is collected for retrieval. If you're +familiar with the Unix shell environment, this design will sound quite +familiar. + +Here is an example that uses a pipe to base64 encode some strings:: + + Pipe pipe(new Base64_Encoder); // pipe owns the pointer + pipe.start_msg(); + pipe.write("message 1"); + pipe.end_msg(); // flushes buffers, increments message number + + // process_msg(x) is start_msg() && write(x) && end_msg() + pipe.process_msg("message2"); + + std::string m1 = pipe.read_all_as_string(0); // "message1" + std::string m2 = pipe.read_all_as_string(1); // "message2" + +Byte streams in the pipe are grouped into messages; blocks of data that +are processed in an identical fashion (ie, with the same sequence of +filter operations). Messages are delimited by calls to ``start_msg`` +and ``end_msg``. Each message in a pipe has its own identifier, which +currently is an integer that increments up from zero. + +The ``Base64_Encoder`` was allocated using ``new``; but where was it +deallocated? When a filter object is passed to a ``Pipe``, the pipe +takes ownership of the object, and will deallocate it when it is no +longer needed. + +There are two different ways to make use of messages. One is to send +several messages through a ``Pipe`` without changing the ``Pipe`` +configuration, so you end up with a sequence of messages; one use of +this would be to send a sequence of identically encrypted UDP packets, +for example (note that the *data* need not be identical; it is just +that each is encrypted, encoded, signed, etc in an identical +fashion). Another is to change the filters that are used in the +``Pipe`` between each message, by adding or removing filters; +functions that let you do this are documented in the Pipe API section. + +Botan has about 40 filters that perform different operations on data. +Here's code that uses one of them to encrypt a string with AES:: + + AutoSeeded_RNG rng, + SymmetricKey key(rng, 16); // a random 128-bit key + InitializationVector iv(rng, 16); // a random 128-bit IV + + // The algorithm we want is specified by a string + Pipe pipe(get_cipher("AES-128/CBC", key, iv, ENCRYPTION)); + + pipe.process_msg("secrets"); + pipe.process_msg("more secrets"); + + secure_vector<uint8_t> c1 = pipe.read_all(0); + + uint8_t c2[4096] = { 0 }; + size_t got_out = pipe.read(c2, sizeof(c2), 1); + // use c2[0...got_out] + +Note the use of ``AutoSeeded_RNG``, which is a random number +generator. If you want to, you can explicitly set up the random number +generators and entropy sources you want to, however for 99% of cases +``AutoSeeded_RNG`` is preferable. + +``Pipe`` also has convenience methods for dealing with ``std::iostream``. +Here is an example of this, using the bzip2 compression filter:: + + std::ifstream in("data.bin", std::ios::binary) + std::ofstream out("data.bin.bz2", std::ios::binary) + + Pipe pipe(new Compression_Filter("bzip2", 9)); + + pipe.start_msg(); + in >> pipe; + pipe.end_msg(); + out << pipe; + +However there is a hitch to the code above; the complete contents of +the compressed data will be held in memory until the entire message +has been compressed, at which time the statement ``out << pipe`` is +executed, and the data is freed as it is read from the pipe and +written to the file. But if the file is very large, we might not have +enough physical memory (or even enough virtual memory!) for that to be +practical. So instead of storing the compressed data in the pipe for +reading it out later, we divert it directly to the file:: + + std::ifstream in("data.bin", std::ios::binary) + std::ofstream out("data.bin.bz2", std::ios::binary) + + Pipe pipe(new Compression_Filter("bzip2", 9), new DataSink_Stream(out)); + + pipe.start_msg(); + in >> pipe; + pipe.end_msg(); + +This is the first code we've seen so far that uses more than one +filter in a pipe. The output of the compressor is sent to the +``DataSink_Stream``. Anything written to a ``DataSink_Stream`` is +written to a file; the filter produces no output. As soon as the +compression algorithm finishes up a block of data, it will send it +along to the sink filter, which will immediately write it to the +stream; if you were to call ``pipe.read_all()`` after +``pipe.end_msg()``, you'd get an empty vector out. This is +particularly useful for cases where you are processing a large amount +of data, as it means you don't have to store everything in memory at +once. + +Here's an example using two computational filters:: + + AutoSeeded_RNG rng, + SymmetricKey key(rng, 32); + InitializationVector iv(rng, 16); + + Pipe encryptor(get_cipher("AES/CBC/PKCS7", key, iv, ENCRYPTION), + new Base64_Encoder); + + encryptor.start_msg(); + file >> encryptor; + encryptor.end_msg(); // flush buffers, complete computations + std::cout << encryptor; + +You can read from a pipe while you are still writing to it, which +allows you to bound the amount of memory that is in use at any one +time. A common idiom for this is:: + + pipe.start_msg(); + std::vector<uint8_t> buffer(4096); // arbitrary size + while(infile.good()) + { + infile.read((char*)&buffer[0], buffer.size()); + const size_t got_from_infile = infile.gcount(); + pipe.write(buffer, got_from_infile); + + if(infile.eof()) + pipe.end_msg(); + + while(pipe.remaining() > 0) + { + const size_t buffered = pipe.read(buffer, buffer.size()); + outfile.write((const char*)&buffer[0], buffered); + } + } + if(infile.bad() || (infile.fail() && !infile.eof())) + throw Some_Exception(); + +Fork +--------------------------------- + +It is common that you might receive some data and want to perform more +than one operation on it (ie, encrypt it with Serpent and calculate +the SHA-256 hash of the plaintext at the same time). That's where +``Fork`` comes in. ``Fork`` is a filter that takes input and passes it +on to *one or more* filters that are attached to it. ``Fork`` changes +the nature of the pipe system completely: instead of being a linked +list, it becomes a tree or acyclic graph. + +Each filter in the fork is given its own output buffer, and thus its +own message. For example, if you had previously written two messages +into a pipe, then you start a new one with a fork that has three +paths of filter's inside it, you add three new messages to the +pipe. The data you put into the pipe is duplicated and sent +into each set of filter and the eventual output is placed into a +dedicated message slot in the pipe. + +Messages in the pipe are allocated in a depth-first manner. This is only +interesting if you are using more than one fork in a single pipe. +As an example, consider the following:: + + Pipe pipe(new Fork( + new Fork( + new Base64_Encoder, + new Fork( + NULL, + new Base64_Encoder + ) + ), + new Hex_Encoder + ) + ); + +In this case, message 0 will be the output of the first +``Base64_Encoder``, message 1 will be a copy of the input (see below +for how fork interprets NULL pointers), message 2 will be the output +of the second ``Base64_Encoder``, and message 3 will be the output of +the ``Hex_Encoder``. This results in message numbers being allocated +in a top to bottom fashion, when looked at on the screen. However, +note that there could be potential for bugs if this is not +anticipated. For example, if your code is passed a filter, and you +assume it is a "normal" one that only uses one message, your message +offsets would be wrong, leading to some confusion during output. + +If Fork's first argument is a null pointer, but a later argument is +not, then Fork will feed a copy of its input directly through. Here's +a case where that is useful:: + + // have std::string ciphertext, auth_code, key, iv, mac_key; + + Pipe pipe(new Base64_Decoder, + get_cipher("AES-128", key, iv, DECRYPTION), + new Fork( + 0, // this message gets plaintext + new MAC_Filter("HMAC(SHA-1)", mac_key) + ) + ); + + pipe.process_msg(ciphertext); + std::string plaintext = pipe.read_all_as_string(0); + secure_vector<uint8_t> mac = pipe.read_all(1); + + if(mac != auth_code) + error(); + +Here we wanted to not only decrypt the message, but send the decrypted +text through an additional computation, in order to compute the +authentication code. + +Any filters that are attached to the pipe after the fork are +implicitly attached onto the first branch created by the fork. For +example, let's say you created this pipe:: + + Pipe pipe(new Fork(new Hash_Filter("SHA-256"), + new Hash_Filter("SHA-512")), + new Hex_Encoder); + +And then called ``start_msg``, inserted some data, then +``end_msg``. Then ``pipe`` would contain two messages. The first one +(message number 0) would contain the SHA-256 sum of the input in hex +encoded form, and the other would contain the SHA-512 sum of the input +in raw binary. In many situations you'll want to perform a sequence of +operations on multiple branches of the fork; in which case, use +the filter described in :ref:`chain`. + +There is also a ``Threaded_Fork`` which acts the same as ``Fork``, +except it runs each of the filters in its own thread. + +.. _chain: + +Chain +--------------------------------- + +A ``Chain`` filter creates a chain of filters and encapsulates them +inside a single filter (itself). This allows a sequence of filters to +become a single filter, to be passed into or out of a function, or to +a ``Fork`` constructor. + +You can call ``Chain``'s constructor with up to four ``Filter`` +pointers (they will be added in order), or with an array of filter +pointers and a ``size_t`` that tells ``Chain`` how many filters are in +the array (again, they will be attached in order). Here's the example +from the last section, using chain instead of relying on the implicit +pass through the other version used:: + + Pipe pipe(new Fork( + new Chain(new Hash_Filter("SHA-256"), new Hex_Encoder), + new Hash_Filter("SHA-512") + ) + ); + +Sources and Sinks +---------------------------------------- + +Data Sources +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A ``DataSource`` is a simple abstraction for a thing that stores +bytes. This type is used heavily in the areas of the API related to +ASN.1 encoding/decoding. The following types are ``DataSource``: +``Pipe``, ``SecureQueue``, and a couple of special purpose ones: +``DataSource_Memory`` and ``DataSource_Stream``. + +You can create a ``DataSource_Memory`` with an array of bytes and a +length field. The object will make a copy of the data, so you don't +have to worry about keeping that memory allocated. This is mostly for +internal use, but if it comes in handy, feel free to use it. + +A ``DataSource_Stream`` is probably more useful than the memory based +one. Its constructors take either a ``std::istream`` or a +``std::string``. If it's a stream, the data source will use the +``istream`` to satisfy read requests (this is particularly useful to +use with ``std::cin``). If the string version is used, it will attempt +to open up a file with that name and read from it. + +Data Sinks +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A ``DataSink`` (in ``data_snk.h``) is a ``Filter`` that takes +arbitrary amounts of input, and produces no output. This means it's +doing something with the data outside the realm of what +``Filter``/``Pipe`` can handle, for example, writing it to a file +(which is what the ``DataSink_Stream`` does). There is no need for +``DataSink``s that write to a ``std::string`` or memory buffer, +because ``Pipe`` can handle that by itself. + +Here's a quick example of using a ``DataSink``, which encrypts +``in.txt`` and sends the output to ``out.txt``. There is +no explicit output operation; the writing of ``out.txt`` is +implicit:: + + DataSource_Stream in("in.txt"); + Pipe pipe(get_cipher("AES-128/CTR-BE", key, iv), + new DataSink_Stream("out.txt")); + pipe.process_msg(in); + +A real advantage of this is that even if "in.txt" is large, only as +much memory is needed for internal I/O buffers will be used. + +The Pipe API +--------------------------------- + +Initializing Pipe +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, ``Pipe`` will do nothing at all; any input placed into the +``Pipe`` will be read back unchanged. Obviously, this has limited +utility, and presumably you want to use one or more filters to somehow +process the data. First, you can choose a set of filters to initialize +the ``Pipe`` via the constructor. You can pass it either a set of up +to four filter pointers, or a pre-defined array and a length:: + + Pipe pipe1(new Filter1(/*args*/), new Filter2(/*args*/), + new Filter3(/*args*/), new Filter4(/*args*/)); + Pipe pipe2(new Filter1(/*args*/), new Filter2(/*args*/)); + + Filter* filters[5] = { + new Filter1(/*args*/), new Filter2(/*args*/), new Filter3(/*args*/), + new Filter4(/*args*/), new Filter5(/*args*/) /* more if desired... */ + }; + Pipe pipe3(filters, 5); + +This is by far the most common way to initialize a ``Pipe``. However, +occasionally a more flexible initialization strategy is necessary; +this is supported by 4 member functions. These functions may only be +used while the pipe in question is not in use; that is, either before +calling ``start_msg``, or after ``end_msg`` has been called (and no +new calls to ``start_msg`` have been made yet). + +.. cpp:function:: void Pipe::prepend(Filter* filter) + + Calling ``prepend`` will put the passed filter first in the list of + transformations. For example, if you prepend a filter implementing + encryption, and the pipe already had a filter that hex encoded the + input, then the next message processed would be first encrypted, + and *then* hex encoded. + +.. cpp:function:: void Pipe::append(Filter* filter) + + Like ``prepend``, but places the filter at the end of the message + flow. This doesn't always do what you expect if there is a fork. + +.. cpp:function:: void Pipe::pop() + + Removes the first filter in the flow. + +.. cpp:function:: void Pipe::reset() + + Removes all the filters that the pipe currently holds - it is reset + to an empty/no-op state. Any data that is being retained by the + pipe is retained after a ``reset``, and ``reset`` does not affect + message numbers (discussed later). + +Giving Data to a Pipe +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Input to a ``Pipe`` is delimited into messages, which can be read from +independently (ie, you can read 5 bytes from one message, and then all of +another message, without either read affecting any other messages). + +.. cpp:function:: void Pipe::start_msg() + + Starts a new message; if a message was already running, an exception is + thrown. After this function returns, you can call ``write``. + +.. cpp:function:: void Pipe::write(const uint8_t* input, size_t length) + +.. cpp:function:: void Pipe::write(const std::vector<uint8_t>& input) + +.. cpp:function:: void Pipe::write(const std::string& input) + +.. cpp:function:: void Pipe::write(DataSource& input) + +.. cpp:function:: void Pipe::write(uint8_t input) + + All versions of ``write`` write the input into the filter sequence. + If a message is not currently active, an exception is thrown. + +.. cpp:function:: void Pipe::end_msg() + + End the currently active message + +Sometimes, you may want to do only a single write per message. In this +case, you can use the ``process_msg`` series of functions, which start +a message, write their argument into the pipe, and then end the +message. In this case you would not make any explicit calls to +``start_msg``/``end_msg``. + +Pipes can also be used with the ``>>`` operator, and will accept a +``std::istream``, or on Unix systems with the ``fd_unix`` module, a +Unix file descriptor. In either case, the entire contents of the file +will be read into the pipe. + +Getting Output from a Pipe +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Retrieving the processed data from a pipe is a bit more complicated, +for various reasons. The pipe will separate each message into a +separate buffer, and you have to retrieve data from each message +independently. Each of the reader functions has a final parameter that +specifies what message to read from. If this parameter is set to +``Pipe::DEFAULT_MESSAGE``, it will read the current default message +(``DEFAULT_MESSAGE`` is also the default value of this parameter). + +Functions in ``Pipe`` related to reading include: + +.. cpp:function:: size_t Pipe::read(uint8_t* out, size_t len) + + Reads up to ``len`` bytes into ``out``, and returns the number of + bytes actually read. + +.. cpp:function:: size_t Pipe::peek(uint8_t* out, size_t len) + + Acts exactly like `read`, except the data is not actually read; the + next read will return the same data. + +.. cpp:function:: secure_vector<uint8_t> Pipe::read_all() + + Reads the entire message into a buffer and returns it + +.. cpp:function:: std::string Pipe::read_all_as_string() + + Like ``read_all``, but it returns the data as a ``std::string``. + No encoding is done; if the message contains raw binary, so will + the string. + +.. cpp:function:: size_t Pipe::remaining() + + Returns how many bytes are left in the message + +.. cpp:function:: Pipe::message_id Pipe::default_msg() + + Returns the current default message number + +.. cpp:function:: Pipe::message_id Pipe::message_count() + + Returns the total number of messages currently in the pipe + +.. cpp:function:: Pipe::set_default_msg(Pipe::message_id msgno) + + Sets the default message number (which must be a valid message + number for that pipe). The ability to set the default message number + is particularly important in the case of using the file output + operations (``<<`` with a ``std::ostream`` or Unix file descriptor), + because there is no way to specify the message explicitly when using + the output operator. + +Pipe I/O for Unix File Descriptors +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is a minor feature, but it comes in handy sometimes. In all +installations of the library, Botan's ``Pipe`` object overloads the +``<<`` and ``>>`` operators for C++ iostream objects, +which is usually more than sufficient for doing I/O. + +However, there are cases where the iostream hierarchy does not map well to +local 'file types', so there is also the ability to do I/O directly with Unix +file descriptors. This is most useful when you want to read from or write to +something like a TCP or Unix-domain socket, or a pipe, since for simple file +access it's usually easier to just use C++'s file streams. + +If ``BOTAN_EXT_PIPE_UNIXFD_IO`` is defined, then you can use the +overloaded I/O operators with Unix file descriptors. For an example of this, +check out the ``hash_fd`` example, included in the Botan distribution. + +Filter Catalog +--------------------------------- + +This section documents most of the useful filters included in the +library. + +Keyed Filters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A few sections ago, it was mentioned that ``Pipe`` can process +multiple messages, treating each of them the same. Well, that was a +bit of a lie. There are some algorithms (in particular, block ciphers +not in ECB mode, and all stream ciphers) that change their state as +data is put through them. + +Naturally, you might well want to reset the keys or (in the case of +block cipher modes) IVs used by such filters, so multiple messages can +be processed using completely different keys, or new IVs, or new keys +and IVs, or whatever. And in fact, even for a MAC or an ECB block +cipher, you might well want to change the key used from message to +message. + +Enter ``Keyed_Filter``, which acts as an abstract interface for any +filter that is uses keys: block cipher modes, stream ciphers, MACs, +and so on. It has two functions, ``set_key`` and ``set_iv``. Calling +``set_key`` will set (or reset) the key used by the algorithm. Setting +the IV only makes sense in certain algorithms -- a call to ``set_iv`` +on an object that doesn't support IVs will cause an exception. You +must call ``set_key`` *before* calling ``set_iv``. + +Here's a example:: + + Keyed_Filter *aes, *hmac; + Pipe pipe(new Base64_Decoder, + // Note the assignments to the cast and hmac variables + aes = get_cipher("AES-128/CBC", aes_key, iv), + new Fork( + 0, // Read the section 'Fork' to understand this + new Chain( + hmac = new MAC_Filter("HMAC(SHA-1)", mac_key, 12), + new Base64_Encoder + ) + ) + ); + pipe.start_msg(); + // use pipe for a while, decrypt some stuff, derive new keys and IVs + pipe.end_msg(); + + aes->set_key(aes_key2); + aes->set_iv(iv2); + hmac->set_key(mac_key2); + + pipe.start_msg(); + // use pipe for some other things + pipe.end_msg(); + +There are some requirements to using ``Keyed_Filter`` that you must +follow. If you call ``set_key`` or ``set_iv`` on a filter that is +owned by a ``Pipe``, you must do so while the ``Pipe`` is +"unlocked". This refers to the times when no messages are being +processed by ``Pipe`` -- either before ``Pipe``'s ``start_msg`` is +called, or after ``end_msg`` is called (and no new call to +``start_msg`` has happened yet). Doing otherwise will result in +undefined behavior, probably silently getting invalid output. + +And remember: if you're resetting both values, reset the key *first*. + +Cipher Filters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Getting a hold of a ``Filter`` implementing a cipher is very +easy. Make sure you're including the header ``lookup.h``, and +then call ``get_cipher``. You will pass the return value +directly into a ``Pipe``. There are a couple different functions +which do varying levels of initialization: + +.. cpp:function:: Keyed_Filter* get_cipher(std::string cipher_spec, \ + SymmetricKey key, InitializationVector iv, Cipher_Dir dir) + +.. cpp:function:: Keyed_Filter* get_cipher(std::string cipher_spec, \ + SymmetricKey key, Cipher_Dir dir) + +The version that doesn't take an IV is useful for things that don't +use them, like block ciphers in ECB mode, or most stream ciphers. If +you specify a cipher spec that does want a IV, and you use the version +that doesn't take one, an exception will be thrown. The ``dir`` +argument can be either ``ENCRYPTION`` or ``DECRYPTION``. + +The cipher_spec is a string that specifies what cipher is to be +used. The general syntax for "cipher_spec" is "STREAM_CIPHER", +"BLOCK_CIPHER/MODE", or "BLOCK_CIPHER/MODE/PADDING". In the case of +stream ciphers, no mode is necessary, so just the name is +sufficient. A block cipher requires a mode of some sort, which can be +"ECB", "CBC", "CFB(n)", "OFB", "CTR-BE", or "EAX(n)". The argument to +CFB mode is how many bits of feedback should be used. If you just use +"CFB" with no argument, it will default to using a feedback equal to +the block size of the cipher. EAX mode also takes an optional bit +argument, which tells EAX how large a tag size to use~--~generally +this is the size of the block size of the cipher, which is the default +if you don't specify any argument. + +In the case of the ECB and CBC modes, a padding method can also be +specified. If it is not supplied, ECB defaults to not padding, and CBC +defaults to using PKCS #5/#7 compatible padding. The padding methods +currently available are "NoPadding", "PKCS7", "OneAndZeros", and +"CTS". CTS padding is currently only available for CBC mode, but the +others can also be used in ECB mode. + +Some example "cipher_spec arguments are: "AES-128/CBC", +"Blowfish/CTR-BE", "Serpent/XTS", and "AES-256/EAX". + +"CTR-BE" refers to counter mode where the counter is incremented as if +it were a big-endian encoded integer. This is compatible with most +other implementations, but it is possible some will use the +incompatible little endian convention. This version would be denoted +as "CTR-LE" if it were supported. + +"EAX" is a new cipher mode designed by Wagner, Rogaway, and +Bellare. It is an authenticated cipher mode (that is, no separate +authentication is needed), has provable security, and is free from +patent entanglements. It runs about half as fast as most of the other +cipher modes (like CBC, OFB, or CTR), which is not bad considering you +don't need to use an authentication code. + +Hashes and MACs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Hash functions and MACs don't need anything special when it comes to +filters. Both just take their input and produce no output until +``end_msg`` is called, at which time they complete the hash or MAC and +send that as output. + +These filters take a string naming the type to be used. If for some +reason you name something that doesn't exist, an exception will be thrown. + +.. cpp:function:: Hash_Filter::Hash_Filter(std::string hash, size_t outlen = 0) + + This constructor creates a filter that hashes its input with + ``hash``. When ``end_msg`` is called on the owning pipe, the hash is + completed and the digest is sent on to the next filter in the + pipeline. The parameter ``outlen`` specifies how many bytes of the + hash output will be passed along to the next filter when ``end_msg`` + is called. By default, it will pass the entire hash. + + Examples of names for ``Hash_Filter`` are "SHA-1" and "Whirlpool". + +.. cpp:function:: MAC_Filter::MAC_Filter(std::string mac, SymmetricKey key, size_t outlen = 0) + + This constructor takes a name for a mac, such as "HMAC(SHA-1)" or + "CMAC(AES-128)", along with a key to use. The optional ``outlen`` + works the same as in ``Hash_Filter``. + +Encoders +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Often you want your data to be in some form of text (for sending over +channels that aren't 8-bit clean, printing it, etc). The filters +``Hex_Encoder`` and ``Base64_Encoder`` will convert arbitrary binary +data into hex or base64 formats. Not surprisingly, you can use +``Hex_Decoder`` and ``Base64_Decoder`` to convert it back into its +original form. + +Both of the encoders can take a few options about how the data should +be formatted (all of which have defaults). The first is a ``bool`` +which says if the encoder should insert line breaks. This defaults to +false. Line breaks don't matter either way to the decoder, but it +makes the output a bit more appealing to the human eye, and a few +transport mechanisms (notably some email systems) limit the maximum +line length. + +The second encoder option is an integer specifying how long such lines +will be (obviously this will be ignored if line-breaking isn't being +used). The default tends to be in the range of 60-80 characters, but +is not specified. If you want a specific value, set it. Otherwise the +default should be fine. + +Lastly, ``Hex_Encoder`` takes an argument of type ``Case``, which can +be ``Uppercase`` or ``Lowercase`` (default is ``Uppercase``). This +specifies what case the characters A-F should be output as. The base64 +encoder has no such option, because it uses both upper and lower case +letters for its output. + +You can find the declarations for these types in ``hex_filt.h`` and +``b64_filt.h``. + +Writing New Filters +--------------------------------- + +The system of filters and pipes was designed in an attempt to make it +as simple as possible to write new filter types. There are four +functions that need to be implemented by a class deriving from +``Filter``: + +.. cpp:function:: std::string Filter::name() const + + This should just return a useful decription of the filter object. + +.. cpp:function:: void Filter::write(const uint8_t* input, size_t length) + + This function is what is called when a filter receives input for it + to process. The filter is not required to process the data right + away; many filters buffer their input before producing any output. A + filter will usually have ``write`` called many times during its + lifetime. + +.. cpp:function:: void Filter::send(uint8_t* output, size_t length) + + Eventually, a filter will want to produce some output to send along + to the next filter in the pipeline. It does so by calling ``send`` + with whatever it wants to send along to the next filter. There is + also a version of ``send`` taking a single byte argument, as a + convenience. + + .. note:: + + Normally a filter does not need to override ``send``, though it + can for special handling. It does however need to call this + function whenever it wants to produce output. + +.. cpp:function:: void Filter::start_msg() + + Implementing this function is optional. Implement it if your filter + would like to do some processing or setup at the start of each + message, such as allocating a data structure. + +.. cpp:function:: void Filter::end_msg() + + Implementing this function is optional. It is called when it has + been requested that filters finish up their computations. The filter + should finish up with whatever computation it is working on (for + example, a compressing filter would flush the compressor and + ``send`` the final block), and empty any buffers in preparation for + processing a fresh new set of input. + +Additionally, if necessary, filters can define a constructor that +takes any needed arguments, and a destructor to deal with deallocating +memory, closing files, etc. + diff --git a/doc/api_ref/fpe.rst b/doc/api_ref/fpe.rst new file mode 100644 index 000000000..9d77a4086 --- /dev/null +++ b/doc/api_ref/fpe.rst @@ -0,0 +1,98 @@ +Format Preserving Encryption +======================================== + +Format preserving encryption (FPE) refers to a set of techniques for +encrypting data such that the ciphertext has the same format as the +plaintext. For instance, you can use FPE to encrypt credit card +numbers with valid checksums such that the ciphertext is also an +credit card number with a valid checksum, or similarly for bank +account numbers, US Social Security numbers, or even more general +mappings like English words onto other English words. + +The scheme currently implemented in botan is called FE1, and described +in the paper `Format Preserving Encryption +<https://eprint.iacr.org/2009/251>`_ by Mihir Bellare, Thomas +Ristenpart, Phillip Rogaway, and Till Stegers. FPE is an area of +ongoing standardization and it is likely that other schemes will be +included in the future. + +To encrypt an arbitrary value using FE1, you need to use a ranking +method. Basically, the idea is to assign an integer to every value you +might encrypt. For instance, a 16 digit credit card number consists of +a 15 digit code plus a 1 digit checksum. So to encrypt a credit card +number, you first remove the checksum, encrypt the 15 digit value +modulo 10\ :sup:`15`, and then calculate what the checksum is for the +new (ciphertext) number. Or, if you were encrypting words in a +dictionary, you could rank the words by their lexicographical order, +and choose the modulus to be the number of words in the dictionary. + +The interfaces for FE1 are defined in the header ``fpe_fe1.h``: + +.. versionadded:: 2.5.0 + +.. cpp:class:: FPE_FE1 + + .. cpp:function:: FPE_FE1(const BigInt& n, size_t rounds = 5, \ + bool compat_mode = false, \ + std::string mac_algo = "HMAC(SHA-256)") + + Initialize an FPE operation to encrypt/decrypt integers less + than *n*. It is expected that *n* is trivially factorable into + small integers. Common usage would be n to be a power of 10. + + Note that the default parameters to this constructor are + **incompatible** with the ``fe1_encrypt`` and ``fe1_decrypt`` + function originally added in 1.9.17. For compatibility, use + 3 rounds and set ``compat_mode`` to true. + + .. cpp:function:: BigInt encrypt(const BigInt& x, const uint8_t tweak[], size_t tweak_len) const + + Encrypts the value *x* modulo the value *n* using the *key* and *tweak* + specified. Returns an integer less than *n*. The *tweak* is a value that + does not need to be secret that parameterizes the encryption function. For + instance, if you were encrypting a database column with a single key, you + could use a per-row-unique integer index value as the tweak. The same + tweak value must be used during decryption. + + .. cpp:function:: BigInt decrypt(const BigInt& x, const uint8_t tweak[], size_t tweak_len) const + + Decrypts an FE1 ciphertext. The *tweak* must be the same as that provided + to the encryption function. Returns the plaintext integer. + + Note that there is not any implicit authentication or checking of data in + FE1, so if you provide an incorrect key or tweak the result is simply a + random integer. + + .. cpp:function:: BigInt encrypt(const BigInt& x, uint64_t tweak) + + Convenience version of encrypt taking an integer tweak. + + .. cpp:function:: BigInt decrypt(const BigInt& x, uint64_t tweak) + + Convenience version of decrypt taking an integer tweak. + +There are two functions that handle the entire FE1 encrypt/decrypt operation. +These are the original interface to FE1, first added in 1.9.17. However because +they do the entire setup cost for each operation, they are significantly slower +than the class-based API presented above. + +.. warning:: These functions are hardcoded to use 3 rounds, which may be + insufficient depending on the chosen modulus. + +.. cpp:function:: BigInt FPE::fe1_encrypt(const BigInt& n, const BigInt& X, \ + const SymmetricKey& key, const std::vector<uint8_t>& tweak) + + This creates an FPE_FE1 object, sets the key, and encrypts *X* using + the provided tweak. + +.. cpp:function:: BigInt FPE::fe1_decrypt(const BigInt& n, const BigInt& X, \ + const SymmetricKey& key, const std::vector<uint8_t>& tweak) + + This creates an FPE_FE1 object, sets the key, and decrypts *X* using + the provided tweak. + +This example encrypts a credit card number with a valid `Luhn checksum +<https://en.wikipedia.org/wiki/Luhn_algorithm>`_ to another number with the same +format, including a correct checksum. + +.. literalinclude:: ../../src/cli/cc_enc.cpp diff --git a/doc/api_ref/hash.rst b/doc/api_ref/hash.rst new file mode 100644 index 000000000..ec83b7f16 --- /dev/null +++ b/doc/api_ref/hash.rst @@ -0,0 +1,332 @@ +Hash Functions and Checksums +============================= + +Hash functions are one-way functions, which map data of arbitrary size to a +fixed output length. Most of the hash functions in Botan are designed to be +cryptographically secure, which means that it is computationally infeasible to +create a collision (finding two inputs with the same hash) or preimages (given a +hash output, generating an arbitrary input with the same hash). But note that +not all such hash functions meet their goals, in particular MD4 and MD5 are +trivially broken. However they are still included due to their wide adoption in +various protocols. + +The class :cpp:class:`HashFunction` is defined in `botan/hash.h`. + +Using a hash function is typically split into three stages: initialization, +update, and finalization (often referred to as a IUF interface). The +initialization stage is implicit: after creating a hash function object, it is +ready to process data. Then update is called one or more times. Calling update +several times is equivalent to calling it once with all of the arguments +concatenated. After completing a hash computation (eg using ``final``), the +internal state is reset to begin hashing a new message. + +.. cpp:class:: HashFunction + + .. cpp:function:: static std::unique_ptr<HashFunction> create(const std::string& name) + + Return a newly allocated hash function object, or nullptr if the + name is not recognized. + + .. cpp:function:: static std::unique_ptr<HashFunction> create_or_throw(const std::string& name) + + Like ``create`` except that it will throw an exception instead of + returning nullptr. + + .. cpp:function:: size_t output_length() + + Return the size (in *bytes*) of the output of this function. + + .. cpp:function:: void update(const uint8_t* input, size_t length) + + Updates the computation with *input*. + + .. cpp:function:: void update(uint8_t input) + + Updates the computation with *input*. + + .. cpp:function:: void update(const std::vector<uint8_t>& input) + + Updates the computation with *input*. + + .. cpp:function:: void update(const std::string& input) + + Updates the computation with *input*. + + .. cpp:function:: void final(uint8_t* out) + + 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. + + .. cpp:function:: secure_vector<uint8_t> final() + + Similar to the other function of the same name, except it returns + the result in a newly allocated vector. + + .. cpp:function:: secure_vector<uint8_t> process(const uint8_t in[], size_t length) + + Equivalent to calling ``update`` followed by ``final``. + + .. cpp:function:: secure_vector<uint8_t> process(const std::string& in) + + Equivalent to calling ``update`` followed by ``final``. + +Code Example +------------ + +Assume we want to calculate the SHA-256, SHA-384, 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-256")); + std::unique_ptr<Botan::HashFunction> hash2(Botan::HashFunction::create("SHA-384")); + 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-256: " << Botan::hex_encode(hash1->final()) << std::endl; + std::cout << "SHA-384: " << Botan::hex_encode(hash2->final()) << std::endl; + std::cout << "SHA-3: " << Botan::hex_encode(hash3->final()) << std::endl; + return 0; + } + +Available Hash Functions +------------------------------ + +The following cryptographic hash functions are implemented. If in doubt, +any of SHA-384, SHA-3, or BLAKE2b are fine choices. + +BLAKE2b +^^^^^^^^^ + +Available if ``BOTAN_HAS_BLAKE2B`` is defined. + +A recently designed hash function. Very fast on 64-bit processors. Can output a +hash of any length between 1 and 64 bytes, this is specified by passing a value +to the constructor with the desired length. + +Named like "Blake2b" which selects default 512-bit output, or as +"Blake2b(256)" to select 256 bits of output. + +GOST-34.11 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_GOST_34_11`` is defined. + +Russian national standard hash. It is old, slow, and has some weaknesses. Avoid +it unless you must. + +Keccak-1600 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_KECCAK`` is defined. + +An older (and incompatible) variant of SHA-3, but sometimes used. Prefer SHA-3 in +new code. + +MD4 +^^^^^^^^^ + +Available if ``BOTAN_HAS_MD4`` is defined. + +An old hash function that is now known to be trivially breakable. It is very +fast, and may still be suitable as a (non-cryptographic) checksum. + +MD5 +^^^^^^^^^ + +Available if ``BOTAN_HAS_MD5`` is defined. + +Widely used, now known to be broken. + +RIPEMD-160 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_RIPEMD160`` is defined. + +A 160 bit hash function, quite old but still thought to be secure (up to the +limit of 2**80 computation required for a collision which is possible with any +160 bit hash function). Somewhat deprecated these days. + +SHA-1 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_SHA1`` is defined. + +Widely adopted NSA designed hash function. Starting to show significant signs of +weakness, and collisions can now be generated. Avoid in new designs. + +SHA-256 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_SHA2_32`` is defined. + +Relatively fast 256 bit hash function, thought to be secure. + +Also includes the variant SHA-224. There is no real reason to use SHA-224. + +SHA-512 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_SHA2_64`` is defined. + +SHA-512 is faster than SHA-256 on 64-bit processors. Also includes +the truncated variants SHA-384 and SHA-512/256. + +SHA-3 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_SHA3`` is defined. + +The new NIST standard hash. Fairly slow. + +Supports 224, 256, 384 or 512 bit outputs. SHA-3 is faster with +smaller outputs. Use as "SHA-3(256)" or "SHA-3(512)". Plain "SHA-3" +selects default 512 bit output. + +SHAKE (SHAKE-128, SHAKE-256) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_SHAKE`` is defined. + +These are actually XOFs (extensible output functions) based on SHA-3, which can +output a value of any byte length. For example "SHAKE-128(1024)" will produce +1024 bits of output. The specified length must be a multiple of 8. Not +specifying an output length, "SHAKE-128" defaults to a 128-bit output and +"SHAKE-256" defaults to a 256-bit output. + +.. warning:: + In the case of SHAKE-128, the default output length in insufficient + to ensure security. The choice of default lengths was a bug which is + currently retained for compatability; they should have been 256 and + 512 bits resp to match SHAKE's security level. Using the default + lengths with SHAKE is deprecated and will be removed in a future major + release. Instead, always specify the desired output length. + +SM3 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_SM3`` is defined. + +Chinese national hash function, 256 bit output. Widely used in industry there. +Fast and seemingly secure, but no reason to prefer it over SHA-2 or SHA-3 unless +required. + +Skein-512 +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_SKEIN_512`` is defined. + +A contender for the NIST SHA-3 competition. Very fast on 64-bit systems. Can +output a hash of any length between 1 and 64 bytes. It also accepts an optional +"personalization string" which can create variants of the hash. This is useful +for domain separation. + +To set a personalization string set the second param to any value, +typically ASCII strings are used. Examples "Skein-512(256)" or +"Skein-512(384,personalization_string)". + +Streebog (Streebog-256, Streebog-512) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_STREEBOG`` is defined. + +Newly designed Russian national hash function. Due to use of input-dependent +table lookups, it is vulnerable to side channels. There is no reason to use it +unless compatibility is needed. + +.. warning:: + The Streebog Sbox has recently been revealed to have a hidden structure which + interacts with its linear layer in a way which may provide a backdoor when + used in certain ways. Avoid Streebog if at all possible. + +Tiger +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_TIGER`` is defined. + +An older 192-bit hash function, optimized for 64-bit systems. Possibly +vulnerable to side channels due to its use of table lookups. + +Tiger supports variable length output (16, 20 or 24 bytes) and +variable rounds (which must be at least 3). Default is 24 byte output +and 3 rounds. Specify with names like "Tiger" or "Tiger(20,5)". + +Whirlpool +^^^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_WHIRLPOOL`` is defined. + +A 512-bit hash function standardized by ISO and NESSIE. Relatively slow, and due +to the table based implementation it is potentially vulnerable to cache based +side channels. + +Hash Function Combiners +--------------------------- + +These are functions which combine multiple hash functions to create a new hash +function. They are typically only used in specialized applications. + +Parallel +^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_PARALLEL_HASH`` is defined. + +Parallel simply concatenates multiple hash functions. For example +"Parallel(SHA-256,SHA-512)" outputs a 256+512 bit hash created by hashing the +input with both SHA-256 and SHA-512 and concatenating the outputs. + +Note that due to the "multicollision attack" it turns out that generating a +collision for multiple parallel hash functions is no harder than generating a +collision for the strongest hash function. + +Comp4P +^^^^^^^^^^^^^ + +Available if ``BOTAN_HAS_COMB4P`` is defined. + +This combines two cryptographic hashes in such a way that preimage and collision +attacks are provably at least as hard as a preimage or collision attack on the +strongest hash. + +Checksums +---------------- + +.. note:: Checksums are not suitable for cryptographic use, but can be used for + error checking purposes. + +Adler32 +^^^^^^^^^^^ + +Available if ``BOTAN_HAS_ADLER32`` is defined. + +The Adler32 checksum is used in the zlib format. 32 bit output. + +CRC24 +^^^^^^^^^^^ + +Available if ``BOTAN_HAS_CRC24`` is defined. + +This is the CRC function used in OpenPGP. 24 bit output. + +CRC32 +^^^^^^^^^^^ + +Available if ``BOTAN_HAS_CRC32`` is defined. + +This is the 32-bit CRC used in protocols such as Ethernet, gzip, PNG, etc. diff --git a/doc/api_ref/kdf.rst b/doc/api_ref/kdf.rst new file mode 100644 index 000000000..bc126cbab --- /dev/null +++ b/doc/api_ref/kdf.rst @@ -0,0 +1,106 @@ + +.. _key_derivation_function: + +Key Derivation Functions +======================================== + +Key derivation functions are used to turn some amount of shared secret +material into uniform random keys suitable for use with symmetric +algorithms. An example of an input which is useful for a KDF is a +shared secret created using Diffie-Hellman key agreement. + +.. cpp:class:: KDF + + .. cpp:function:: secure_vector<uint8_t> derive_key( \ + size_t key_len, const std::vector<uint8_t>& secret, \ + const std::string& salt = "") const + + .. cpp:function:: secure_vector<uint8_t> derive_key( \ + size_t key_len, const std::vector<uint8_t>& secret, \ + const std::vector<uint8_t>& salt) const + + .. cpp:function:: secure_vector<uint8_t> derive_key( \ + size_t key_len, const std::vector<uint8_t>& secret, \ + const uint8_t* salt, size_t salt_len) const + + .. cpp:function:: secure_vector<uint8_t> derive_key( \ + size_t key_len, const uint8_t* secret, size_t secret_len, \ + const std::string& salt) const + + All variations on the same theme. Deterministically creates a + uniform random value from *secret* and *salt*. Typically *salt* is + a label or identifier, such as a session id. + +You can create a :cpp:class:`KDF` using + +.. cpp:function:: KDF* get_kdf(const std::string& algo_spec) + + +Available KDFs +------------------- + +Botan includes many different KDFs simply because different protocols and +standards have created subtly different approaches to this problem. For new +code, use HKDF which is conservative, well studied, widely implemented and NIST +approved. + +HKDF +~~~~~ + +Defined in RFC 5869, HKDF uses HMAC to process inputs. Also available +are variants HKDF-Extract and HKDF-Expand. HKDF is the combined +Extract+Expand operation. Use the combined HKDF unless you need +compatibility with some other system. + +Available if ``BOTAN_HAS_HKDF`` is defined. + +KDF2 +~~~~~ + +KDF2 comes from IEEE 1363. It uses a hash function. + +Available if ``BOTAN_HAS_KDF2`` is defined. + +KDF1-18033 +~~~~~~~~~~~~ + +KDF1 from ISO 18033-2. Very similar to (but incompatible with) KDF2. + +Available if ``BOTAN_HAS_KDF1_18033`` is defined. + +KDF1 +~~~~~~ + +KDF1 from IEEE 1363. It can only produce an output at most the length +of the hash function used. + +Available if ``BOTAN_HAS_KDF1`` is defined. + +X9.42 PRF +~~~~~~~~~~ + +A KDF from ANSI X9.42. Sometimes used for Diffie-Hellman. + +Available if ``BOTAN_HAS_X942_PRF`` is defined. + +SP800-108 +~~~~~~~~~~ + +KDFs from NIST SP 800-108. Variants include "SP800-108-Counter", +"SP800-108-Feedback" and "SP800-108-Pipeline". + +Available if ``BOTAN_HAS_SP800_108`` is defined. + +SP800-56A +~~~~~~~~~~ + +KDF from NIST SP 800-56A. + +Available if ``BOTAN_HAS_SP800_56A`` is defined. + +SP800-56C +~~~~~~~~~~ + +KDF from NIST SP 800-56C. + +Available if ``BOTAN_HAS_SP800_56C`` is defined. diff --git a/doc/api_ref/keywrap.rst b/doc/api_ref/keywrap.rst new file mode 100644 index 000000000..5c3aac0a3 --- /dev/null +++ b/doc/api_ref/keywrap.rst @@ -0,0 +1,60 @@ +AES Key Wrapping +================================= + +NIST specifies two mechanisms for wrapping (encrypting) symmetric keys using +another key. The first (and older, more widely supported) method requires the +input be a multiple of 8 bytes long. The other allows any length input, though +only up to 2**32 bytes. + +These algorithms are described in NIST SP 800-38F, and RFCs 3394 and 5649. + +This API, defined in ``nist_keywrap.h``, first became available in version 2.4.0 + +These functions take an arbitrary 128-bit block cipher object, which must +already have been keyed with the key encryption key. NIST only allows these +functions with AES, but any 128-bit cipher will do and some other implementations +(such as in OpenSSL) do also allow other ciphers. Use AES for best interop. + +.. cpp:function:: std::vector<uint8_t> nist_key_wrap(const uint8_t input[], \ + size_t input_len, const BlockCipher& bc) + + This performs KW (key wrap) mode. The input must be a multiple of 8 bytes long. + +.. cpp:function:: secure_vector<uint8_t> nist_key_unwrap(const uint8_t input[], \ + size_t input_len, const BlockCipher& bc) + + This unwraps the result of nist_key_wrap, or throw Invalid_Authentication_Tag on error. + +.. cpp:function:: std::vector<uint8_t> nist_key_wrap_padded(const uint8_t input[], \ + size_t input_len, const BlockCipher& bc) + + This performs KWP (key wrap with padding) mode. The input can be any length. + +.. cpp:function:: secure_vector<uint8_t> nist_key_unwrap_padded(const uint8_t input[], \ + size_t input_len, const BlockCipher& bc) + + This unwraps the result of nist_key_wrap_padded, or throws Invalid_Authentication_Tag + on error. + +RFC 3394 Interface +----------------------------- + +This is an older interface that was first available (with slight changes) in +1.10, and available in its current form since 2.0 release. It uses a 128-bit, +192-bit, or 256-bit key to encrypt an input key. AES is always used. The input +must be a multiple of 8 bytes; if not an exception is thrown. + +This interface is defined in ``rfc3394.h``. + +.. cpp:function:: secure_vector<uint8_t> rfc3394_keywrap(const secure_vector<uint8_t>& key, \ + const SymmetricKey& kek) + + Wrap the input key using kek (the key encryption key), and return the result. It will + be 8 bytes longer than the input key. + +.. cpp:function:: secure_vector<uint8_t> rfc3394_keyunwrap(const secure_vector<uint8_t>& key, \ + const SymmetricKey& kek) + + Unwrap a key wrapped with rfc3394_keywrap. + + diff --git a/doc/api_ref/message_auth_codes.rst b/doc/api_ref/message_auth_codes.rst new file mode 100644 index 000000000..70b6c9c3b --- /dev/null +++ b/doc/api_ref/message_auth_codes.rst @@ -0,0 +1,255 @@ + +.. _mac: + +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 message. Only entities in possession of the shared secret key are able to +verify the tag. + +.. note:: + + When combining a MAC with unauthenticated encryption mode, prefer to first + encrypt the message and then MAC the ciphertext. The alternative is to MAC + the plaintext, which depending on exact usage can suffer serious security + issues. For a detailed discussion of this issue see the paper "The Order of + Encryption and Authentication for Protecting Communications" by Hugo + Krawczyk + +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:: std::string name() const + + Returns a human-readable string of the name of this algorithm. + + .. cpp:function:: void clear() + + Clear the key. + + .. cpp:function:: MessageAuthenticationCode* clone() const + + Return a newly allocated object of the same type as this one. + + .. cpp:function:: void set_key(const uint8_t* 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:: 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 acceptable for the + algorithm. + + .. cpp:function:: size_t maximum_keylength() const + + Return the largest key length (in bytes) that is acceptable for the + algorithm. + + .. cpp:function:: void start(const uint8_t* 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. + For algorithms that don't require it, the call can be omitted, or else called + with ``nonce_len`` of zero. + + .. cpp:function:: void update(const uint8_t* input, size_t length) + + Process the passed data. + + .. cpp:function:: void update(const secure_vector<uint8_t>& in) + + Process the passed data. + + .. cpp:function:: void update(uint8_t in) + + Process a single byte. + + .. cpp:function:: void final(uint8_t* out) + + Complete the MAC computation and write the calculated tag to the passed byte array. + + .. cpp:function:: secure_vector<uint8_t> final() + + Complete the MAC computation and return the calculated tag. + + .. cpp:function:: bool verify_mac(const uint8_t* mac, size_t length) + + Finalize the current MAC computation and compare the result to the passed + ``mac``. Returns ``true``, if the verification is successful and false + otherwise. + + +Code Examples +------------------------ + +The following example computes an HMAC with a random key then verifies the tag. + + #include <botan/mac.h> + #include <botan/hex.h> + #include <botan/system_rng.h> + #include <assert.h> + + std::string compute_mac(const std::string& msg, const Botan::secure_vector<uint8_t>& key) + { + auto hmac = Botan::MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)"); + + hmac->set_key(key); + hmac->update(msg); + + return Botan::hex_encode(hmac->final()); + } + + int main() + { + Botan::System_RNG rng; + + const auto key = rng.random_vec(32); // 256 bit random key + + // "Message" != "Mussage" so tags will also not match + std::string tag1 = compute_mac("Message", key); + std::string tag2 = compute_mac("Mussage", key); + assert(tag1 != tag2); + + // Recomputing with original input message results in identical tag + std::string tag3 = compute_mac("Message", key); + assert(tag1 == tag3); + } + + +The following example code computes a AES-256 GMAC and subsequently verifies the +tag. Unlike most other MACs, GMAC requires a nonce *which must not repeat or +all security is lost*. + +.. 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> nonce = 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(nonce); + 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(nonce); + 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; + } + +Available MACs +------------------------------------------ + +Currently the following MAC algorithms are available in Botan. In new code, +default to HMAC with a strong hash like SHA-256 or SHA-384. + +CBC-MAC +~~~~~~~~~~~~ + +An older authentication code based on a block cipher. Serious security problems, +in particular **insecure** if messages of several different lengths are +authenticated. Avoid unless required for compatibility. + +Available if ``BOTAN_HAS_CBC_MAC`` is defined. + +CMAC +~~~~~~~~~~~~ + +A modern CBC-MAC variant that avoids the security problems of plain CBC-MAC. +Approved by NIST. Also sometimes called OMAC. + +Available if ``BOTAN_HAS_CMAC`` is defined. + +GMAC +~~~~~~~~~~~~ + +GMAC is related to the GCM authenticated cipher mode. It is quite slow unless +hardware support for carryless multiplications is available. A new nonce +must be used with **each** message authenticated, or otherwise all security is +lost. + +Available if ``BOTAN_HAS_GMAC`` is defined. + +HMAC +~~~~~~~~~~~~ + +A message authentication code based on a hash function. Very commonly used. + +Available if ``BOTAN_HAS_HMAC`` is defined. + +Poly1305 +~~~~~~~~~~~~ + +A polynomial mac (similar to GMAC). Very fast, but tricky to use safely. Forms +part of the ChaCha20Poly1305 AEAD mode. A new key must be used for **each** +message, or all security is lost. + +Available if ``BOTAN_HAS_POLY1305`` is defined. + +SipHash +~~~~~~~~~~~~ + +A modern and very fast PRF. Produces only a 64-bit output. Defaults to +"SipHash(2,4)" which is the recommended configuration, using 2 rounds for each +input block and 4 rounds for finalization. + +Available if ``BOTAN_HAS_SIPHASH`` is defined. + +X9.19-MAC +~~~~~~~~~~~~ + +A CBC-MAC variant sometimes used in finance. Always uses DES. Avoid unless +required. + +Available if ``BOTAN_HAS_X919_MAC`` is defined. diff --git a/doc/api_ref/otp.rst b/doc/api_ref/otp.rst new file mode 100644 index 000000000..133201b4e --- /dev/null +++ b/doc/api_ref/otp.rst @@ -0,0 +1,98 @@ +One Time Passwords +======================== + +.. versionadded:: 2.2.0 + +One time password schemes are a user authentication method that relies on a +fixed secret key which is used to derive a sequence of short passwords, each of +which is accepted only once. Commonly this is used to implement two-factor +authentication (2FA), where the user authenticates using both a conventional +password (or a public key signature) and an OTP generated by a small device such +as a mobile phone. + +Botan implements the HOTP and TOTP schemes from RFC 4226 and 6238. + +Since the range of possible OTPs is quite small, applications must rate limit +OTP authentication attempts to some small number per second. Otherwise an attacker +could quickly try all 1000000 6-digit OTPs in a brief amount of time. + +HOTP +^^^^^^ + +HOTP generates OTPs that are a short numeric sequence, between 6 and 8 digits +(most applications use 6 digits), created using the HMAC of a 64-bit counter +value. If the counter ever repeats the OTP will also repeat, thus both parties +must assure the counter only increments and is never repeated or +decremented. Thus both client and server must keep track of the next counter +expected. + +Anyone with access to the client-specific secret key can authenticate as that +client, so it should be treated with the same security consideration as would be +given to any other symmetric key or plaintext password. + +.. cpp:class:: HOTP + + Implement counter-based OTP + + .. cpp:function:: HOTP(const SymmetricKey& key, const std::string& hash_algo = "SHA-1", size_t digits = 6) + + Initialize an HOTP instance with a secret key (specific to each client), + a hash algorithm (must be SHA-1, SHA-256, or SHA-512), and the number of + digits with each OTP (must be 6, 7, or 8). + + In RFC 4226, HOTP is only defined with SHA-1, but many HOTP + implementations support SHA-256 as an extension. The collision attacks + on SHA-1 do not have any known effect on HOTP's security. + + .. cpp:function:: uint32_t generate_hotp(uint64_t counter) + + Return the OTP associated with a specific counter value. + + .. cpp:function:: std::pair<bool,uint64_t> verify_hotp(uint32_t otp, \ + uint64_t starting_counter, size_t resync_range = 0) + + Check if a provided OTP matches the one that should be generated for + the specified counter. + + The *starting_counter* should be the counter of the last successful + authentication plus 1. If *resync_resync* is greater than 0, some number + of counter values above *starting_counter* will also be checked if + necessary. This is useful for instance when a client mistypes an OTP on + entry; the authentication will fail so the server will not update its + counter, but the client device will subsequently show the OTP for the + next counter. Depending on the environment a *resync_range* of 3 to 10 + might be appropriate. + + Returns a pair of (is_valid,next_counter_to_use). If the OTP is invalid + then always returns (false,starting_counter), since the last successful + authentication counter has not changed. + + +TOTP +^^^^^^^^^^ + +TOTP is based on the same algorithm as HOTP, but instead of a counter a +timestamp is used. + +.. cpp:class:: TOTP + + .. cpp:function:: TOTP(const SymmetricKey& key, const std::string& hash_algo = "SHA-1", \ + size_t digits = 6, size_t time_step = 30) + + Setup to perform TOTP authentication using secret key *key*. + + .. cpp:function:: uint32_t generate_totp(std::chrono::system_clock::time_point time_point) + + .. cpp:function:: uint32_t generate_totp(uint64_t unix_time) + + Generate and return a TOTP code based on a timestamp. + + .. cpp:function:: bool verify_totp(uint32_t otp, std::chrono::system_clock::time_point time, \ + size_t clock_drift_accepted = 0) + + .. cpp:function:: bool verify_totp(uint32_t otp, uint64_t unix_time, \ + size_t clock_drift_accepted = 0) + + Return true if the provided OTP code is correct for the provided + timestamp. If required, use *clock_drift_accepted* to deal with + the client and server having slightly different clocks. diff --git a/doc/api_ref/passhash.rst b/doc/api_ref/passhash.rst new file mode 100644 index 000000000..4ef26f7be --- /dev/null +++ b/doc/api_ref/passhash.rst @@ -0,0 +1,219 @@ +Password Hashing +======================================== + +Storing passwords for user authentication purposes in plaintext is the +simplest but least secure method; when an attacker compromises the +database in which the passwords are stored, they immediately gain +access to all of them. Often passwords are reused among multiple +services or machines, meaning once a password to a single service is +known an attacker has a substantial head start on attacking other +machines. + +The general approach is to store, instead of the password, the output +of a one way function of the password. Upon receiving an +authentication request, the authenticating party can recompute the one way +function and compare the value just computed with the one that was +stored. If they match, then the authentication request succeeds. But +when an attacker gains access to the database, they only have the +output of the one way function, not the original password. + +Common hash functions such as SHA-256 are one way, but used alone they +have problems for this purpose. What an attacker can do, upon gaining +access to such a stored password database, is hash common dictionary +words and other possible passwords, storing them in a list. Then he +can search through his list; if a stored hash and an entry in his list +match, then he has found the password. Even worse, this can happen +*offline*: an attacker can begin hashing common passwords days, +months, or years before ever gaining access to the database. In +addition, if two users choose the same password, the one way function +output will be the same for both of them, which will be visible upon +inspection of the database. + +There are two solutions to these problems: salting and +iteration. Salting refers to including, along with the password, a +randomly chosen value which perturbs the one way function. Salting can +reduce the effectiveness of offline dictionary generation, because for +each potential password, an attacker would have to compute the one way +function output for all possible salts. It also prevents the same +password from producing the same output, as long as the salts do not +collide. Choosing n-bit salts randomly, salt collisions become likely +only after about 2\ :sup:\ `(n/2)` salts have been generated. Choosing a +large salt (say 80 to 128 bits) ensures this is very unlikely. Note +that in password hashing salt collisions are unfortunate, but not +fatal - it simply allows the attacker to attack those two passwords in +parallel easier than they would otherwise be able to. + +The other approach, iteration, refers to the general technique of +forcing multiple one way function evaluations when computing the +output, to slow down the operation. For instance if hashing a single +password requires running SHA-256 100,000 times instead of just once, +that will slow down user authentication by a factor of 100,000, but +user authentication happens quite rarely, and usually there are more +expensive operations that need to occur anyway (network and database +I/O, etc). On the other hand, an attacker who is attempting to break a +database full of stolen password hashes will be seriously +inconvenienced by a factor of 100,000 slowdown; they will be able to +only test at a rate of .0001% of what they would without iterations +(or, equivalently, will require 100,000 times as many zombie botnet +hosts). + +Memory usage while checking a password is also a consideration; if the +computation requires using a certain minimum amount of memory, then an +attacker can become memory-bound, which may in particular make +customized cracking hardware more expensive. Some password hashing +designs, such as scrypt, explicitly attempt to provide this. The +bcrypt approach requires over 4 KiB of RAM (for the Blowfish key +schedule) and may also make some hardware attacks more expensive. + +Botan provides three techniques for password hashing: Argon2, bcrypt, and +passhash9 (based on PBKDF2). + +Argon2 +---------------------------------------- + +.. versionadded:: 2.11.0 + +Argon2 is the winner of the PHC (Password Hashing Competition) and provides +a tunable memory hard password hash. It has a standard string encoding, which looks like:: + + "$argon2i$v=19$m=8192,t=10,p=3$YWFhYWFhYWE$itkWB9ODqTd85wUsoib7pfpVTNGMOu0ZJan1odl25V8" + +Argon2 has three tunable parameters: ``M``, ``p``, and ``t``. ``M`` gives the +total memory consumption of the algorithm in kilobytes. Increasing ``p`` +increases the available parallelism of the computation. The ``t`` parameter +gives the number of passes which are made over the data. + +.. note:: + Currently Botan does not make use of ``p`` > 1, so it is best to set it to 1 + to minimize any advantage to highly parallel cracking attempts. + +There are three variants of Argon2, namely Argon2d, Argon2i and Argon2id. +Argon2d uses data dependent table lookups with may leak information about the +password via side channel attacks, and is **not recommended** for password +hashing. Argon2i uses data independent table lookups and is immune to these +attacks, but at the cost of requiring higher ``t`` for security. Argon2id uses a +hybrid approach which is thought to be highly secure. The algorithm designers +recommend using Argon2id with ``t`` and ``p`` both equal to 1 and ``M`` set to +the largest amount of memory usable in your environment. + +.. cpp:function:: std::string argon2_generate_pwhash(const char* password, size_t password_len, \ + RandomNumberGenerator& rng, \ + size_t p, size_t M, size_t t, \ + size_t y = 2, size_t salt_len = 16, size_t output_len = 32) + + Generate an Argon2 hash of the specified password. The ``y`` parameter specifies + the variant: 0 for Argon2d, 1 for Argon2i, and 2 for Argon2id. + +.. cpp:function:: bool argon2_check_pwhash(const char* password, size_t password_len, \ + const std::string& hash) + + Verify an Argon2 password hash against the provided password. Returns false if + the input hash seems malformed or if the computed hash does not match. + +Bcrypt +---------------------------------------- + +`Bcrypt <https://www.usenix.org/legacy/event/usenix99/provos/provos.pdf>`_ is a +password hashing scheme originally designed for use in OpenBSD, but numerous +other implementations exist. It is made available by including ``bcrypt.h``. + +It has the advantage that it requires a small amount (4K) of fast RAM +to compute, which can make hardware password cracking somewhat more +expensive. + +Bcrypt provides outputs that look like this:: + + "$2a$12$7KIYdyv8Bp32WAvc.7YvI.wvRlyVn0HP/EhPmmOyMQA4YKxINO0p2" + +.. note:: + + Due to the design of bcrypt, the password is effectively truncated at 72 + characters; further characters are ignored and do not change the hash. To + support longer passwords, one common approach is to pre-hash the password + with SHA-256, then run bcrypt using the hex or base64 encoding of the hash as + the password. (Many bcrypt implementations truncate the password at the first + NULL character, so hashing the raw binary SHA-256 may cause problems. Botan's + bcrypt implementation will hash whatever values are given in the + ``std::string`` including any embedded NULLs so this is not an issue, but + might cause interop problems if another library needs to validate the + password hashes.) + +.. cpp:function:: std::string generate_bcrypt(const std::string& password, \ + RandomNumberGenerator& rng, \ + uint16_t work_factor = 12, \ + char bcrypt_version = "a") + + Takes the password to hash, a rng, and a work factor. + The resulting password hash is returned as a string. + + Higher work factors increase the amount of time the algorithm runs, + increasing the cost of cracking attempts. The increase is exponential, so a + work factor of 12 takes roughly twice as long as work factor 11. The default + work factor was set to 10 up until the 2.8.0 release. + + It is recommended to set the work factor as high as your system can tolerate + (from a performance and latency perspective) since higher work factors greatly + improve the security against GPU-based attacks. For example, for protecting + high value administrator passwords, consider using work factor 15 or 16; at + these work factors each bcrypt computation takes several seconds. Since admin + logins will be relatively uncommon, it might be acceptable for each login + attempt to take some time. As of 2018, a good password cracking rig (with 8 + NVIDIA 1080 cards) can attempt about 1 billion bcrypt computations per month + for work factor 13. For work factor 12, it can do twice as many. For work + factor 15, it can do only one quarter as many attempts. + + Due to bugs affecting various implementations of bcrypt, several different + variants of the algorithm are defined. As of 2.7.0 Botan supports generating + (or checking) the 2a, 2b, and 2y variants. Since Botan has never been + affected by any of the bugs which necessitated these version upgrades, all + three versions are identical beyond the version identifier. Which variant to + use is controlled by the ``bcrypt_version`` argument. + + The bcrypt work factor must be at least 4 (though at this work factor bcrypt + is not very secure). The bcrypt format allows up to 31, but Botan currently + rejects all work factors greater than 18 since even that work factor requires + roughly 15 seconds of computation on a fast machine. + +.. cpp:function:: bool check_bcrypt(const std::string& password, \ + const std::string& hash) + + Takes a password and a bcrypt output and returns true if the + password is the same as the one that was used to generate the + bcrypt hash. + +.. _passhash9: + +Passhash9 +---------------------------------------- + +Botan also provides a password hashing technique called passhash9, in +``passhash9.h``, which is based on PBKDF2. + +Passhash9 hashes look like:: + + "$9$AAAKxwMGNPSdPkOKJS07Xutm3+1Cr3ytmbnkjO6LjHzCMcMQXvcT" + +This function should be secure with the proper parameters, and will remain in +the library for the foreseeable future, but it is specific to Botan rather than +being a widely used password hash. Prefer bcrypt or Argon2. + +.. warning:: + + This password format string ("$9$") conflicts with the format used + for scrypt password hashes on Cisco systems. + +.. cpp:function:: std::string generate_passhash9(const std::string& password, \ + RandomNumberGenerator& rng, uint16_t work_factor = 15, uint8_t alg_id = 4) + + Functions much like ``generate_bcrypt``. The last parameter, + ``alg_id``, specifies which PRF to use. Currently defined values are + 0: HMAC(SHA-1), 1: HMAC(SHA-256), 2: CMAC(Blowfish), 3: HMAC(SHA-384), 4: HMAC(SHA-512) + + The work factor must be greater than zero and less than 512. This performs + 10000 * ``work_factor`` PBKDF2 iterations, using 96 bits of salt taken from + ``rng``. Using work factor of 10 or more is recommended. + +.. cpp:function:: bool check_passhash9(const std::string& password, \ + const std::string& hash) + + Functions much like ``check_bcrypt`` diff --git a/doc/api_ref/pbkdf.rst b/doc/api_ref/pbkdf.rst new file mode 100644 index 000000000..92f59f278 --- /dev/null +++ b/doc/api_ref/pbkdf.rst @@ -0,0 +1,190 @@ + +.. _pbkdf: + +Password Based Key Derivation +======================================== + +Often one needs to convert a human readable password into a cryptographic +key. It is useful to slow down the computation of these computations in order to +reduce the speed of brute force search, thus they are parameterized in some +way which allows their required computation to be tuned. + +PBKDF +--------- + +:cpp:class:`PBKDF` is the older API for this functionality, presented in header +``pbkdf.h``. It does not support Scrypt, nor will it be able to support other +future hashes (such as Argon2) that may be added in the future. In addition, +this API requires the passphrase be entered as a ``std::string``, which means +the secret will be stored in memory that will not be zeroed. + +.. cpp:class:: PBKDF + + .. cpp:function:: void pbkdf_iterations(uint8_t out[], size_t out_len, \ + const std::string& passphrase, \ + const uint8_t salt[], size_t salt_len, \ + size_t iterations) const + + Run the PBKDF algorithm for the specified number of iterations, + with the given salt, and write output to the buffer. + + .. cpp:function:: void pbkdf_timed(uint8_t out[], size_t out_len, \ + const std::string& passphrase, \ + const uint8_t salt[], size_t salt_len, \ + std::chrono::milliseconds msec, \ + size_t& iterations) const + + Choose (via short run-time benchmark) how many iterations to perform + in order to run for roughly msec milliseconds. Writes the number + of iterations used to reference argument. + + .. cpp:function:: OctetString derive_key( \ + size_t output_len, const std::string& passphrase, \ + const uint8_t* salt, size_t salt_len, \ + size_t iterations) const + + Computes a key from *passphrase* and the *salt* (of length + *salt_len* bytes) using an algorithm-specific interpretation of + *iterations*, producing a key of length *output_len*. + + Use an iteration count of at least 10000. The salt should be + randomly chosen by a good random number generator (see + :ref:`random_number_generators` for how), or at the very least + unique to this usage of the passphrase. + + If you call this function again with the same parameters, you will + get the same key. + +PasswordHash +-------------- + +.. versionadded:: 2.8.0 + +This API has two classes, one representing the algorithm (such as +"PBKDF2(SHA-256)", or "Scrypt") and the other representing a specific instance +of the problem which is fully specified (say "Scrypt" with N=8192,r=64,p=8). + +.. cpp:class:: PasswordHash + + .. cpp:function:: void derive_key(uint8_t out[], size_t out_len, \ + const char* password, const size_t password_len, \ + const uint8_t salt[], size_t salt_len) const + + Derive a key, placing it into output + + .. cpp:function:: std::string to_string() const + + Return a descriptive string including the parameters (iteration count, etc) + +The ``PasswordHashFamily`` creates specific instances of ``PasswordHash``: + +.. cpp:class:: PasswordHashFamily + + .. cpp:function:: static std::unique_ptr<PasswordHashFamily> create(const std::string& what) + + For example "PBKDF2(SHA-256)", "Scrypt", "OpenPGP-S2K(SHA-384)". Returns + null if not available. + + .. cpp:function:: std::unique_ptr<PasswordHash> default_params() const + + Create a default instance of the password hashing algorithm. Be warned the + value returned here may change from release to release. + + .. cpp:function:: std::unique_ptr<PasswordHash> tune(size_t output_len, std::chrono::milliseconds msec) const + + Return a password hash instance tuned to run for approximately ``msec`` + milliseconds when producing an output of length ``output_len``. (Accuracy + may vary, use the command line utility ``botan pbkdf_tune`` to check.) + + .. cpp:function:: std::unique_ptr<PasswordHash> from_params( \ + size_t i1, size_t i2 = 0, size_t i3 = 0) const + + Create a password hash using some scheme specific format. + Eg PBKDF2 and PGP-S2K set iterations in i1 + Scrypt uses N,r,p in i{1-3} + Bcrypt-PBKDF just has iterations + Argon2{i,d,id} would use iterations, memory, parallelism for i{1-3}, and Argon2 type is part of the family. + + Values not needed should be set to 0. + +Available Schemes +---------------------- + +PBKDF2 +^^^^^^^^^^^^ + +PBKDF2 is the "standard" password derivation scheme, widely implemented in many +different libraries. It uses HMAC internally. + +Scrypt +^^^^^^^^^^ + +Scrypt is a relatively newer design which is "memory hard" - in +addition to requiring large amounts of CPU power it uses a large block +of memory to compute the hash. This makes brute force attacks using +ASICs substantially more expensive. + +Scrypt is not supported through :cpp:class:`PBKDF`, only :cpp:class:`PasswordHash`, +starting in 2.8.0. In addition, starting in version 2.7.0, scrypt is available +with this function: + +.. cpp:function:: void scrypt(uint8_t output[], size_t output_len, \ + const std::string& password, \ + const uint8_t salt[], size_t salt_len, \ + size_t N, size_t r, size_t p) + + Computes the Scrypt using the password and salt, and produces an output + of arbitrary length. + + The N, r, p parameters control how much work and memory Scrypt + uses. N is the primary control of the workfactor, and must be a + power of 2. For interactive logins use 32768, for protection of + secret keys or backups use 1048576. + + The r parameter controls how 'wide' the internal hashing operation + is. It also increases the amount of memory that is used. Values + from 1 to 8 are reasonable. + + Setting p parameter to greater than one splits up the work in a way + that up to p processors can work in parallel. + + As a general recommendation, use N=32768, r=8, p=1 + +Argon2 +^^^^^^^^^^ + +.. versionadded:: 2.11.0 + +Argon2 is the winner of the PHC (Password Hashing Competition) and +provides a tunable memory hard PBKDF. + +OpenPGP S2K +^^^^^^^^^^^^ + +.. warning:: + + The OpenPGP algorithm is weak and strange, and should be avoided unless + implementing OpenPGP. + +There are some oddities about OpenPGP's S2K algorithms that are documented +here. For one thing, it uses the iteration count in a strange manner; instead of +specifying how many times to iterate the hash, it tells how many *bytes* should +be hashed in total (including the salt). So the exact iteration count will +depend on the size of the salt (which is fixed at 8 bytes by the OpenPGP +standard, though the implementation will allow any salt size) and the size of +the passphrase. + +To get what OpenPGP calls "Simple S2K", set iterations to 0, and do not specify +a salt. To get "Salted S2K", again leave the iteration count at 0, but give an +8-byte salt. "Salted and Iterated S2K" requires an 8-byte salt and some +iteration count (this should be significantly larger than the size of the +longest passphrase that might reasonably be used; somewhere from 1024 to 65536 +would probably be about right). Using both a reasonably sized salt and a large +iteration count is highly recommended to prevent password guessing attempts. + +PBKDF1 +^^^^^^^^^^^^ + +PBKDF1 is an old scheme that can only produce an output length at most +as long as the hash function. It is deprecated and will be removed in +a future release. It is not supported through :cpp:class:`PasswordHash`. diff --git a/doc/api_ref/pkcs11.rst b/doc/api_ref/pkcs11.rst new file mode 100644 index 000000000..781777264 --- /dev/null +++ b/doc/api_ref/pkcs11.rst @@ -0,0 +1,1398 @@ +.. _pkcs11: + +PKCS#11 +======================================== + +.. versionadded:: 1.11.31 + +| + +PKCS#11 is a platform-independent interface for accessing smart cards and +hardware security modules (HSM). Vendors of PKCS#11 compatible devices usually +provide a so called middleware or "PKCS#11 module" which implements the PKCS#11 +standard. This middleware translates calls from the platform-independent PKCS#11 +API to device specific calls. So application developers don't have to write smart card +or HSM specific code for each device they want to support. + + .. note:: + + The Botan PKCS#11 interface is implemented against version v2.40 of the standard. + +Botan wraps the C PKCS#11 API to provide a C++ PKCS#11 interface. This is done +in two levels of abstraction: a low level API (see :ref:`pkcs11_low_level`) and +a high level API (see :ref:`pkcs11_high_level`). The low level API provides +access to all functions that are specified by the standard. The high level API +represents an object oriented approach to use PKCS#11 compatible devices but +only provides a subset of the functions described in the standard. + +To use the PKCS#11 implementation the ``pkcs11`` module has to be enabled. + + .. note:: + + Both PKCS#11 APIs live in the namespace ``Botan::PKCS11`` + +.. _pkcs11_low_level: + +Low Level API +---------------------------------------- + +The PKCS#11 standards committee provides header files (``pkcs11.h``, ``pkcs11f.h`` and +``pkcs11t.h``) which define the PKCS#11 API in the C programming language. These +header files could be used directly to access PKCS#11 compatible smart cards or +HSMs. The external header files are shipped with Botan in version v2.4 of the standard. The PKCS#11 low +level API wraps the original PKCS#11 API, but still allows to access all functions described in the +standard and has the advantage that it is a C++ interface with features like RAII, exceptions +and automatic memory management. + +The low level API is implemented by the :cpp:class:`LowLevel` class and can be accessed by +including the header ``botan/p11.h``. + +Preface +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +All constants that belong together in the PKCS#11 standard are grouped into C++ +enum classes. For example the different user types are grouped in the +:cpp:enum:`UserType` enumeration: + +.. cpp:enum-class:: UserType : CK_USER_TYPE + + .. cpp:enumerator:: UserType::SO = CKU_SO + .. cpp:enumerator:: UserType::User = CKU_USER + .. cpp:enumerator:: UserType::ContextSpecific = CKU_CONTEXT_SPECIFIC + +Additionally, all types that are used by the low or high level API are mapped by +type aliases to more C++ like names. For instance: + +.. cpp:type:: FunctionListPtr = CK_FUNCTION_LIST_PTR + +.. rubric:: C-API Wrapping + +There is at least one method in the :cpp:class:`LowLevel` class that corresponds to a PKCS#11 +function. For example the :cpp:func:`C_GetSlotList` method in the :cpp:class:`LowLevel` class is defined as follows: + +.. cpp:class:: LowLevel + + .. cpp:function:: bool C_GetSlotList(Bbool token_present, SlotId* slot_list_ptr, Ulong* count_ptr, ReturnValue* return_value = ThrowException) const + +The :cpp:class:`LowLevel` class calls the PKCS#11 function from the function list of the PKCS#11 module: + + .. code-block:: c + + CK_DEFINE_FUNCTION(CK_RV, C_GetSlotList)( CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, + CK_ULONG_PTR pulCount ) + +Where it makes sense there is also an overload of the :cpp:class:`LowLevel` method to make usage easier and safer: + + .. cpp:function:: bool C_GetSlotList( bool token_present, std::vector<SlotId>& slot_ids, ReturnValue* return_value = ThrowException ) const + +With this overload the user of this API just has to pass a vector of :cpp:type:`SlotId` instead of pointers +to preallocated memory for the slot list and the number of elements. Additionally, there is no need +to call the method twice in order to determine the number of elements first. + +Another example is the :cpp:func:`C_InitPIN` overload: + + .. cpp:function:: template<typename Talloc> bool C_InitPIN( SessionHandle session, const std::vector<uint8_t, TAlloc>& pin, ReturnValue* return_value = ThrowException ) const + +The templated ``pin`` parameter allows to pass the PIN as a ``std::vector<uint8_t>`` or a ``secure_vector<uint8_t>``. +If used with a ``secure_vector`` it is assured that the memory is securely erased when the ``pin`` object is no longer needed. + +Error Handling +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +All possible PKCS#11 return values are represented by the enum class: + +.. cpp:enum-class:: ReturnValue : CK_RV + +All methods of the :cpp:class:`LowLevel` class have a default parameter ``ReturnValue* return_value = ThrowException``. +This parameter controls the error handling of all :cpp:class:`LowLevel` methods. The default +behavior ``return_value = ThrowException`` is to throw an exception if the method does +not complete successfully. If a non-``NULL`` pointer is passed, ``return_value`` receives the +return value of the PKCS#11 function and no exception is thrown. In case ``nullptr`` is +passed as ``return_value``, the exact return value is ignored and the method just returns +``true`` if the function succeeds and ``false`` otherwise. + +Getting started +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +An object of this class can be instantiated by providing a :cpp:type:`FunctionListPtr` to the :cpp:class:`LowLevel` constructor: + + .. cpp:function:: explicit LowLevel(FunctionListPtr ptr) + +The :cpp:class:`LowLevel` class provides a static method to retrieve a :cpp:type:`FunctionListPtr` +from a PKCS#11 module file: + + .. cpp:function:: static bool C_GetFunctionList(Dynamically_Loaded_Library& pkcs11_module, FunctionListPtr* function_list_ptr_ptr, ReturnValue* return_value = ThrowException) + +---------- + +Code Example: Object Instantiation + + .. code-block:: cpp + + Botan::Dynamically_Loaded_Library pkcs11_module( "C:\\pkcs11-middleware\\library.dll" ); + Botan::PKCS11::FunctionListPtr func_list = nullptr; + Botan::PKCS11::LowLevel::C_GetFunctionList( pkcs11_module, &func_list ); + Botan::PKCS11::LowLevel p11_low_level( func_list ); + +---------- + +Code Example: PKCS#11 Module Initialization + + .. code-block:: cpp + + Botan::PKCS11::LowLevel p11_low_level(func_list); + + Botan::PKCS11::C_InitializeArgs init_args = { nullptr, nullptr, nullptr, nullptr, + static_cast<CK_FLAGS>(Botan::PKCS11::Flag::OsLockingOk), nullptr }; + + p11_low_level.C_Initialize(&init_args); + + // work with the token + + p11_low_level.C_Finalize(nullptr); + +More code examples can be found in the test suite in the ``test_pkcs11_low_level.cpp`` file. + +.. _pkcs11_high_level: + +High Level API +---------------------------------------- + +The high level API provides access to the most commonly used PKCS#11 functionality in an +object oriented manner. Functionality of the high level API includes: + +* Loading/unloading of PKCS#11 modules +* Initialization of tokens +* Change of PIN/SO-PIN +* Session management +* Random number generation +* Enumeration of objects on the token (certificates, public keys, private keys) +* Import/export/deletion of certificates +* Generation/import/export/deletion of RSA and EC public and private keys +* Encryption/decryption using RSA with support for OAEP and PKCS1-v1_5 (and raw) +* Signature generation/verification using RSA with support for PSS and PKCS1-v1_5 (and raw) +* Signature generation/verification using ECDSA +* Key derivation using ECDH + +Module +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :cpp:class:`Module` class represents a PKCS#11 shared library (module) and is defined in +``botan/p11_module.h``. + +It is constructed from a a file path to a PKCS#11 module and optional :cpp:type:`C_InitializeArgs`: + +.. cpp:class:: Module + + .. code-block:: cpp + + Module(const std::string& file_path, C_InitializeArgs init_args = + { nullptr, nullptr, nullptr, nullptr, static_cast<CK_FLAGS>(Flag::OsLockingOk), nullptr }) + + It loads the shared library and calls :cpp:func:`C_Initialize` with the provided :cpp:type:`C_InitializeArgs`. + On destruction of the object :cpp:func:`C_Finalize` is called. + +There are two more methods in this class. One is for reloading the shared library +and reinitializing the PKCS#11 module: + + .. code-block:: cpp + + void reload(C_InitializeArgs init_args = + { nullptr, nullptr, nullptr, nullptr, static_cast< CK_FLAGS >(Flag::OsLockingOk), nullptr }); + +The other one is for getting general information about the PKCS#11 module: + + .. cpp:function:: Info get_info() const + + This function calls :cpp:func:`C_GetInfo` internally. + +---------- + +Code example: + + .. code-block:: cpp + + Botan::PKCS11::Module module( "C:\\pkcs11-middleware\\library.dll" ); + + // Sometimes useful if a newly connected token is not detected by the PKCS#11 module + module.reload(); + + Botan::PKCS11::Info info = module.get_info(); + + // print library version + std::cout << std::to_string( info.libraryVersion.major ) << "." + << std::to_string( info.libraryVersion.minor ) << std::endl; + +Slot +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :cpp:class:`Slot` class represents a PKCS#11 slot and is defined in +``botan/p11_slot.h``. + +A PKCS#11 slot is usually a smart card reader that potentially contains a token. + +.. cpp:class:: Slot + + .. cpp:function:: Slot(Module& module, SlotId slot_id) + + To instantiate this class a reference to a :cpp:class:`Module` object and a ``slot_id`` have to be passed + to the constructor. + + .. cpp:function:: static std::vector<SlotId> get_available_slots(Module& module, bool token_present) + + Retrieve available slot ids by calling this static method. + + The parameter ``token_present`` controls whether all slots or only slots with a + token attached are returned by this method. This method calls :cpp:func:`C_GetSlotList()`. + + .. cpp:function:: SlotInfo get_slot_info() const + + Returns information about the slot. Calls :cpp:func:`C_GetSlotInfo`. + + .. cpp:function:: TokenInfo get_token_info() const + + Obtains information about a particular token in the system. Calls :cpp:func:`C_GetTokenInfo`. + + .. cpp:function:: std::vector<MechanismType> get_mechanism_list() const + + Obtains a list of mechanism types supported by the slot. Calls :cpp:func:`C_GetMechanismList`. + + .. cpp:function:: MechanismInfo get_mechanism_info(MechanismType mechanism_type) const + + Obtains information about a particular mechanism possibly supported by a slot. + Calls :cpp:func:`C_GetMechanismInfo`. + + .. cpp:function:: void initialize(const std::string& label, const secure_string& so_pin) const + + Calls :cpp:func:`C_InitToken` to initialize the token. The ``label`` must not exceed 32 bytes. + The current PIN of the security officer must be passed in ``so_pin`` if the token + is reinitialized or if it's a factory new token, the ``so_pin`` that is passed will initially be set. + +---------- + +Code example: + + .. code-block:: cpp + + // only slots with connected token + std::vector<Botan::PKCS11::SlotId> slots = Botan::PKCS11::Slot::get_available_slots( module, true ); + + // use first slot + Botan::PKCS11::Slot slot( module, slots.at( 0 ) ); + + // print firmware version of the slot + Botan::PKCS11::SlotInfo slot_info = slot.get_slot_info(); + std::cout << std::to_string( slot_info.firmwareVersion.major ) << "." + << std::to_string( slot_info.firmwareVersion.minor ) << std::endl; + + // print firmware version of the token + Botan::PKCS11::TokenInfo token_info = slot.get_token_info(); + std::cout << std::to_string( token_info.firmwareVersion.major ) << "." + << std::to_string( token_info.firmwareVersion.minor ) << std::endl; + + // retrieve all mechanisms supported by the token + std::vector<Botan::PKCS11::MechanismType> mechanisms = slot.get_mechanism_list(); + + // retrieve information about a particular mechanism + Botan::PKCS11::MechanismInfo mech_info = + slot.get_mechanism_info( Botan::PKCS11::MechanismType::RsaPkcsOaep ); + + // maximum RSA key length supported: + std::cout << mech_info.ulMaxKeySize << std::endl; + + // initialize the token + Botan::PKCS11::secure_string so_pin( 8, '0' ); + slot.initialize( "Botan PKCS11 documentation test label", so_pin ); + +Session +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :cpp:class:`Session` class represents a PKCS#11 session and is defined in ``botan/p11_session.h``. + +A session is a logical connection between an application and a token. + +.. cpp:class:: Session + + There are two constructors to create a new session and one constructor to + take ownership of an existing session. The destructor calls + :cpp:func:`C_Logout` if a user is logged in to this session and always + :cpp:func:`C_CloseSession`. + + .. cpp:function:: Session(Slot& slot, bool read_only) + + To initialize a session object a :cpp:class:`Slot` has to be specified on which the session + should operate. ``read_only`` specifies whether the session should be read only or read write. + Calls :cpp:func:`C_OpenSession`. + + .. cpp:function:: Session(Slot& slot, Flags flags, VoidPtr callback_data, Notify notify_callback) + + Creates a new session by passing a :cpp:class:`Slot`, session ``flags``, ``callback_data`` and a + ``notify_callback``. Calls :cpp:func:`C_OpenSession`. + + .. cpp:function:: Session(Slot& slot, SessionHandle handle) + + Takes ownership of an existing session by passing :cpp:class:`Slot` and a session ``handle``. + + .. cpp:function:: SessionHandle release() + + Returns the released :cpp:type:`SessionHandle` + + .. cpp:function:: void login(UserType userType, const secure_string& pin) + + Login to this session by passing :cpp:enum:`UserType` and ``pin``. Calls :cpp:func:`C_Login`. + + .. cpp:function:: void logoff() + + Logout from this session. Not mandatory because on destruction of the :cpp:class:`Session` object + this is done automatically. + + .. cpp:function:: SessionInfo get_info() const + + Returns information about this session. Calls :cpp:func:`C_GetSessionInfo`. + + .. cpp:function:: void set_pin(const secure_string& old_pin, const secure_string& new_pin) const + + Calls :cpp:func:`C_SetPIN` to change the PIN of the logged in user using the ``old_pin``. + + .. cpp:function:: void init_pin(const secure_string& new_pin) + + Calls :cpp:func:`C_InitPIN` to change or initialize the PIN using the SO_PIN (requires a logged in session). + +---------- + +Code example: + + .. code-block:: cpp + + // open read only session + { + Botan::PKCS11::Session read_only_session( slot, true ); + } + + // open read write session + { + Botan::PKCS11::Session read_write_session( slot, false ); + } + + // open read write session by passing flags + { + Botan::PKCS11::Flags flags = + Botan::PKCS11::flags( Botan::PKCS11::Flag::SerialSession | Botan::PKCS11::Flag::RwSession ); + + Botan::PKCS11::Session read_write_session( slot, flags, nullptr, nullptr ); + } + + // move ownership of a session + { + Botan::PKCS11::Session session( slot, false ); + Botan::PKCS11::SessionHandle handle = session.release(); + + Botan::PKCS11::Session session2( slot, handle ); + } + + Botan::PKCS11::Session session( slot, false ); + + // get session info + Botan::PKCS11::SessionInfo info = session.get_info(); + std::cout << info.slotID << std::endl; + + // login + Botan::PKCS11::secure_string pin = { '1', '2', '3', '4', '5', '6' }; + session.login( Botan::PKCS11::UserType::User, pin ); + + // set pin + Botan::PKCS11::secure_string new_pin = { '6', '5', '4', '3', '2', '1' }; + session.set_pin( pin, new_pin ); + + // logoff + session.logoff(); + + // log in as security officer + Botan::PKCS11::secure_string so_pin = { '0', '0', '0', '0', '0', '0', '0', '0' }; + session.login( Botan::PKCS11::UserType::SO, so_pin ); + + // change pin to old pin + session.init_pin( pin ); + +Objects +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +PKCS#11 objects consist of various attributes (:c:type:`CK_ATTRIBUTE`). For example :c:macro:`CKA_TOKEN` +describes if a PKCS#11 object is a session object or a token object. The helper class :cpp:class:`AttributeContainer` +helps with storing these attributes. The class is defined in ``botan/p11_object.h``. + +.. cpp:class:: AttributeContainer + +Attributes can be set in an :cpp:class:`AttributeContainer` by various ``add_`` methods: + + .. cpp:function:: void add_class(ObjectClass object_class) + + Add a class attribute (:c:macro:`CKA_CLASS` / :cpp:enumerator:`AttributeType::Class`) + + .. cpp:function:: void add_string(AttributeType attribute, const std::string& value) + + Add a string attribute (e.g. :c:macro:`CKA_LABEL` / :cpp:enumerator:`AttributeType::Label`). + + .. cpp:function:: void AttributeContainer::add_binary(AttributeType attribute, const uint8_t* value, size_t length) + + Add a binary attribute (e.g. :c:macro:`CKA_ID` / :cpp:enumerator:`AttributeType::Id`). + + .. cpp:function:: template<typename TAlloc> void AttributeContainer::add_binary(AttributeType attribute, const std::vector<uint8_t, TAlloc>& binary) + + Add a binary attribute by passing a ``vector``/``secure_vector`` (e.g. :c:macro:`CKA_ID` / :cpp:enumerator:`AttributeType::Id`). + + .. cpp:function:: void AttributeContainer::add_bool(AttributeType attribute, bool value) + + Add a bool attribute (e.g. :c:macro:`CKA_SENSITIVE` / :cpp:enumerator:`AttributeType::Sensitive`). + + .. cpp:function:: template<typename T> void AttributeContainer::add_numeric(AttributeType attribute, T value) + + Add a numeric attribute (e.g. :c:macro:`CKA_MODULUS_BITS` / :cpp:enumerator:`AttributeType::ModulusBits`). + +.. rubric:: Object Properties + +The PKCS#11 standard defines the mandatory and optional attributes for each object class. +The mandatory and optional attribute requirements are mapped in so called property classes. +Mandatory attributes are set in the constructor, optional attributes can be set via ``set_`` methods. + +In the top hierarchy is the :cpp:class:`ObjectProperties` class which inherits from the :cpp:class:`AttributeContainer`. +This class represents the common attributes of all PKCS#11 objects. + +.. cpp:class:: ObjectProperties : public AttributeContainer + +The constructor is defined as follows: + + .. cpp:function:: ObjectProperties(ObjectClass object_class) + + Every PKCS#11 object needs an object class attribute. + +The next level defines the :cpp:class:`StorageObjectProperties` class which inherits from +:cpp:class:`ObjectProperties`. + +.. cpp:class:: StorageObjectProperties : public ObjectProperties + +The only mandatory attribute is the object class, so the constructor is +defined as follows: + + .. cpp:function:: StorageObjectProperties(ObjectClass object_class) + +But in contrast to the :cpp:class:`ObjectProperties` class there are various setter methods. For example to +set the :cpp:enumerator:`AttributeType::Label`: + + .. cpp:function:: void set_label(const std::string& label) + + Sets the label description of the object (RFC2279 string). + +The remaining hierarchy is defined as follows: + +* :cpp:class:`DataObjectProperties` inherits from :cpp:class:`StorageObjectProperties` +* :cpp:class:`CertificateProperties` inherits from :cpp:class:`StorageObjectProperties` +* :cpp:class:`DomainParameterProperties` inherits from :cpp:class:`StorageObjectProperties` +* :cpp:class:`KeyProperties` inherits from :cpp:class:`StorageObjectProperties` +* :cpp:class:`PublicKeyProperties` inherits from :cpp:class:`KeyProperties` +* :cpp:class:`PrivateKeyProperties` inherits from :cpp:class:`KeyProperties` +* :cpp:class:`SecretKeyProperties` inherits from :cpp:class:`KeyProperties` + +PKCS#11 objects themselves are represented by the :cpp:class:`Object` class. + +.. cpp:class:: Object + +Following constructors are defined: + + .. cpp:function:: Object(Session& session, ObjectHandle handle) + + Takes ownership over an existing object. + + .. cpp:function:: Object(Session& session, const ObjectProperties& obj_props) + + Creates a new object with the :cpp:class:`ObjectProperties` provided in ``obj_props``. + +The other methods are: + + .. cpp:function:: secure_vector<uint8_t> get_attribute_value(AttributeType attribute) const + + Returns the value of the given attribute (using :cpp:func:`C_GetAttributeValue`) + + .. cpp:function:: void set_attribute_value(AttributeType attribute, const secure_vector<uint8_t>& value) const + + Sets the given value for the attribute (using :cpp:func:`C_SetAttributeValue`) + + .. cpp:function:: void destroy() const + + Destroys the object. + + .. cpp:function:: ObjectHandle copy(const AttributeContainer& modified_attributes) const + + Allows to copy the object with modified attributes. + +And static methods to search for objects: + + .. cpp:function:: template<typename T> static std::vector<T> search(Session& session, const std::vector<Attribute>& search_template) + + Searches for all objects of the given type that match ``search_template``. + + .. cpp:function:: template<typename T> static std::vector<T> search(Session& session, const std::string& label) + + Searches for all objects of the given type using the label (:c:macro:`CKA_LABEL`). + + .. cpp:function:: template<typename T> static std::vector<T> search(Session& session, const std::vector<uint8_t>& id) + + Searches for all objects of the given type using the id (:c:macro:`CKA_ID`). + + .. cpp:function:: template<typename T> static std::vector<T> search(Session& session, const std::string& label, const std::vector<uint8_t>& id) + + Searches for all objects of the given type using the label (:c:macro:`CKA_LABEL`) and id (:c:macro:`CKA_ID`). + + .. cpp:function:: template<typename T> static std::vector<T> search(Session& session) + + Searches for all objects of the given type. + +.. rubric:: The ObjectFinder + +Another way for searching objects is to use the :cpp:class:`ObjectFinder` class. This class +manages calls to the ``C_FindObjects*`` functions: :cpp:func:`C_FindObjectsInit`, :cpp:func:`C_FindObjects` +and :cpp:func:`C_FindObjectsFinal`. + +.. cpp:class:: ObjectFinder + +The constructor has the following signature: + + .. cpp:function:: ObjectFinder(Session& session, const std::vector<Attribute>& search_template) + + A search can be prepared with an :cpp:class:`ObjectSearcher` by passing a :cpp:class:`Session` and a ``search_template``. + +The actual search operation is started by calling the :cpp:func:`find` method: + + .. cpp:function:: std::vector<ObjectHandle> find(std::uint32_t max_count = 100) const + + Starts or continues a search for token and session objects that match a template. ``max_count`` + specifies the maximum number of search results (object handles) that are returned. + + .. cpp:function:: void finish() + + Finishes the search operation manually to allow a new :cpp:class:`ObjectFinder` to exist. + Otherwise the search is finished by the destructor. + +---------- + +Code example: + + .. code-block:: cpp + + // create an simple data object + Botan::secure_vector<uint8_t> value = { 0x00, 0x01 ,0x02, 0x03 }; + std::size_t id = 1337; + std::string label = "test data object"; + + // set properties of the new object + Botan::PKCS11::DataObjectProperties data_obj_props; + data_obj_props.set_label( label ); + data_obj_props.set_value( value ); + data_obj_props.set_token( true ); + data_obj_props.set_modifiable( true ); + data_obj_props.set_object_id( Botan::DER_Encoder().encode( id ).get_contents_unlocked() ); + + // create the object + Botan::PKCS11::Object data_obj( session, data_obj_props ); + + // get label of this object + Botan::PKCS11::secure_string retrieved_label = + data_obj.get_attribute_value( Botan::PKCS11::AttributeType::Label ); + + // set a new label + Botan::PKCS11::secure_string new_label = { 'B', 'o', 't', 'a', 'n' }; + data_obj.set_attribute_value( Botan::PKCS11::AttributeType::Label, new_label ); + + // copy the object + Botan::PKCS11::AttributeContainer copy_attributes; + copy_attributes.add_string( Botan::PKCS11::AttributeType::Label, "copied object" ); + Botan::PKCS11::ObjectHandle copied_obj_handle = data_obj.copy( copy_attributes ); + + // search for an object + Botan::PKCS11::AttributeContainer search_template; + search_template.add_string( Botan::PKCS11::AttributeType::Label, "Botan" ); + auto found_objs = + Botan::PKCS11::Object::search<Botan::PKCS11::Object>( session, search_template.attributes() ); + + // destroy the object + data_obj.destroy(); + +RSA +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +PKCS#11 RSA support is implemented in ``<botan/p11_rsa.h>``. + +.. rubric:: RSA Public Keys + +PKCS#11 RSA public keys are provided by the class :cpp:class:`PKCS11_RSA_PublicKey`. This class +inherits from :cpp:class:`RSA_PublicKey` and :cpp:class:`Object`. Furthermore there are two property classes defined +to generate and import RSA public keys analogous to the other property classes described +before: :cpp:class:`RSA_PublicKeyGenerationProperties` and :cpp:class:`RSA_PublicKeyImportProperties`. + +.. cpp:class:: PKCS11_RSA_PublicKey : public RSA_PublicKey, public Object + + .. cpp:function:: PKCS11_RSA_PublicKey(Session& session, ObjectHandle handle) + + Existing PKCS#11 RSA public keys can be used by providing an :cpp:type:`ObjectHandle` to the + constructor. + + .. cpp:function:: PKCS11_RSA_PublicKey(Session& session, const RSA_PublicKeyImportProperties& pubkey_props) + + This constructor can be used to import an existing RSA public key with the :cpp:class:`RSA_PublicKeyImportProperties` + passed in ``pubkey_props`` to the token. + +.. rubric:: RSA Private Keys + +The support for PKCS#11 RSA private keys is implemented in a similar way. There are two property +classes: :cpp:class:`RSA_PrivateKeyGenerationProperties` and :cpp:class:`RSA_PrivateKeyImportProperties`. The :cpp:class:`PKCS11_RSA_PrivateKey` +class implements the actual support for PKCS#11 RSA private keys. This class inherits from :cpp:class:`Private_Key`, +:cpp:class:`RSA_PublicKey` and :cpp:class:`Object`. In contrast to the public key class there is a third constructor +to generate private keys directly on the token or in the session and one method to export private keys. + +.. cpp:class:: PKCS11_RSA_PrivateKey : public Private_Key, public RSA_PublicKey, public Object + + .. cpp:function:: PKCS11_RSA_PrivateKey(Session& session, ObjectHandle handle) + + Existing PKCS#11 RSA private keys can be used by providing an :cpp:type:`ObjectHandle` to the + constructor. + + .. cpp:function:: PKCS11_RSA_PrivateKey(Session& session, const RSA_PrivateKeyImportProperties& priv_key_props) + + This constructor can be used to import an existing RSA private key with the :cpp:class:`RSA_PrivateKeyImportProperties` + passed in ``priv_key_props`` to the token. + + .. cpp:function:: PKCS11_RSA_PrivateKey(Session& session, uint32_t bits, const RSA_PrivateKeyGenerationProperties& priv_key_props) + + Generates a new PKCS#11 RSA private key with bit length provided in ``bits`` and the :cpp:class:`RSA_PrivateKeyGenerationProperties` + passed in ``priv_key_props``. + + .. cpp:function:: RSA_PrivateKey export_key() const + + Returns the exported :cpp:class:`RSA_PrivateKey`. + +PKCS#11 RSA key pairs can be generated with the following free function: + + .. cpp:function:: PKCS11_RSA_KeyPair PKCS11::generate_rsa_keypair(Session& session, const RSA_PublicKeyGenerationProperties& pub_props, const RSA_PrivateKeyGenerationProperties& priv_props) + +---------- + +Code example: + + .. code-block:: cpp + + Botan::PKCS11::secure_string pin = { '1', '2', '3', '4', '5', '6' }; + session.login( Botan::PKCS11::UserType::User, pin ); + + /************ import RSA private key *************/ + + // create private key in software + Botan::AutoSeeded_RNG rng; + Botan::RSA_PrivateKey priv_key_sw( rng, 2048 ); + + // set the private key import properties + Botan::PKCS11::RSA_PrivateKeyImportProperties + priv_import_props( priv_key_sw.get_n(), priv_key_sw.get_d() ); + + priv_import_props.set_pub_exponent( priv_key_sw.get_e() ); + priv_import_props.set_prime_1( priv_key_sw.get_p() ); + priv_import_props.set_prime_2( priv_key_sw.get_q() ); + priv_import_props.set_coefficient( priv_key_sw.get_c() ); + priv_import_props.set_exponent_1( priv_key_sw.get_d1() ); + priv_import_props.set_exponent_2( priv_key_sw.get_d2() ); + + priv_import_props.set_token( true ); + priv_import_props.set_private( true ); + priv_import_props.set_decrypt( true ); + priv_import_props.set_sign( true ); + + // import + Botan::PKCS11::PKCS11_RSA_PrivateKey priv_key( session, priv_import_props ); + + /************ export PKCS#11 RSA private key *************/ + Botan::RSA_PrivateKey exported = priv_key.export_key(); + + /************ import RSA public key *************/ + + // set the public key import properties + Botan::PKCS11::RSA_PublicKeyImportProperties pub_import_props( priv_key.get_n(), priv_key.get_e() ); + pub_import_props.set_token( true ); + pub_import_props.set_encrypt( true ); + pub_import_props.set_private( false ); + + // import + Botan::PKCS11::PKCS11_RSA_PublicKey public_key( session, pub_import_props ); + + /************ generate RSA private key *************/ + + Botan::PKCS11::RSA_PrivateKeyGenerationProperties priv_generate_props; + priv_generate_props.set_token( true ); + priv_generate_props.set_private( true ); + priv_generate_props.set_sign( true ); + priv_generate_props.set_decrypt( true ); + priv_generate_props.set_label( "BOTAN_TEST_RSA_PRIV_KEY" ); + + Botan::PKCS11::PKCS11_RSA_PrivateKey private_key2( session, 2048, priv_generate_props ); + + /************ generate RSA key pair *************/ + + Botan::PKCS11::RSA_PublicKeyGenerationProperties pub_generate_props( 2048UL ); + pub_generate_props.set_pub_exponent(); + pub_generate_props.set_label( "BOTAN_TEST_RSA_PUB_KEY" ); + pub_generate_props.set_token( true ); + pub_generate_props.set_encrypt( true ); + pub_generate_props.set_verify( true ); + pub_generate_props.set_private( false ); + + Botan::PKCS11::PKCS11_RSA_KeyPair rsa_keypair = + Botan::PKCS11::generate_rsa_keypair( session, pub_generate_props, priv_generate_props ); + + /************ RSA encrypt *************/ + + Botan::secure_vector<uint8_t> plaintext = { 0x00, 0x01, 0x02, 0x03 }; + Botan::PK_Encryptor_EME encryptor( rsa_keypair.first, rng, "Raw" ); + auto ciphertext = encryptor.encrypt( plaintext, rng ); + + /************ RSA decrypt *************/ + + Botan::PK_Decryptor_EME decryptor( rsa_keypair.second, rng, "Raw" ); + plaintext = decryptor.decrypt( ciphertext ); + + /************ RSA sign *************/ + + Botan::PK_Signer signer( rsa_keypair.second, rng, "EMSA4(SHA-256)", Botan::IEEE_1363 ); + auto signature = signer.sign_message( plaintext, rng ); + + /************ RSA verify *************/ + + Botan::PK_Verifier verifier( rsa_keypair.first, "EMSA4(SHA-256)", Botan::IEEE_1363 ); + auto ok = verifier.verify_message( plaintext, signature ); + +ECDSA +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +PKCS#11 ECDSA support is implemented in ``<botan/p11_ecdsa.h>``. + +.. rubric:: ECDSA Public Keys + +PKCS#11 ECDSA public keys are provided by the class :cpp:class:`PKCS11_ECDSA_PublicKey`. This class +inherits from :cpp:class:`PKCS11_EC_PublicKey` and :cpp:class:`ECDSA_PublicKey`. The necessary property classes +are defined in ``<botan/p11_ecc_key.h>``. For public keys there are :cpp:class:`EC_PublicKeyGenerationProperties` +and :cpp:class:`EC_PublicKeyImportProperties`. + +.. cpp:class:: PKCS11_ECDSA_PublicKey : public PKCS11_EC_PublicKey, public virtual ECDSA_PublicKey + + .. cpp:function:: PKCS11_ECDSA_PublicKey(Session& session, ObjectHandle handle) + + Existing PKCS#11 ECDSA private keys can be used by providing an :cpp:type:`ObjectHandle` to the + constructor. + + .. cpp:function:: PKCS11_ECDSA_PublicKey(Session& session, const EC_PublicKeyImportProperties& props) + + This constructor can be used to import an existing ECDSA public key with the :cpp:class:`EC_PublicKeyImportProperties` + passed in ``props`` to the token. + + .. cpp:function:: ECDSA_PublicKey PKCS11_ECDSA_PublicKey::export_key() const + + Returns the exported :cpp:class:`ECDSA_PublicKey`. + +.. rubric:: ECDSA Private Keys + +The class :cpp:class:`PKCS11_ECDSA_PrivateKey` inherits from :cpp:class:`PKCS11_EC_PrivateKey` and implements support +for PKCS#11 ECDSA private keys. There are two property classes for key generation +and import: :cpp:class:`EC_PrivateKeyGenerationProperties` and :cpp:class:`EC_PrivateKeyImportProperties`. + +.. cpp:class:: PKCS11_ECDSA_PrivateKey : public PKCS11_EC_PrivateKey + + .. cpp:function:: PKCS11_ECDSA_PrivateKey(Session& session, ObjectHandle handle) + + Existing PKCS#11 ECDSA private keys can be used by providing an :cpp:type:`ObjectHandle` to the + constructor. + + .. cpp:function:: PKCS11_ECDSA_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props) + + This constructor can be used to import an existing ECDSA private key with the :cpp:class:`EC_PrivateKeyImportProperties` + passed in ``props`` to the token. + + .. cpp:function:: PKCS11_ECDSA_PrivateKey(Session& session, const std::vector<uint8_t>& ec_params, const EC_PrivateKeyGenerationProperties& props) + + This constructor can be used to generate a new ECDSA private key with the :cpp:class:`EC_PrivateKeyGenerationProperties` + passed in ``props`` on the token. The ``ec_params`` parameter is the DER-encoding of an + ANSI X9.62 Parameters value. + + .. cpp:function:: ECDSA_PrivateKey export_key() const + + Returns the exported :cpp:class:`ECDSA_PrivateKey`. + +PKCS#11 ECDSA key pairs can be generated with the following free function: + + .. cpp:function:: PKCS11_ECDSA_KeyPair PKCS11::generate_ecdsa_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props, const EC_PrivateKeyGenerationProperties& priv_props) + +---------- + +Code example: + + .. code-block:: cpp + + Botan::PKCS11::secure_string pin = { '1', '2', '3', '4', '5', '6' }; + session.login( Botan::PKCS11::UserType::User, pin ); + + /************ import ECDSA private key *************/ + + // create private key in software + Botan::AutoSeeded_RNG rng; + + Botan::ECDSA_PrivateKey priv_key_sw( rng, Botan::EC_Group( "secp256r1" ) ); + priv_key_sw.set_parameter_encoding( Botan::EC_Group_Encoding::EC_DOMPAR_ENC_OID ); + + // set the private key import properties + Botan::PKCS11::EC_PrivateKeyImportProperties priv_import_props( + priv_key_sw.DER_domain(), priv_key_sw.private_value() ); + + priv_import_props.set_token( true ); + priv_import_props.set_private( true ); + priv_import_props.set_sign( true ); + priv_import_props.set_extractable( true ); + + // label + std::string label = "test ECDSA key"; + priv_import_props.set_label( label ); + + // import to card + Botan::PKCS11::PKCS11_ECDSA_PrivateKey priv_key( session, priv_import_props ); + + /************ export PKCS#11 ECDSA private key *************/ + Botan::ECDSA_PrivateKey priv_exported = priv_key.export_key(); + + /************ import ECDSA public key *************/ + + // import to card + Botan::PKCS11::EC_PublicKeyImportProperties pub_import_props( priv_key_sw.DER_domain(), + Botan::DER_Encoder().encode( EC2OSP( priv_key_sw.public_point(), Botan::PointGFp::UNCOMPRESSED ), + Botan::OCTET_STRING ).get_contents_unlocked() ); + + pub_import_props.set_token( true ); + pub_import_props.set_verify( true ); + pub_import_props.set_private( false ); + + // label + label = "test ECDSA pub key"; + pub_import_props.set_label( label ); + + Botan::PKCS11::PKCS11_ECDSA_PublicKey public_key( session, pub_import_props ); + + /************ export PKCS#11 ECDSA public key *************/ + Botan::ECDSA_PublicKey pub_exported = public_key.export_key(); + + /************ generate PKCS#11 ECDSA private key *************/ + Botan::PKCS11::EC_PrivateKeyGenerationProperties priv_generate_props; + priv_generate_props.set_token( true ); + priv_generate_props.set_private( true ); + priv_generate_props.set_sign( true ); + + Botan::PKCS11::PKCS11_ECDSA_PrivateKey pk( session, + Botan::EC_Group( "secp256r1" ).DER_encode( Botan::EC_Group_Encoding::EC_DOMPAR_ENC_OID ), + priv_generate_props ); + + /************ generate PKCS#11 ECDSA key pair *************/ + + Botan::PKCS11::EC_PublicKeyGenerationProperties pub_generate_props( + Botan::EC_Group( "secp256r1" ).DER_encode(Botan::EC_Group_Encoding::EC_DOMPAR_ENC_OID ) ); + + pub_generate_props.set_label( "BOTAN_TEST_ECDSA_PUB_KEY" ); + pub_generate_props.set_token( true ); + pub_generate_props.set_verify( true ); + pub_generate_props.set_private( false ); + pub_generate_props.set_modifiable( true ); + + Botan::PKCS11::PKCS11_ECDSA_KeyPair key_pair = Botan::PKCS11::generate_ecdsa_keypair( session, + pub_generate_props, priv_generate_props ); + + /************ PKCS#11 ECDSA sign and verify *************/ + + std::vector<uint8_t> plaintext( 20, 0x01 ); + + Botan::PK_Signer signer( key_pair.second, rng, "Raw", Botan::IEEE_1363, "pkcs11" ); + auto signature = signer.sign_message( plaintext, rng ); + + Botan::PK_Verifier token_verifier( key_pair.first, "Raw", Botan::IEEE_1363, "pkcs11" ); + bool ecdsa_ok = token_verifier.verify_message( plaintext, signature ); + +ECDH +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +PKCS#11 ECDH support is implemented in ``<botan/p11_ecdh.h>``. + +.. rubric:: ECDH Public Keys + +PKCS#11 ECDH public keys are provided by the class :cpp:class:`PKCS11_ECDH_PublicKey`. This class +inherits from :cpp:class:`PKCS11_EC_PublicKey`. The necessary property classes +are defined in ``<botan/p11_ecc_key.h>``. For public keys there are :cpp:class:`EC_PublicKeyGenerationProperties` +and :cpp:class:`EC_PublicKeyImportProperties`. + +.. cpp:class:: PKCS11_ECDH_PublicKey : public PKCS11_EC_PublicKey + + .. cpp:function:: PKCS11_ECDH_PublicKey(Session& session, ObjectHandle handle) + + Existing PKCS#11 ECDH private keys can be used by providing an :cpp:type:`ObjectHandle` to the + constructor. + + .. cpp:function:: PKCS11_ECDH_PublicKey(Session& session, const EC_PublicKeyImportProperties& props) + + This constructor can be used to import an existing ECDH public key with the :cpp:class:`EC_PublicKeyImportProperties` + passed in ``props`` to the token. + + .. cpp:function:: ECDH_PublicKey export_key() const + + Returns the exported :cpp:class:`ECDH_PublicKey`. + +.. rubric:: ECDH Private Keys + +The class :cpp:class:`PKCS11_ECDH_PrivateKey` inherits from :cpp:class:`PKCS11_EC_PrivateKey` and :cpp:class:`PK_Key_Agreement_Key` +and implements support for PKCS#11 ECDH private keys. There are two +property classes. One for key generation and one for import: :cpp:class:`EC_PrivateKeyGenerationProperties` and +:cpp:class:`EC_PrivateKeyImportProperties`. + +.. cpp:class:: PKCS11_ECDH_PrivateKey : public virtual PKCS11_EC_PrivateKey, public virtual PK_Key_Agreement_Key + + .. cpp:function:: PKCS11_ECDH_PrivateKey(Session& session, ObjectHandle handle) + + Existing PKCS#11 ECDH private keys can be used by providing an :cpp:type:`ObjectHandle` to the + constructor. + + .. cpp:function:: PKCS11_ECDH_PrivateKey(Session& session, const EC_PrivateKeyImportProperties& props) + + This constructor can be used to import an existing ECDH private key with the :cpp:class:`EC_PrivateKeyImportProperties` + passed in ``props`` to the token. + + .. cpp:function:: PKCS11_ECDH_PrivateKey(Session& session, const std::vector<uint8_t>& ec_params, const EC_PrivateKeyGenerationProperties& props) + + This constructor can be used to generate a new ECDH private key with the :cpp:class:`EC_PrivateKeyGenerationProperties` + passed in ``props`` on the token. The ``ec_params`` parameter is the DER-encoding of an + ANSI X9.62 Parameters value. + + .. cpp:function:: ECDH_PrivateKey export_key() const + + Returns the exported :cpp:class:`ECDH_PrivateKey`. + +PKCS#11 ECDH key pairs can be generated with the following free function: + +.. cpp:function:: PKCS11_ECDH_KeyPair PKCS11::generate_ecdh_keypair(Session& session, const EC_PublicKeyGenerationProperties& pub_props, const EC_PrivateKeyGenerationProperties& priv_props) + +---------- + +Code example: + + .. code-block:: cpp + + Botan::PKCS11::secure_string pin = { '1', '2', '3', '4', '5', '6' }; + session.login( Botan::PKCS11::UserType::User, pin ); + + /************ import ECDH private key *************/ + + Botan::AutoSeeded_RNG rng; + + // create private key in software + Botan::ECDH_PrivateKey priv_key_sw( rng, Botan::EC_Group( "secp256r1" ) ); + priv_key_sw.set_parameter_encoding( Botan::EC_Group_Encoding::EC_DOMPAR_ENC_OID ); + + // set import properties + Botan::PKCS11::EC_PrivateKeyImportProperties priv_import_props( + priv_key_sw.DER_domain(), priv_key_sw.private_value() ); + + priv_import_props.set_token( true ); + priv_import_props.set_private( true ); + priv_import_props.set_derive( true ); + priv_import_props.set_extractable( true ); + + // label + std::string label = "test ECDH key"; + priv_import_props.set_label( label ); + + // import to card + Botan::PKCS11::PKCS11_ECDH_PrivateKey priv_key( session, priv_import_props ); + + /************ export ECDH private key *************/ + Botan::ECDH_PrivateKey exported = priv_key.export_key(); + + /************ import ECDH public key *************/ + + // set import properties + Botan::PKCS11::EC_PublicKeyImportProperties pub_import_props( priv_key_sw.DER_domain(), + Botan::DER_Encoder().encode( EC2OSP( priv_key_sw.public_point(), Botan::PointGFp::UNCOMPRESSED ), + Botan::OCTET_STRING ).get_contents_unlocked() ); + + pub_import_props.set_token( true ); + pub_import_props.set_private( false ); + pub_import_props.set_derive( true ); + + // label + label = "test ECDH pub key"; + pub_import_props.set_label( label ); + + // import + Botan::PKCS11::PKCS11_ECDH_PublicKey pub_key( session, pub_import_props ); + + /************ export ECDH private key *************/ + Botan::ECDH_PublicKey exported_pub = pub_key.export_key(); + + /************ generate ECDH private key *************/ + + Botan::PKCS11::EC_PrivateKeyGenerationProperties priv_generate_props; + priv_generate_props.set_token( true ); + priv_generate_props.set_private( true ); + priv_generate_props.set_derive( true ); + + Botan::PKCS11::PKCS11_ECDH_PrivateKey priv_key2( session, + Botan::EC_Group( "secp256r1" ).DER_encode( Botan::EC_Group_Encoding::EC_DOMPAR_ENC_OID ), + priv_generate_props ); + + /************ generate ECDH key pair *************/ + + Botan::PKCS11::EC_PublicKeyGenerationProperties pub_generate_props( + Botan::EC_Group( "secp256r1" ).DER_encode( Botan::EC_Group_Encoding::EC_DOMPAR_ENC_OID ) ); + + pub_generate_props.set_label( label + "_PUB_KEY" ); + pub_generate_props.set_token( true ); + pub_generate_props.set_derive( true ); + pub_generate_props.set_private( false ); + pub_generate_props.set_modifiable( true ); + + Botan::PKCS11::PKCS11_ECDH_KeyPair key_pair = Botan::PKCS11::generate_ecdh_keypair( + session, pub_generate_props, priv_generate_props ); + + /************ ECDH derive *************/ + + Botan::PKCS11::PKCS11_ECDH_KeyPair key_pair_other = Botan::PKCS11::generate_ecdh_keypair( + session, pub_generate_props, priv_generate_props ); + + Botan::PK_Key_Agreement ka( key_pair.second, rng, "Raw", "pkcs11" ); + Botan::PK_Key_Agreement kb( key_pair_other.second, rng, "Raw", "pkcs11" ); + + Botan::SymmetricKey alice_key = ka.derive_key( 32, + Botan::unlock( Botan::EC2OSP( key_pair_other.first.public_point(), + Botan::PointGFp::UNCOMPRESSED ) ) ); + + Botan::SymmetricKey bob_key = kb.derive_key( 32, + Botan::unlock( Botan::EC2OSP( key_pair.first.public_point(), + Botan::PointGFp::UNCOMPRESSED ) ) ); + + bool eq = alice_key == bob_key; + +RNG +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The PKCS#11 RNG is defined in ``<botan/p11_randomgenerator.h>``. The class :cpp:class:`PKCS11_RNG` +implements the :cpp:class:`Hardware_RNG` interface. + +.. cpp:class:: PKCS11_RNG : public Hardware_RNG + + .. cpp:function:: PKCS11_RNG(Session& session) + + A PKCS#11 :cpp:class:`Session` must be passed to instantiate a ``PKCS11_RNG``. + + .. cpp:function:: void randomize(uint8_t output[], std::size_t length) override + + Calls :cpp:func:`C_GenerateRandom` to generate random data. + + .. cpp:function:: void add_entropy(const uint8_t in[], std::size_t length) override + + Calls :cpp:func:`C_SeedRandom` to add entropy to the random generation function of the token/middleware. + +---------- + +Code example: + + .. code-block:: cpp + + Botan::PKCS11::PKCS11_RNG p11_rng( session ); + + /************ generate random data *************/ + std::vector<uint8_t> random( 20 ); + p11_rng.randomize( random.data(), random.size() ); + + /************ add entropy *************/ + Botan::AutoSeeded_RNG auto_rng; + auto auto_rng_random = auto_rng.random_vec( 20 ); + p11_rng.add_entropy( auto_rng_random.data(), auto_rng_random.size() ); + + /************ use PKCS#11 RNG to seed HMAC_DRBG *************/ + Botan::HMAC_DRBG drbg( Botan::MessageAuthenticationCode::create( "HMAC(SHA-512)" ), p11_rng ); + drbg.randomize( random.data(), random.size() ); + +Token Management Functions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The header file ``<botan/p11.h>`` also defines some free functions for token management: + + .. cpp:function:: void initialize_token(Slot& slot, const std::string& label, const secure_string& so_pin, const secure_string& pin) + + Initializes a token by passing a :cpp:class:`Slot`, a ``label`` and the ``so_pin`` of the security officer. + + .. cpp:function:: void change_pin(Slot& slot, const secure_string& old_pin, const secure_string& new_pin) + + Change PIN with ``old_pin`` to ``new_pin``. + + .. cpp:function:: void change_so_pin(Slot& slot, const secure_string& old_so_pin, const secure_string& new_so_pin) + + Change SO_PIN with ``old_so_pin`` to new ``new_so_pin``. + + .. cpp:function:: void set_pin(Slot& slot, const secure_string& so_pin, const secure_string& pin) + + Sets user ``pin`` with ``so_pin``. + +---------- + +Code example: + + .. code-block:: cpp + + /************ set pin *************/ + + Botan::PKCS11::Module module( Middleware_path ); + + // only slots with connected token + std::vector<Botan::PKCS11::SlotId> slots = Botan::PKCS11::Slot::get_available_slots( module, true ); + + // use first slot + Botan::PKCS11::Slot slot( module, slots.at( 0 ) ); + + Botan::PKCS11::secure_string so_pin = { '1', '2', '3', '4', '5', '6', '7', '8' }; + Botan::PKCS11::secure_string pin = { '1', '2', '3', '4', '5', '6' }; + Botan::PKCS11::secure_string test_pin = { '6', '5', '4', '3', '2', '1' }; + + // set pin + Botan::PKCS11::set_pin( slot, so_pin, test_pin ); + + // change back + Botan::PKCS11::set_pin( slot, so_pin, pin ); + + /************ initialize *************/ + Botan::PKCS11::initialize_token( slot, "Botan handbook example", so_pin, pin ); + + /************ change pin *************/ + Botan::PKCS11::change_pin( slot, pin, test_pin ); + + // change back + Botan::PKCS11::change_pin( slot, test_pin, pin ); + + /************ change security officer pin *************/ + Botan::PKCS11::change_so_pin( slot, so_pin, test_pin ); + + // change back + Botan::PKCS11::change_so_pin( slot, test_pin, so_pin ); + +X.509 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The header file ``<botan/p11_x509.h>`` defines the property class :cpp:class:`X509_CertificateProperties` +and the class :cpp:class:`PKCS11_X509_Certificate`. + +.. cpp:class:: PKCS11_X509_Certificate : public Object, public X509_Certificate + + .. cpp:function:: PKCS11_X509_Certificate(Session& session, ObjectHandle handle) + + Allows to use existing certificates on the token by passing a valid :cpp:type:`ObjectHandle`. + + .. cpp:function:: PKCS11_X509_Certificate(Session& session, const X509_CertificateProperties& props) + + Allows to import an existing X.509 certificate to the token with the :cpp:class:`X509_CertificateProperties` + passed in ``props``. + +---------- + +Code example: + + .. code-block:: cpp + + // load existing certificate + Botan::X509_Certificate root( "test.crt" ); + + // set props + Botan::PKCS11::X509_CertificateProperties props( + Botan::DER_Encoder().encode( root.subject_dn() ).get_contents_unlocked(), root.BER_encode() ); + + props.set_label( "Botan PKCS#11 test certificate" ); + props.set_private( false ); + props.set_token( true ); + + // import + Botan::PKCS11::PKCS11_X509_Certificate pkcs11_cert( session, props ); + + // load by handle + Botan::PKCS11::PKCS11_X509_Certificate pkcs11_cert2( session, pkcs11_cert.handle() ); + +Tests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The PKCS#11 tests are not executed automatically because the depend on an external +PKCS#11 module/middleware. The test tool has to be executed with ``--pkcs11-lib=`` +followed with the path of the PKCS#11 module and a second argument which controls the +PKCS#11 tests that are executed. Passing ``pkcs11`` will execute all PKCS#11 tests but it's +also possible to execute only a subset with the following arguments: + +- pkcs11-ecdh +- pkcs11-ecdsa +- pkcs11-lowlevel +- pkcs11-manage +- pkcs11-module +- pkcs11-object +- pkcs11-rng +- pkcs11-rsa +- pkcs11-session +- pkcs11-slot +- pkcs11-x509 + +The following PIN and SO-PIN/PUK values are used in tests: + +- PIN 123456 +- SO-PIN/PUK 12345678 + + .. warning:: + + Unlike the CardOS (4.4, 5.0, 5.3), the aforementioned SO-PIN/PUK is + inappropriate for Gemalto (IDPrime MD 3840) cards, as it must be a byte array + of length 24. For this reason some of the tests for Gemalto card involving + SO-PIN will fail. You run into a risk of exceding login attempts and as a + result locking your card! Currently, specifying pin via command-line option + is not implemented, and therefore the desired PIN must be modified in the + header src/tests/test_pkcs11.h: + + .. code-block:: cpp + + // SO PIN is expected to be set to "12345678" prior to running the tests + const std::string SO_PIN = "12345678"; + const auto SO_PIN_SECVEC = Botan::PKCS11::secure_string(SO_PIN.begin(), SO_PIN.end()); + + +Tested/Supported Smartcards +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You are very welcome to contribute your own test results for other testing environments or other cards. + + +Test results + ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ +| Smartcard | Status | OS | Midleware | Botan | Errors | ++=====================================+===========================================+===================================================+===================================================+===================================================+===================================================+ +| CardOS 4.4 | mostly works | Windows 10, 64-bit, version 1709 | API Version 5.4.9.77 (Cryptoki v2.11) | 2.4.0, Cryptoki v2.40 | [50]_ | ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ +| CardOS 5.0 | mostly works | Windows 10, 64-bit, version 1709 | API Version 5.4.9.77 (Cryptoki v2.11) | 2.4.0, Cryptoki v2.40 | [51]_ | ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ +| CardOS 5.3 | mostly works | Windows 10, 64-bit, version 1709 | API Version 5.4.9.77 (Cryptoki v2.11) | 2.4.0, Cryptoki v2.40 | [52]_ | ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ +| Gemalto IDPrime MD 3840 | mostly works | Windows 10, 64-bit, version 1709 | IDGo 800, v1.2.4 (Cryptoki v2.20) | 2.4.0, Cryptoki v2.40 | [53]_ | ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ +| SoftHSM 2.3.0 (OpenSSL 1.0.2g) | works | Windows 10, 64-bit, version 1709 | Cryptoki v2.40 | 2.4.0, Cryptoki v2.40 | | ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ +| SoftHSM 2.5.0 (OpenSSL 1.1.1) | works | Windows 10, 64-bit, version 1803 | Cryptoki v2.40 | 2.11.0, Cryptoki v2.40 | | ++-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+ + +.. [50] Failing operations for CardOS 4.4: + + - object_copy [20]_ + + - rsa_privkey_export [21]_ + - rsa_generate_private_key [22]_ + - rsa_sign_verify [23]_ + + - ecdh_privkey_import [3]_ + - ecdh_privkey_export [2]_ + - ecdh_pubkey_import [4]_ + - ecdh_pubkey_export [4]_ + - ecdh_generate_private_key [3]_ + - ecdh_generate_keypair [3]_ + - ecdh_derive [3]_ + + - ecdsa_privkey_import [3]_ + - ecdsa_privkey_export [2]_ + - ecdsa_pubkey_import [4]_ + - ecdsa_pubkey_export [4]_ + - ecdsa_generate_private_key [3]_ + - ecdsa_generate_keypair [3]_ + - ecdsa_sign_verify [3]_ + + - rng_add_entropy [5]_ + + +.. [51] Failing operations for CardOS 5.0 + + - object_copy [20]_ + + - rsa_privkey_export [21]_ + - rsa_generate_private_key [22]_ + - rsa_sign_verify [23]_ + + - ecdh_privkey_export [2]_ + - ecdh_pubkey_import [4]_ + - ecdh_generate_private_key [32]_ + - ecdh_generate_keypair [3]_ + - ecdh_derive [33]_ + + - ecdsa_privkey_export [2]_ + - ecdsa_generate_private_key [30]_ + - ecdsa_generate_keypair [30]_ + - ecdsa_sign_verify [30]_ + + - rng_add_entropy [5]_ + +.. [52] Failing operations for CardOS 5.3 + + - object_copy [20]_ + + - rsa_privkey_export [21]_ + - rsa_generate_private_key [22]_ + - rsa_sign_verify [23]_ + + - ecdh_privkey_export [2]_ + - ecdh_pubkey_import [6]_ + - ecdh_pubkey_export [6]_ + - ecdh_generate_private_key [30]_ + - ecdh_generate_keypair [31]_ + - ecdh_derive [30]_ + + - ecdsa_privkey_export [2]_ + - ecdsa_pubkey_import [6]_ + - ecdsa_pubkey_export [6]_ + - ecdsa_generate_private_key [31]_ + - ecdsa_generate_keypair [31]_ + - ecdsa_sign_verify [34]_ + + - rng_add_entropy [5]_ + +.. [53] Failing operations for Gemalto IDPrime MD 3840 + + - session_login_logout [2]_ + - session_info [2]_ + - set_pin [2]_ + - initialize [2]_ + - change_so_pin [2]_ + + - object_copy [20]_ + + - rsa_generate_private_key [7]_ + - rsa_encrypt_decrypt [8]_ + - rsa_sign_verify [2]_ + + - rng_add_entropy [5]_ + +Error descriptions + +.. [2] CKR_ARGUMENTS_BAD (0x7=7) +.. [3] CKR_MECHANISM_INVALID (0x70=112) +.. [4] CKR_FUNCTION_NOT_SUPPORTED (0x54=84) +.. [5] CKR_RANDOM_SEED_NOT_SUPPORTED (0x120=288) +.. [6] CKM_X9_42_DH_KEY_PAIR_GEN | CKR_DEVICE_ERROR (0x30=48) +.. [7] CKR_TEMPLATE_INCONSISTENT (0xD1=209) +.. [8] CKR_ENCRYPTED_DATA_INVALID | CKM_SHA256_RSA_PKCS (0x40=64) + +.. [20] Test fails due to unsupported copy function (CKR_FUNCTION_NOT_SUPPORTED) +.. [21] Generating private key for extraction with property extractable fails (CKR_ARGUMENTS_BAD) +.. [22] Generate rsa private key operation fails (CKR_TEMPLATE_INCOMPLETE) +.. [23] Raw RSA sign-verify fails (CKR_MECHANISM_INVALID) + +.. [30] Invalid argument Decoding error: BER: Value truncated +.. [31] Invalid argument Decoding error: BER: Length field is to large +.. [32] Invalid argument OS2ECP: Unknown format type 155 +.. [33] Invalid argument OS2ECP: Unknown format type 92 +.. [34] Invalid argument OS2ECP: Unknown format type 57 diff --git a/doc/api_ref/psk_db.rst b/doc/api_ref/psk_db.rst new file mode 100644 index 000000000..2668c6bad --- /dev/null +++ b/doc/api_ref/psk_db.rst @@ -0,0 +1,108 @@ +PSK Database +====================== + +.. versionadded:: 2.4.0 + +Many applications need to store pre-shared keys (hereafter PSKs) for +authentication purposes. + +An abstract interface to PSK stores is provided in ``psk_db.h`` + +.. cpp:class:: PSK_Database + + .. cpp:function:: bool is_encrypted() const + + Returns true if (at least) the PSKs themselves are encrypted. Returns + false if PSKs are stored in plaintext. + + .. cpp:function:: std::set<std::string> list_names() const + + Return the set of valid names stored in the database, ie values for which + ``get`` will return a value. + + .. cpp:function:: void set(const std::string& name, const uint8_t psk[], size_t psk_len) + + Save a PSK. If ``name`` already exists, the current value will be + overwritten. + + .. cpp:function:: secure_vector<uint8_t> get(const std::string& name) const + + Return a value saved with ``set``. Throws an exception if ``name`` doesn't + exist. + + .. cpp:function:: void remove(const std::string& name) + + Remove ``name`` from the database. If ``name`` doesn't exist, ignores the request. + + .. cpp::function:: std::string get_str(const std::string& name) const + + Like ``get`` but casts the return value to a string. + + .. cpp:function:: void set_str(const std::string& name, const std::string& psk) + + Like ``set`` but accepts the psk as a string (eg for a password). + + .. cpp:function:: template<typename Alloc> void set_vec(const std::string& name, \ + const std::vector<uint8_t, Alloc>& psk) + + Like ``set`` but accepting a vector. + +The same header also provides a specific instantiation of ``PSK_Database`` which +encrypts both names and PSKs. It must be subclassed to provide the storage. + +.. cpp:class:: Encrypted_PSK_Database : public PSK_Database + + .. cpp:function:: Encrypted_PSK_Database(const secure_vector<uint8_t>& master_key) + + Initializes or opens a PSK database. The master key is used the secure the + contents. It may be of any length. If encrypting PSKs under a passphrase, + use a suitable key derivation scheme (such as PBKDF2) to derive the secret + key. If the master key is lost, all PSKs stored are unrecoverable. + + Both names and values are encrypted using NIST key wrapping (see NIST + SP800-38F) with AES-256. First the master key is used with HMAC(SHA-256) + to derive two 256-bit keys, one for encrypting all names and the other to + key an instance of HMAC(SHA-256). Values are each encrypted under an + individual key created by hashing the encrypted name with HMAC. This + associates the encrypted key with the name, and prevents an attacker with + write access to the data store from taking an encrypted key associated + with one entity and copying it to another entity. + + Names and PSKs are both padded to the next multiple of 8 bytes, providing + some obfuscation of the length. + + One artifact of the names being encrypted is that is is possible to use + multiple different master keys with the same underlying storage. Each + master key will be responsible for a subset of the keys. An attacker who + knows one of the keys will be able to tell there are other values + encrypted under another key. + + .. cpp:function:: virtual void kv_set(const std::string& index, const std::string& value) = 0 + + Save an encrypted value. Both ``index`` and ``value`` will be non-empty + base64 encoded strings. + + .. cpp:function:: virtual std::string kv_get(const std::string& index) const = 0 + + Return a value saved with ``kv_set``, or return the empty string. + + .. cpp:function:: virtual void kv_del(const std::string& index) = 0 + + Remove a value saved with ``kv_set``. + + .. cpp:function:: virtual std::set<std::string> kv_get_all() const = 0 + + Return all active names (ie values for which ``kv_get`` will return a + non-empty string). + +A subclass of ``Encrypted_PSK_Database`` which stores data in a SQL database +is also available. This class is declared in ``psk_db_sql.h``: + +.. cpp:class:: Encrypted_PSK_Database_SQL : public Encrypted_PSK_Database + + .. cpp:function:: Encrypted_PSK_Database_SQL(const secure_vector<uint8_t>& master_key, \ + std::shared_ptr<SQL_Database> db, \ + const std::string& table_name) + + Creates or uses the named table in ``db``. The SQL schema of the table is + ``(psk_name TEXT PRIMARY KEY, psk_value TEXT)``. diff --git a/doc/api_ref/pubkey.rst b/doc/api_ref/pubkey.rst new file mode 100644 index 000000000..6f867103f --- /dev/null +++ b/doc/api_ref/pubkey.rst @@ -0,0 +1,919 @@ +Public Key Cryptography +================================= + +Public key cryptography (also called asymmetric cryptography) is a collection +of techniques allowing for encryption, signatures, and key agreement. + +Key Objects +---------------------------------------- + +Public and private keys are represented by classes ``Public_Key`` and it's +subclass ``Private_Key``. The use of inheritance here means that a +``Private_Key`` can be converted into a reference to a public key. + +None of the functions on ``Public_Key`` and ``Private_Key`` itself are +particularly useful for users of the library, because 'bare' public key +operations are *very insecure*. The only purpose of these functions is to +provide a clean interface that higher level operations can be built on. So +really the only thing you need to know is that when a function takes a +reference to a ``Public_Key``, it can take any public key or private key, and +similarly for ``Private_Key``. + +Types of ``Public_Key`` include ``RSA_PublicKey``, ``DSA_PublicKey``, +``ECDSA_PublicKey``, ``ECKCDSA_PublicKey``, ``ECGDSA_PublicKey``, ``DH_PublicKey``, ``ECDH_PublicKey``, +``Curve25519_PublicKey``, ``ElGamal_PublicKey``, ``McEliece_PublicKey``, ``XMSS_PublicKey`` +and ``GOST_3410_PublicKey``. There are corresponding ``Private_Key`` classes for each of these algorithms. + +.. _creating_new_private_keys: + +Creating New Private Keys +---------------------------------------- + +Creating a new private key requires two things: a source of random numbers +(see :ref:`random_number_generators`) and some algorithm specific parameters +that define the *security level* of the resulting key. For instance, the +security level of an RSA key is (at least in part) defined by the length of +the public key modulus in bits. So to create a new RSA private key, you would +call + +.. cpp:function:: RSA_PrivateKey::RSA_PrivateKey(RandomNumberGenerator& rng, size_t bits) + + A constructor that creates a new random RSA private key with a modulus + of length *bits*. + +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 +integers modulo a prime, represented by :ref:`dl_group`, and elliptic curves +in GF(p), represented by :ref:`ec_group`. A rough generalization is that the +larger the group is, the more secure the algorithm is, but correspondingly the +slower the operations will be. + +Given a ``DL_Group``, you can create new DSA, Diffie-Hellman and ElGamal key pairs with + +.. cpp:function:: DSA_PrivateKey::DSA_PrivateKey(RandomNumberGenerator& rng, \ + const DL_Group& group, const BigInt& x = 0) + +.. cpp:function:: DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng, \ + const DL_Group& group, const BigInt& x = 0) + +.. cpp:function:: ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng, \ + const DL_Group& group, const BigInt& x = 0) + + The optional *x* parameter to each of these constructors is a private key + value. This allows you to create keys where the private key is formed by + some special technique; for instance you can use the hash of a password (see + :ref:`pbkdf` for how to do that) as a private key value. Normally, you would + leave the value as zero, letting the class generate a new random key. + +Finally, given an ``EC_Group`` object, you can create a new ECDSA, ECKCDSA, ECGDSA, +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) + +.. cpp:function:: GOST_3410_PrivateKey::GOST_3410_PrivateKey(RandomNumberGenerator& rng, \ + const EC_Group& domain, const BigInt& x = 0) + +.. _serializing_private_keys: + +Serializing Private Keys Using PKCS #8 +---------------------------------------- + +The standard format for serializing a private key is PKCS #8, the operations +for which are defined in ``pkcs8.h``. It supports both unencrypted and +encrypted storage. + +.. cpp:function:: secure_vector<uint8_t> PKCS8::BER_encode(const Private_Key& key, \ + RandomNumberGenerator& rng, const std::string& password, const std::string& pbe_algo = "") + + Takes any private key object, serializes it, encrypts it using + *password*, and returns a binary structure representing the private + key. + + The final (optional) argument, *pbe_algo*, specifies a particular + password based encryption (or PBE) algorithm. If you don't specify a + PBE, a sensible default will be used. + + The currently supported PBE is PBES2 from PKCS5. Format is as follows: + ``PBE-PKCS5v20(CIPHER,PBKDF)``. Since 2.8.0, ``PBES2(CIPHER,PBKDF)`` also works. + Cipher can be any block cipher with /CBC or /GCM appended, for example + "AES-128/CBC" or "Camellia-256/GCM". For best interop with other systems, use + AES in CBC mode. The PBKDF can be either the name of a hash function (in which + case PBKDF2 is used with that hash) or "Scrypt", which causes the scrypt + memory hard password hashing function to be used. Scrypt is supported since + version 2.7.0. + + Use `PBE-PKCS5v20(AES-256/CBC,SHA-256)` if you want to ensure the keys can + be imported by different software packages. Use + `PBE-PKCS5v20(AES-256/GCM,Scrypt)` for best security assuming you do not + care about interop. + + For ciphers you can use anything which has an OID defined for CBC, GCM or SIV + modes. Currently this includes AES, Camellia, Serpent, Twofish, and SM4. Most + other libraries only support CBC mode for private key encryption. GCM has + been supported in PBES2 since 1.11.10. SIV has been supported since 2.8. + +.. cpp:function:: std::string PKCS8::PEM_encode(const Private_Key& key, \ + RandomNumberGenerator& rng, const std::string& pass, const std::string& pbe_algo = "") + + This formats the key in the same manner as ``BER_encode``, but additionally + encodes it into a text format with identifying headers. Using PEM encoding + is *highly* recommended for many reasons, including compatibility with other + software, for transmission over 8-bit unclean channels, because it can be + identified by a human without special tools, and because it sometimes allows + more sane behavior of tools that process the data. + +Unencrypted serialization is also supported. + +.. warning:: + + In most situations, using unencrypted private key storage is a bad idea, + because anyone can come along and grab the private key without having to + know any passwords or other secrets. Unless you have very particular + security requirements, always use the versions that encrypt the key based on + a passphrase, described above. + +.. cpp:function:: secure_vector<uint8_t> PKCS8::BER_encode(const Private_Key& key) + + Serializes the private key and returns the result. + +.. cpp:function:: std::string PKCS8::PEM_encode(const Private_Key& key) + + Serializes the private key, base64 encodes it, and returns the + result. + +Last but not least, there are some functions that will load (and +decrypt, if necessary) a PKCS #8 private key: + +.. cpp:function:: Private_Key* PKCS8::load_key(DataSource& in, \ + RandomNumberGenerator& rng, const User_Interface& ui) + +.. cpp:function:: Private_Key* PKCS8::load_key(DataSource& in, \ + RandomNumberGenerator& rng, std::string passphrase = "") + +.. cpp:function:: Private_Key* PKCS8::load_key(const std::string& filename, \ + RandomNumberGenerator& rng, const User_Interface& ui) + +.. cpp:function:: Private_Key* PKCS8::load_key(const std::string& filename, \ + RandomNumberGenerator& rng, const std::string& passphrase = "") + +These functions will return an object allocated key object based on the data +from whatever source it is using (assuming, of course, the source is in fact +storing a representation of a private key, and the decryption was +successful). The encoding used (PEM or BER) need not be specified; the format +will be detected automatically. The key is allocated with ``new``, and should +be released with ``delete`` when you are done with it. The first takes a +generic ``DataSource`` that you have to create - the other is a simple wrapper +functions that take either a filename or a memory buffer and create the +appropriate ``DataSource``. + +The versions taking a ``std::string`` attempt to decrypt using the password +given (if the key is encrypted; if it is not, the passphase value will be +ignored). If the passphrase does not decrypt the key, an exception will be +thrown. + +The ones taking a ``User_Interface`` provide a simple callback interface which +makes handling incorrect passphrases and such a bit simpler. A +``User_Interface`` has very little to do with talking to users; it's just a +way to glue together Botan and whatever user interface you happen to be using. + +.. note:: + + In a future version, it is likely that ``User_Interface`` will be + replaced by a simple callback using ``std::function``. + +To use ``User_Interface``, derive a subclass and implement: + +.. cpp:function:: std::string User_Interface::get_passphrase(const std::string& what, \ + const std::string& source, UI_Result& result) const + + The ``what`` argument specifies what the passphrase is needed for (for + example, PKCS #8 key loading passes ``what`` as "PKCS #8 private key"). This + lets you provide the user with some indication of *why* your application is + asking for a passphrase; feel free to pass the string through ``gettext(3)`` + or moral equivalent for i18n purposes. Similarly, ``source`` specifies where + the data in question came from, if available (for example, a file name). If + the source is not available for whatever reason, then ``source`` will be an + empty string; be sure to account for this possibility. + + The function returns the passphrase as the return value, and a status code + in ``result`` (either ``OK`` or ``CANCEL_ACTION``). If ``CANCEL_ACTION`` is + returned in ``result``, then the return value will be ignored, and the + caller will take whatever action is necessary (typically, throwing an + exception stating that the passphrase couldn't be determined). In the + specific case of PKCS #8 key decryption, a ``Decoding_Error`` exception will + be thrown; your UI should assume this can happen, and provide appropriate + error handling (such as putting up a dialog box informing the user of the + situation, and canceling the operation in progress). + +.. _serializing_public_keys: + +Serializing Public Keys +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To import and export public keys, use: + +.. cpp:function:: std::vector<uint8_t> X509::BER_encode(const Public_Key& key) + +.. cpp:function:: std::string X509::PEM_encode(const Public_Key& key) + +.. cpp:function:: Public_Key* X509::load_key(DataSource& in) + +.. cpp:function:: Public_Key* X509::load_key(const secure_vector<uint8_t>& buffer) + +.. cpp:function:: Public_Key* X509::load_key(const std::string& filename) + + These functions operate in the same way as the ones described in + :ref:`serializing_private_keys`, except that no encryption option is + available. + +.. _dl_group: + +DL_Group +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As described in :ref:`creating_new_private_keys`, a discrete logarithm group +can be shared among many keys, even keys created by users who do not trust +each other. However, it is necessary to trust the entity who created the +group; that is why organization like NIST use algorithms which generate groups +in a deterministic way such that creating a bogus group would require breaking +some trusted cryptographic primitive like SHA-2. + +Instantiating a ``DL_Group`` simply requires calling + +.. cpp:function:: DL_Group::DL_Group(const std::string& name) + + The *name* parameter is a specially formatted string that consists of three + things, the type of the group ("modp" or "dsa"), the creator of the group, + and the size of the group in bits, all delimited by '/' characters. + + Currently all "modp" groups included in botan are ones defined by the + Internet Engineering Task Force, so the provider is "ietf", and the strings + look like "modp/ietf/N" where N can be any of 1024, 1536, 2048, 3072, + 4096, 6144, or 8192. This group type is used for Diffie-Hellman and ElGamal + algorithms. + + The other type, "dsa" is used for DSA keys. They can also be used with + Diffie-Hellman and ElGamal, but this is less common. The currently available + groups are "dsa/jce/1024" and "dsa/botan/N" with N being 2048 or 3072. The + "jce" groups are the standard DSA groups used in the Java Cryptography + Extensions, while the "botan" groups were randomly generated using the + FIPS 186-3 algorithm by the library maintainers. + +You can generate a new random group using + +.. cpp:function:: DL_Group::DL_Group(RandomNumberGenerator& rng, \ + PrimeType type, size_t pbits, size_t qbits = 0) + + The *type* can be either ``Strong``, ``Prime_Subgroup``, or + ``DSA_Kosherizer``. *pbits* specifies the size of the prime in + bits. If the *type* is ``Prime_Subgroup`` or ``DSA_Kosherizer``, + then *qbits* specifies the size of the subgroup. + +You can serialize a ``DL_Group`` using + +.. cpp:function:: secure_vector<uint8_t> DL_Group::DER_Encode(Format format) + +or + +.. cpp:function:: std::string DL_Group::PEM_encode(Format format) + +where *format* is any of + +* ``ANSI_X9_42`` (or ``DH_PARAMETERS``) for modp groups +* ``ANSI_X9_57`` (or ``DSA_PARAMETERS``) for DSA-style groups +* ``PKCS_3`` is an older format for modp groups; it should only + be used for backwards compatibility. + +You can reload a serialized group using + +.. cpp:function:: void DL_Group::BER_decode(DataSource& source, Format format) + +.. 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 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +An ``EC_Group`` is initialized by passing the name of the +group to be used to the constructor. These groups have +semi-standardized names like "secp256r1" and "brainpool512r1". + +Key Checking +--------------------------------- + +Most public key algorithms have limitations or restrictions on their +parameters. For example RSA requires an odd exponent, and algorithms +based on the discrete logarithm problem need a generator > 1. + +Each public key type has a function + +.. cpp:function:: bool Public_Key::check_key(RandomNumberGenerator& rng, bool strong) + + This function performs a number of algorithm-specific tests that the key + seems to be mathematically valid and consistent, and returns true if all of + the tests pass. + + It does not have anything to do with the validity of the key for any + particular use, nor does it have anything to do with certificates that link + a key (which, after all, is just some numbers) with a user or other + entity. If *strong* is ``true``, then it does "strong" checking, which + includes expensive operations like primality checking. + +As key checks are not automatically performed they must be called +manually after loading keys from untrusted sources. If a key from an untrusted source +is not checked, the implementation might be vulnerable to algorithm specific attacks. + +The following example loads the Subject Public Key from the x509 certificate ``cert.pem`` and checks the +loaded key. If the key check fails a respective error is thrown. + +.. code-block:: cpp + + #include <botan/x509cert.h> + #include <botan/auto_rng.h> + #include <botan/rng.h> + + int main() + { + Botan::X509_Certificate cert("cert.pem"); + std::unique_ptr<Botan::RandomNumberGenerator> rng(new Botan::AutoSeeded_RNG); + std::unique_ptr<Botan::Public_Key> key(cert.subject_public_key()); + if(!key->check_key(*rng.get(), false)) + { + throw std::invalid_argument("Loaded key is invalid"); + } + } + +Encryption +--------------------------------- + +Safe public key encryption requires the use of a padding scheme which hides +the underlying mathematical properties of the algorithm. Additionally, they +will add randomness, so encrypting the same plaintext twice produces two +different ciphertexts. + +The primary interface for encryption is + +.. cpp:class:: PK_Encryptor + + .. cpp:function:: secure_vector<uint8_t> encrypt( \ + const uint8_t* in, size_t length, RandomNumberGenerator& rng) const + + .. cpp:function:: secure_vector<uint8_t> encrypt( \ + const std::vector<uint8_t>& in, RandomNumberGenerator& rng) const + + These encrypt a message, returning the ciphertext. + + .. cpp:function:: size_t maximum_input_size() const + + Returns the maximum size of the message that can be processed, in + bytes. If you call :cpp:func:`PK_Encryptor::encrypt` with a value larger + than this the operation will fail with an exception. + +:cpp:class:`PK_Encryptor` is only an interface - to actually encrypt you have +to create an implementation, of which there are currently three available in the +library, :cpp:class:`PK_Encryptor_EME`, :cpp:class:`DLIES_Encryptor` and +:cpp:class:`ECIES_Encryptor`. DLIES is a hybrid encryption scheme (from +IEEE 1363) that uses the DH key agreement technique in combination with a KDF, a +MAC and a symmetric encryption algorithm to perform message encryption. ECIES is +similar to DLIES, but uses ECDH for the key agreement. Normally, public key +encryption is done using algorithms which support it directly, such as RSA or +ElGamal; these use the EME class: + +.. cpp:class:: PK_Encryptor_EME + + .. cpp:function:: PK_Encryptor_EME(const Public_Key& key, std::string eme) + + With *key* being the key you want to encrypt messages to. The padding + method to use is specified in *eme*. + + The recommended values for *eme* is "EME1(SHA-1)" or "EME1(SHA-256)". If + you need compatibility with protocols using the PKCS #1 v1.5 standard, + you can also use "EME-PKCS1-v1_5". + +.. cpp:class:: DLIES_Encryptor + + Available in the header ``dlies.h`` + + .. cpp:function:: DLIES_Encryptor(const DH_PrivateKey& own_priv_key, \ + RandomNumberGenerator& rng, KDF* kdf, MessageAuthenticationCode* mac, \ + size_t mac_key_len = 20) + + Where *kdf* is a key derivation function (see + :ref:`key_derivation_function`) and *mac* is a + MessageAuthenticationCode. The encryption is performed by XORing the + message with a stream of bytes provided by the KDF. + + .. cpp:function:: DLIES_Encryptor(const DH_PrivateKey& own_priv_key, \ + RandomNumberGenerator& rng, KDF* kdf, Cipher_Mode* cipher, \ + size_t cipher_key_len, MessageAuthenticationCode* mac, \ + size_t mac_key_len = 20) + + Instead of XORing the message a block cipher can be specified. + +.. cpp:class:: ECIES_Encryptor + + Available in the header ``ecies.h``. + + Parameters for encryption and decryption are set by the + :cpp:class:`ECIES_System_Params` class which stores the EC domain parameters, + the KDF (see :ref:`key_derivation_function`), the cipher (see + :ref:`cipher_modes`) and the MAC. + + .. cpp:function:: ECIES_Encryptor(const PK_Key_Agreement_Key& private_key, \ + const ECIES_System_Params& ecies_params, \ + RandomNumberGenerator& rng) + + Where *private_key* is the key to use for the key agreement. The system + parameters are specified in *ecies_params* and the RNG to use is passed in + *rng*. + + .. cpp:function:: ECIES_Encryptor(RandomNumberGenerator& rng, \ + const ECIES_System_Params& ecies_params) + + Creates an ephemeral private key which is used for the key agreement. + +The decryption classes are named :cpp:class:`PK_Decryptor`, +:cpp:class:`PK_Decryptor_EME`, :cpp:class:`DLIES_Decryptor` and +:cpp:class:`ECIES_Decryptor`. They are created in the exact same way, except +they take 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)" +#. DLIES +#. ECIES +#. SM2 + +Code Example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The following Code sample reads a PKCS #8 keypair from the passed location and +subsequently encrypts a fixed plaintext with the included public key, using EME1 +with SHA-256. For the sake of completeness, the ciphertext is then decrypted using +the private key. + +.. code-block:: cpp + + #include <botan/pkcs8.h> + #include <botan/hex.h> + #include <botan/pk_keys.h> + #include <botan/pubkey.h> + #include <botan/auto_rng.h> + #include <botan/rng.h> + #include <iostream> + int main (int argc, char* argv[]) + { + if(argc!=2) + return 1; + 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."); + std::vector<uint8_t> pt(plaintext.data(),plaintext.data()+plaintext.length()); + std::unique_ptr<Botan::RandomNumberGenerator> rng(new Botan::AutoSeeded_RNG); + + //load keypair + std::unique_ptr<Botan::Private_Key> kp(Botan::PKCS8::load_key(argv[1],*rng.get())); + + //encrypt with pk + Botan::PK_Encryptor_EME enc(*kp,*rng.get(), "EME1(SHA-256)"); + std::vector<uint8_t> ct = enc.encrypt(pt,*rng.get()); + + //decrypt with sk + Botan::PK_Decryptor_EME dec(*kp,*rng.get(), "EME1(SHA-256)"); + std::cout << std::endl << "enc: " << Botan::hex_encode(ct) << std::endl << "dec: "<< Botan::hex_encode(dec.decrypt(ct)); + + return 0; + } + + +Signatures +--------------------------------- + +Signature generation is performed using + +.. cpp:class:: PK_Signer + + .. cpp:function:: PK_Signer(const Private_Key& key, \ + const std::string& emsa, \ + Signature_Format format = IEEE_1363) + + 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, ECKCDSA, + ECGDSA, GOST 34.10-2001. Other signature schemes may be supported in the future. + + .. note:: + + Botan both supports non-deterministic and deterministic (as per RFC + 6979) DSA and ECDSA signatures. Deterministic signatures are compatible + in the way that they can be verified with a non-deterministic implementation. + If the ``rfc6979`` module is enabled, deterministic DSA and ECDSA signatures + will be generated. + + Currently available values for *emsa* include EMSA1, EMSA2, EMSA3, EMSA4, + and Raw. All of them, except Raw, take a parameter naming a message + digest function to hash the message with. The Raw encoding signs the + input directly; if the message is too big, the signing operation will + fail. Raw is not useful except in very specialized applications. Examples + are "EMSA1(SHA-1)" and "EMSA4(SHA-256)". + + 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, ECKCDSA, ECGDSA and + GOST 34.10-2001 you should use EMSA1. + + The *format* defaults to ``IEEE_1363`` which is the only available + format for RSA. For DSA, ECDSA, ECGDSA and ECKCDSA you can also use + ``DER_SEQUENCE``, which will format the signature as an ASN.1 + SEQUENCE value. + + .. cpp:function:: void update(const uint8_t* in, size_t length) + .. cpp:function:: void update(const std::vector<uint8_t>& in) + .. cpp:function:: void update(uint8_t in) + + These add more data to be included in the signature + computation. Typically, the input will be provided directly to a + hash function. + + .. cpp:function:: secure_vector<uint8_t> signature(RandomNumberGenerator& rng) + + Creates the signature and returns it + + .. cpp:function:: secure_vector<uint8_t> sign_message( \ + const uint8_t* in, size_t length, RandomNumberGenerator& rng) + + .. cpp:function:: secure_vector<uint8_t> sign_message( \ + const std::vector<uint8_t>& in, RandomNumberGenerator& rng) + + These functions are equivalent to calling + :cpp:func:`PK_Signer::update` and then + :cpp:func:`PK_Signer::signature`. Any data previously provided + using ``update`` will be included. + +Signatures are verified using + +.. cpp:class:: PK_Verifier + + .. cpp:function:: PK_Verifier(const Public_Key& pub_key, \ + const std::string& emsa, Signature_Format format = IEEE_1363) + + Construct a new verifier for signatures associated with public + key *pub_key*. The *emsa* and *format* should be the same as + that used by the signer. + + .. cpp:function:: void update(const uint8_t* in, size_t length) + .. cpp:function:: void update(const std::vector<uint8_t>& in) + .. cpp:function:: void update(uint8_t in) + + Add further message data that is purportedly associated with the + signature that will be checked. + + .. cpp:function:: bool check_signature(const uint8_t* sig, size_t length) + .. cpp:function:: bool check_signature(const std::vector<uint8_t>& sig) + + Check to see if *sig* is a valid signature for the message data + that was written in. Return true if so. This function clears the + internal message state, so after this call you can call + :cpp:func:`PK_Verifier::update` to start verifying another + message. + + .. cpp:function:: bool verify_message(const uint8_t* msg, size_t msg_length, \ + const uint8_t* sig, size_t sig_length) + + .. cpp:function:: bool verify_message(const std::vector<uint8_t>& msg, \ + const std::vector<uint8_t>& sig) + + These are equivalent to calling :cpp:func:`PK_Verifier::update` + 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 +#. Ed25519 +#. SM2 + +Code Example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following sample program below demonstrates the generation of a new ECDSA keypair over the curve secp512r1 +and a ECDSA signature using EMSA1 with SHA-256. Subsequently the computed signature is validated. + +.. code-block:: cpp + + #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; + // Generate ECDSA keypair + Botan::ECDSA_PrivateKey key(rng, Botan::EC_Group("secp521r1")); + + std::string text("This is a tasty burger!"); + std::vector<uint8_t> data(text.data(),text.data()+text.length()); + // sign data + 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); + // verify signature + Botan::PK_Verifier verifier(key, "EMSA1(SHA-256)"); + verifier.update(data); + std::cout << std::endl << "is " << (verifier.check_signature(signature)? "valid" : "invalid"); + return 0; + } + + + +Key Agreement +--------------------------------- + +You can get a hold of a ``PK_Key_Agreement_Scheme`` object by calling +``get_pk_kas`` with a key that is of a type that supports key +agreement (such as a Diffie-Hellman key stored in a ``DH_PrivateKey`` +object), and the name of a key derivation function. This can be "Raw", +meaning the output of the primitive itself is returned as the key, or +"KDF1(hash)" or "KDF2(hash)" where "hash" is any string you happen to +like (hopefully you like strings like "SHA-256" or "RIPEMD-160"), or +"X9.42-PRF(keywrap)", which uses the PRF specified in ANSI X9.42. It +takes the name or OID of the key wrap algorithm that will be used to +encrypt a content encryption key. + +How key agreement works is that you trade public values with some +other party, and then each of you runs a computation with the other's +value and your key (this should return the same result to both +parties). This computation can be called by using +``derive_key`` with either a byte array/length pair, or a +``secure_vector<uint8_t>`` than holds the public value of the other +party. The last argument to either call is a number that specifies how +long a key you want. + +Depending on the KDF you're using, you *might not* get back a key +of the size you requested. In particular "Raw" will return a number +about the size of the Diffie-Hellman modulus, and KDF1 can only return +a key that is the same size as the output of the hash. KDF2, on the +other hand, will always give you a key exactly as long as you request, +regardless of the underlying hash used with it. The key returned is a +``SymmetricKey``, ready to pass to a block cipher, MAC, or other +symmetric algorithm. + +The public value that should be used can be obtained by calling +``public_data``, which exists for any key that is associated with a +key agreement algorithm. It returns a ``secure_vector<uint8_t>``. + +"KDF2(SHA-256)" is by far the preferred algorithm for key derivation +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 over GF(p) Weierstrass curves +#. ECDH over x25519 +#. DH over prime fields +#. McEliece +#. NewHope + +Code Example +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The code below performs an unauthenticated ECDH key agreement using the secp521r elliptic curve and +applies the key derivation function KDF2(SHA-256) with 256 bit output length to the computed shared secret. + +.. code-block:: cpp + + #include <botan/auto_rng.h> + #include <botan/ecdh.h> + #include <botan/ec_group.h> + #include <botan/pubkey.h> + #include <botan/hex.h> + #include <iostream> + + int main() + { + Botan::AutoSeeded_RNG rng; + // ec domain and + Botan::EC_Group domain("secp521r1"); + std::string kdf = "KDF2(SHA-256)"; + // generate ECDH keys + Botan::ECDH_PrivateKey keyA(rng, domain); + Botan::ECDH_PrivateKey keyB(rng, domain); + // Construct key agreements + Botan::PK_Key_Agreement ecdhA(keyA,rng,kdf); + Botan::PK_Key_Agreement ecdhB(keyB,rng,kdf); + // Agree on shared secret and derive symmetric key of 256 bit length + Botan::secure_vector<uint8_t> sA = ecdhA.derive_key(32,keyB.public_value()).bits_of(); + Botan::secure_vector<uint8_t> sB = ecdhB.derive_key(32,keyA.public_value()).bits_of(); + + if(sA != sB) + return 1; + + std::cout << "agreed key: " << std::endl << Botan::hex_encode(sA); + return 0; + } + + +McEliece +-------------------------- + +McEliece is a cryptographic scheme based on error correcting codes which is +thought to be resistant to quantum computers. First proposed in 1978, it is fast +and patent-free. Variants have been proposed and broken, but with suitable +parameters the original scheme remains secure. However the public keys are quite +large, which has hindered deployment in the past. + +The implementation of McEliece in Botan was contributed by cryptosource GmbH. It +is based on the implementation HyMES, with the kind permission of Nicolas +Sendrier and INRIA to release a C++ adaption of their original C code under the +Botan license. It was then modified by Falko Strenzke to add side channel and +fault attack countermeasures. You can read more about the implementation at +http://www.cryptosource.de/docs/mceliece_in_botan.pdf + +Encryption in the McEliece scheme consists of choosing a message block of size +`n`, encoding it in the error correcting code which is the public key, then +adding `t` bit errors. The code is created such that knowing only the public +key, decoding `t` errors is intractable, but with the additional knowledge of +the secret structure of the code a fast decoding technique exists. + +The McEliece implementation in HyMES, and also in Botan, uses an optimization to +reduce the public key size, by converting the public key into a systemic code. +This means a portion of the public key is a identity matrix, and can be excluded +from the published public key. However it also means that in McEliece the +plaintext is represented directly in the ciphertext, with only a small number of +bit errors. Thus it is absolutely essential to only use McEliece with a CCA2 +secure scheme. + +One such scheme, KEM, is provided in Botan currently. It it a somewhat unusual +scheme in that it outputs two values, a symmetric key for use with an AEAD, and +an encrypted key. It does this by choosing a random plaintext (n - log2(n)*t +bits) using ``McEliece_PublicKey::random_plaintext_element``. Then a random +error mask is chosen and the message is coded and masked. The symmetric key is +SHA-512(plaintext || error_mask). As long as the resulting key is used with a +secure AEAD scheme (which can be used for transporting arbitrary amounts of +data), CCA2 security is provided. + +In ``mcies.h`` there are functions for this combination: + +.. cpp:function:: secure_vector<uint8_t> mceies_encrypt(const McEliece_PublicKey& pubkey, \ + const secure_vector<uint8_t>& pt, \ + uint8_t ad[], size_t ad_len, \ + RandomNumberGenerator& rng, \ + const std::string& aead = "AES-256/OCB") + +.. cpp:function:: secure_vector<uint8_t> mceies_decrypt(const McEliece_PrivateKey& privkey, \ + const secure_vector<uint8_t>& ct, \ + uint8_t ad[], size_t ad_len, \ + const std::string& aead = "AES-256/OCB") + +For a given security level (SL) a McEliece key would use +parameters n and t, and have the corresponding key sizes listed: + ++-----+------+-----+---------------+----------------+ +| SL | n | t | public key KB | private key KB | ++=====+======+=====+===============+================+ +| 80 | 1632 | 33 | 59 | 140 | ++-----+------+-----+---------------+----------------+ +| 107 | 2280 | 45 | 128 | 300 | ++-----+------+-----+---------------+----------------+ +| 128 | 2960 | 57 | 195 | 459 | ++-----+------+-----+---------------+----------------+ +| 147 | 3408 | 67 | 265 | 622 | ++-----+------+-----+---------------+----------------+ +| 191 | 4624 | 95 | 516 | 1234 | ++-----+------+-----+---------------+----------------+ +| 256 | 6624 | 115 | 942 | 2184 | ++-----+------+-----+---------------+----------------+ + +You can check the speed of McEliece with the suggested parameters above +using ``botan speed McEliece`` + + +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 RFC 8391 "XMSS: eXtended Merkle Signature Scheme", available at +https://datatracker.ietf.org/doc/rfc8391/. + +XMSS uses the Botan interfaces for public key cryptography. +The following algorithms are implemented: + +1. XMSS-SHA2_10_256 +# XMSS-SHA2_16_256 +# XMSS-SHA2_20_256 +# XMSS-SHA2_10_512 +# XMSS-SHA2_16_512 +# XMSS-SHA2_20_512 +# XMSS-SHAKE_10_256 +# XMSS-SHAKE_16_256 +# XMSS-SHAKE_20_256 +# XMSS-SHAKE_10_512 +# XMSS-SHAKE_16_512 +# XMSS-SHAKE_20_512 + +The algorithm name contains the hash function name, tree height and digest +width defined by the corresponding parameter set. Choosing `XMSS-SHA2_10_256` +for instance will use the SHA2-256 hash function to generate a tree of height +ten. + +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 <iostream> + #include <botan/secmem.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_10_256, + 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<uint8_t> msg { 0x01, 0x02, 0x03, 0x04 }; + sig_op->update(msg.data(), msg.size()); + Botan::secure_vector<uint8_t> 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/api_ref/python.rst b/doc/api_ref/python.rst new file mode 100644 index 000000000..5022d9bf8 --- /dev/null +++ b/doc/api_ref/python.rst @@ -0,0 +1,406 @@ + +Python Binding +======================================== + +.. versionadded:: 1.11.14 + +.. highlight:: python + +.. py:module:: botan + +The Python binding is based on the `ffi` module of botan and the +`ctypes` module of the Python standard library. + +Starting in 2.8, the class names were renamed to match Python standard +conventions. However aliases are defined which allow older code to +continue to work; the older names are mentioned as "previously X". + +Versioning +---------------------------------------- +.. py:function:: version_major() + + Returns the major number of the library version. + +.. py:function:: version_minor() + + Returns the minor number of the library version. + +.. py:function:: version_patch() + + Returns the patch number of the library version. + +.. py:function:: version_string() + + Returns a free form version string for the library + +Random Number Generators +---------------------------------------- + +.. py:class:: RandomNumberGenerator(rng_type = 'system') + + Previously ``rng`` + + Type 'user' also allowed (userspace HKDF RNG seeded from system + rng). The system RNG is very cheap to create, as just a single file + handle or CSP handle is kept open, from first use until shutdown, + no matter how many 'system' rng instances are created. Thus it is + easy to use the RNG in a one-off way, with `botan.rng().get(32)`. + + .. py:method:: get(length) + + Return some bits + + .. py:method:: reseed(bits = 256) + + Meaningless on system RNG, on userspace RNG causes a reseed/rekey + + .. py:method:: reseed_from_rng(source_rng, bits = 256) + + Take bits from the source RNG and use it to seed ``self`` + + .. py:method:: add_entropy(seed) + + Add some unpredictable seed data to the RNG + + + +Hash Functions +---------------------------------------- + +.. py:class:: HashFunction(algo) + + Previously ``hash_function`` + + Algo is a string (eg 'SHA-1', 'SHA-384', 'Skein-512') + + .. py:method:: algo_name() + + Returns the name of this algorithm + + .. py:method:: clear() + + Clear state + + .. py:method:: output_length() + + Return output length in bytes + + .. py:method:: update(x) + + Add some input + + .. py:method:: final() + + Returns the hash of all input provided, resets + for another message. + +Message Authentication Codes +---------------------------------------- + +.. py:class:: MsgAuthCode(algo) + + Previously ``message_authentication_code`` + + Algo is a string (eg 'HMAC(SHA-256)', 'Poly1305', 'CMAC(AES-256)') + + .. py:method:: algo_name() + + Returns the name of this algorithm + + .. py:method:: clear() + + Clear internal state including the key + + .. py:method:: output_length() + + Return the output length in bytes + + .. py:method:: set_key(key) + + Set the key + + .. py:method:: update(x) + + Add some input + + .. py:method:: final() + + Returns the MAC of all input provided, resets + for another message with the same key. + +Ciphers +---------------------------------------- + +.. py:class:: SymmetricCipher(object, algo, encrypt = True) + + Previously ``cipher`` + + The algorithm is spcified as a string (eg 'AES-128/GCM', + 'Serpent/OCB(12)', 'Threefish-512/EAX'). + + Set the second param to False for decryption + + .. py:method:: algo_name() + + Returns the name of this algorithm + + .. py:method:: tag_length() + + Returns the tag length (0 for unauthenticated modes) + + .. py:method:: default_nonce_length() + + Returns default nonce length + + .. py:method:: update_granularity() + + Returns update block size. Call to update() must provide input + of exactly this many bytes + + .. py:method:: is_authenticated() + + Returns True if this is an AEAD mode + + .. py:method:: valid_nonce_length(nonce_len) + + Returns True if nonce_len is a valid nonce len for this mode + + .. py:method:: clear() + + Resets all state + + .. py:method:: set_key(key) + + Set the key + + .. py:method:: set_assoc_data(ad) + + Sets the associated data. Fails if this is not an AEAD mode + + .. py:method:: start(nonce) + + Start processing a message using nonce + + .. py:method:: update(txt) + + Consumes input text and returns output. Input text must be of + update_granularity() length. Alternately, always call finish + with the entire message, avoiding calls to update entirely + + .. py:method:: finish(txt = None) + + Finish processing (with an optional final input). May throw if + message authentication checks fail, in which case all plaintext + previously processed must be discarded. You may call finish() + with the entire message + +Bcrypt +---------------------------------------- +.. py:function:: bcrypt(passwd, rng, work_factor = 10) + + Provided the password and an RNG object, returns a bcrypt string + +.. py:function:: check_bcrypt(passwd, bcrypt) + + Check a bcrypt hash against the provided password, returning True + iff the password matches. + +PBKDF +---------------------------------------- + +.. py:function:: pbkdf(algo, password, out_len, iterations = 100000, salt = None) + + Runs a PBKDF2 algo specified as a string (eg 'PBKDF2(SHA-256)', + 'PBKDF2(CMAC(Blowfish))'). Runs with specified iterations, with + meaning depending on the algorithm. The salt can be provided or + otherwise is randomly chosen. In any case it is returned from the + call. + + Returns out_len bytes of output (or potentially less depending on + the algorithm and the size of the request). + + Returns tuple of salt, iterations, and psk + +.. py:function:: pbkdf_timed(algo, password, out_len, ms_to_run = 300, salt = rng().get(12)) + + Runs for as many iterations as needed to consumed ms_to_run + milliseconds on whatever we're running on. Returns tuple of salt, + iterations, and psk + +Scrypt +--------------- + +.. versionadded:: 2.8.0 + +.. py:function:: scrypt(out_len, password, salt, N=1024, r=8, p=8) + + Runs Scrypt key derivation function over the specified password + and salt using Scrypt parameters N, r, p. + +KDF +---------------------------------------- +.. py:function:: kdf(algo, secret, out_len, salt) + + Performs a key derviation function (such as "HKDF(SHA-384)") over + the provided secret and salt values. Returns a value of the + specified length. + +Public Key +---------------------------------------- + +.. py:class:: PublicKey(object) + + Previously ``public_key`` + + .. py:method:: fingerprint(hash = 'SHA-256') + + Returns a hash of the public key + + .. py:method:: algo_name() + + Returns the algorithm name + + .. py:method:: estimated_strength() + + Returns the estimated strength of this key against known attacks + (NFS, Pollard's rho, etc) + + .. py:method:: encoding(pem=False) + + Returns the encoding of the key, PEM if set otherwise DER + +Private Key +---------------------------------------- + +.. py:class:: PrivateKey + + Previously ``private_key`` + + .. py:classmethod:: create(algo, param, rng) + + Creates a new private key. The parameter type/value depends on + the algorithm. For "rsa" is is the size of the key in bits. + For "ecdsa" and "ecdh" it is a group name (for instance + "secp256r1"). For "ecdh" there is also a special case for group + "curve25519" (which is actually a completely distinct key type + with a non-standard encoding). + + .. py:classmethod:: load(val, passphrase="") + + Load a private key (DER or PEM formats accepted) + + .. py:method:: get_public_key() + + Return a public_key object + + .. py:method:: to_pem() + + Return the PEM encoded private key (unencrypted) + + .. py:method:: to_der() + + Return the PEM encoded private key (unencrypted) + +Public Key Operations +---------------------------------------- + +.. py:class:: PKEncrypt(pubkey, padding) + + Previously ``pk_op_encrypt`` + + .. py:method:: encrypt(msg, rng) + +.. py:class:: PKDecrypt(privkey, padding) + + Previously ``pk_op_decrypt`` + + .. py:method:: decrypt(msg) + +.. py:class:: PKSign(privkey, hash_w_padding) + + Previously ``pk_op_sign`` + + .. py:method:: update(msg) + .. py:method:: finish(rng) + +.. py:class:: PKVerify(pubkey, hash_w_padding) + + Previously ``pk_op_verify`` + + .. py:method:: update(msg) + .. py:method:: check_signature(signature) + +.. py:class:: PKKeyAgreement(privkey, kdf) + + Previously ``pk_op_key_agreement`` + + .. py:method:: public_value() + + Returns the public value to be passed to the other party + + .. py:method:: agree(other, key_len, salt) + + Returns a key derived by the KDF. + +Multiple Precision Integers (MPI) +------------------------------------- +.. versionadded:: 2.8.0 + +.. py:class:: MPI(initial_value=None) + + Initialize an MPI object with specified value, left as zero otherwise. The + ``initial_value`` should be an ``int``, ``str``, or ``MPI``. + + Most of the usual arithmetic operators (``__add__``, ``__mul__``, etc) are + defined. + + .. py:method:: inverse_mod(modulus) + + Return the inverse of ``self`` modulo modulus, or zero if no inverse exists + + .. py:method:: is_prime(rng, prob=128) + + Test if ``self`` is prime + + .. py:method:: pow_mod(exponent, modulus): + + Return ``self`` to the ``exponent`` power modulo ``modulus`` + +Format Preserving Encryption (FE1 scheme) +----------------------------------------- +.. versionadded:: 2.8.0 + +.. py:class:: FormatPreservingEncryptionFE1(modulus, key, rounds=5, compat_mode=False) + + Initialize an instance for format preserving encryption + + .. py:method:: encrypt(msg, tweak) + + The msg should be a botan2.MPI or an object which can be converted to one + + .. py:method:: decrypt(msg, tweak) + + The msg should be a botan2.MPI or an object which can be converted to one + +HOTP +----------------------------------------- +.. versionadded:: 2.8.0 + +.. py:class:: HOTP(key, hash="SHA-1", digits=6) + + .. py:method:: generate(counter) + + Generate an HOTP code for the provided counter + + .. py:method:: check(code, counter, resync_range=0) + + Check if provided ``code`` is the correct code for ``counter``. + If ``resync_range`` is greater than zero, HOTP also checks + up to ``resync_range`` following counter values. + + Returns a tuple of (bool,int) where the boolean indicates if the + code was valid, and the int indicates the next counter value + that should be used. If the code did not verify, the next + counter value is always identical to the counter that was passed + in. If the code did verify and resync_range was zero, then the + next counter will always be counter+1. diff --git a/doc/api_ref/rng.rst b/doc/api_ref/rng.rst new file mode 100644 index 000000000..0fc9da388 --- /dev/null +++ b/doc/api_ref/rng.rst @@ -0,0 +1,276 @@ +.. _random_number_generators: + +Random Number Generators +======================================== + +.. cpp:class:: RandomNumberGenerator + + The base class for all RNG objects, is declared in ``rng.h``. + + .. cpp:function:: void randomize(uint8_t* output_array, size_t length) + + Places *length* random bytes into the provided buffer. + + .. cpp:function:: void randomize_with_input(uint8_t* data, size_t length, \ + const uint8_t* extra_input, size_t extra_input_len) + + Like randomize, but first incorporates the additional input field into the + state of the RNG. The additional input could be anything which + parameterizes this request. Not all RNG types accept additional inputs, + the value will be silently ignored when not supported. + + .. cpp:function:: void randomize_with_ts_input(uint8_t* data, size_t length) + + Creates a buffer with some timestamp values and calls ``randomize_with_input`` + + .. note:: + + When RDRAND is enabled and available at runtime, instead of timestamps + the output of RDRAND is used as the additional data. + + .. cpp:function:: uint8_t next_byte() + + Generates a single random byte and returns it. Note that calling this + function several times is much slower than calling ``randomize`` once to + produce multiple bytes at a time. + + .. cpp:function:: void add_entropy(const uint8_t* data, size_t length) + + Incorporates provided data into the state of the PRNG, if at all possible. + This works for most RNG types, including the system and TPM RNGs. But if + the RNG doesn't support this operation, the data is dropped, no error is + indicated. + + .. cpp:function:: bool accepts_input() const + + This function returns ``false`` if it is known that this RNG object cannot + accept external inputs. In this case, any calls to + :cpp:func:`RandomNumberGenerator::add_entropy` will be ignored. + + .. cpp:function:: void reseed_from_rng(RandomNumberGenerator& rng, \ + size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS) + + Reseed by calling ``rng`` to acquire ``poll_bits`` data. + + +RNG Types +---------------------------------------- + +Several different RNG types are implemented. Some access hardware RNGs, which +are only available on certain platforms. Others are mostly useful in specific +situations. + +Generally prefer using either the system RNG, or else ``AutoSeeded_RNG`` which is +intended to provide best possible behavior in a userspace PRNG. + +System_RNG +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On systems which support it, in ``system_rng.h`` you can access a shared +reference to a process global instance of the system PRNG (using interfaces such +as ``/dev/urandom``, ``getrandom``, ``arc4random``, or ``RtlGenRandom``): + +.. cpp:function:: RandomNumberGenerator& system_rng() + + Returns a reference to the system RNG + +There is also a wrapper class ``System_RNG`` which simply invokes on +the return value of ``system_rng()``. This is useful in situations where +you may sometimes want to use the system RNG and a userspace RNG in others, +for example:: + + std::unique_ptr<Botan::RandomNumberGenerator> rng; + #if defined(BOTAN_HAS_SYSTEM_RNG) + rng.reset(new System_RNG); + #else + rng.reset(new AutoSeeded_RNG); + #endif + +Unlike nearly any other object in Botan it is acceptable to share a single +instance of ``System_RNG`` between threads, because the underlying RNG is itself +thread safe due to being serialized by a mutex in the kernel itself. + +AutoSeeded_RNG +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +AutoSeeded_RNG is type naming a 'best available' userspace PRNG. The +exact definition of this has changed over time and may change in the +future, fortunately there is no compatibility concerns when changing +any RNG since the only expectation is it produces bits +indistinguishable from random. + +.. note:: Like most other classes in Botan, it is not safe to share an instance + of ``AutoSeeded_RNG`` among multiple threads without serialization. + +The current version uses HMAC_DRBG with either SHA-384 or SHA-256. The +initial seed is generated either by the system PRNG (if available) or +a default set of entropy sources. These are also used for periodic +reseeding of the RNG state. + +HMAC_DRBG +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +HMAC DRBG is a random number generator designed by NIST and specified +in SP 800-90A. It seems to be the most conservative generator of the +NIST approved options. + +It can be instantiated with any HMAC but is typically used with +SHA-256, SHA-384, or SHA-512, as these are the hash functions approved +for this use by NIST. + +HMAC_DRBG's constructors are: + +.. cpp:class:: HMAC_DRBG + + .. cpp:function:: HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, \ + RandomNumberGenerator& underlying_rng, \ + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, \ + size_t max_number_of_bytes_per_request = 64 * 1024) + + Creates a DRBG which will automatically reseed as required by making + calls to ``underlying_rng`` either after being invoked + ``reseed_interval`` times, or if use of ``fork`` system call is + detected. + + You can disable automatic reseeding by setting ``reseed_interval`` to + zero, in which case ``underlying_rng`` will only be invoked in the case + of ``fork``. + + The specification of HMAC DRBG requires that each invocation produce no + more than 64 kibibytes of data. However, the RNG interface allows + producing arbitrary amounts of data in a single request. To accommodate + this, ``HMAC_DRBG`` treats requests for more data as if they were + multiple requests each of (at most) the maximum size. You can specify a + smaller maximum size with ``max_number_of_bytes_per_request``. There is + normally no reason to do this. + + .. cpp:function:: HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, \ + Entropy_Sources& entropy_sources, \ + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, \ + size_t max_number_of_bytes_per_request = 64 * 1024) + + Like above function, but instead of an RNG taking a set of entropy + sources to seed from as required. + + .. cpp:function:: HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf, \ + RandomNumberGenerator& underlying_rng, \ + Entropy_Sources& entropy_sources, \ + size_t reseed_interval = BOTAN_RNG_DEFAULT_RESEED_INTERVAL, \ + size_t max_number_of_bytes_per_request = 64 * 1024) + + Like above function, but taking both an RNG and a set of entropy + sources to seed from as required. + + .. cpp:function:: HMAC_DRBG(std::unique_ptr<MessageAuthenticationCode> prf) + + Creates an unseeded DRBG. You must explicitly provide seed data later + on in order to use this RNG. This is primarily useful for deterministic + key generation. + + Since no source of data is available to automatically reseed, automatic + reseeding is disabled when this constructor is used. If the RNG object + detects that ``fork`` system call was used without it being + subsequently reseeded, it will throw an exception. + + .. cpp:function:: HMAC_DRBG(const std::string& hmac_hash) + + Like the constructor just taking a PRF, except instead of a PRF object, + a string specifying what hash to use with HMAC is provided. + +ChaCha_RNG +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This is a very fast userspace PRNG based on ChaCha20 and HMAC(SHA-256). The key +for ChaCha is derived by hashing entropy inputs with HMAC. Then the ChaCha +keystream generator is run, first to generate the new HMAC key (used for any +future entropy additions), then the desired RNG outputs. + +This RNG composes two primitives thought to be secure (ChaCha and HMAC) in a +simple and well studied way (the extract-then-expand paradigm), but is still an +ad-hoc and non-standard construction. It is included because it is roughly 20x +faster then HMAC_DRBG (basically running as fast as ChaCha can generate +keystream bits), and certain applications need access to a very fast RNG. + +One thing applications using ``ChaCha_RNG`` need to be aware of is that for +performance reasons, no backtracking resistance is implemented in the RNG +design. An attacker who recovers the ``ChaCha_RNG`` state can recover the output +backwards in time to the last rekey and forwards to the next rekey. + +An explicit reseeding (:cpp:func:`RandomNumberGenerator::add_entropy`) or +providing any input to the RNG +(:cpp:func:`RandomNumberGenerator::randomize_with_ts_input`, +:cpp:func:`RandomNumberGenerator::randomize_with_input`) is sufficient to cause +a reseeding. Or, if a RNG or entropy source was provided to the ``ChaCha_RNG`` +constructor, then reseeding will be performed automatically after a certain +interval of requests. + +RDRAND_RNG +^^^^^^^^^^^^^^^^^ + +This RNG type directly calls the x86 ``rdrand`` instruction. If the instruction +is not available it will throw at runtime, you can check beforehand by calling +``Botan::CPUID::has_rdrand()``. + +TPM_RNG +^^^^^^^^^^^^^^^^^ + +This RNG type allows using the RNG exported from a TPM chip. + +PKCS11_RNG +^^^^^^^^^^^^^^^^^ + +This RNG type allows using the RNG exported from a hardware token accessed via PKCS11. + +Entropy Sources +--------------------------------- + +An ``EntropySource`` is an abstract representation of some method of +gather "real" entropy. This tends to be very system dependent. The +*only* way you should use an ``EntropySource`` is to pass it to a PRNG +that will extract entropy from it -- never use the output directly for +any kind of key or nonce generation! + +``EntropySource`` has a pair of functions for getting entropy from +some external source, called ``fast_poll`` and ``slow_poll``. These +pass a buffer of bytes to be written; the functions then return how +many bytes of entropy were gathered. + +Note for writers of ``EntropySource`` subclasses: it isn't necessary +to use any kind of cryptographic hash on your output. The data +produced by an EntropySource is only used by an application after it +has been hashed by the ``RandomNumberGenerator`` that asked for the +entropy, thus any hashing you do will be wasteful of both CPU cycles +and entropy. + +The following entropy sources are currently used: + + * The system RNG (``arc4random``, ``/dev/urandom``, or ``RtlGenRandom``). + * RDRAND and RDSEED are used if available, but not counted as contributing entropy + * ``/dev/random`` and ``/dev/urandom``. This may be redundant with the system RNG + * ``getentropy``, only used on OpenBSD currently + * ``/proc`` walk: read files in ``/proc``. Last ditch protection against + flawed system RNG. + * Win32 stats: takes snapshot of current system processes. Last ditch + protection against flawed system RNG. + +Fork Safety +--------------------------------- + +On Unix platforms, the ``fork()`` and ``clone()`` system calls can +be used to spawn a new child process. Fork safety ensures that the +child process doesn't see the same output of random bytes as the +parent process. Botan tries to ensure fork safety by feeding the +process ID into the internal state of the random generator and by +automatically reseeding the random generator if the process ID +changed between two requests of random bytes. However, this does +not protect against PID wrap around. The process ID is usually +implemented as a 16 bit integer. In this scenario, a process will +spawn a new child process, which exits the parent process and +spawns a new child process himself. If the PID wrapped around, the +second child process may get assigned the process ID of it's +grandparent and the fork safety can not be ensured. + +Therefore, it is strongly recommended to explicitly reseed any +userspace random generators after forking a new process. If this is +not possible in your application, prefer using the system PRNG +instead. diff --git a/doc/api_ref/secmem.rst b/doc/api_ref/secmem.rst new file mode 100644 index 000000000..8dd479b7e --- /dev/null +++ b/doc/api_ref/secmem.rst @@ -0,0 +1,31 @@ + +Memory container +======================================== + +A major concern with mixing modern multi-user OSes and cryptographic +code is that at any time the code (including secret keys) could be +swapped to disk, where it can later be read by an attacker, or left +floating around in memory for later retrieval. + +For this reason the library uses a ``std::vector`` with a custom +allocator that will zero memory before deallocation, named via typedef +as ``secure_vector``. Because it is simply a STL vector with a custom +allocator, it has an identical API to the ``std::vector`` you know and +love. + +Some operating systems offer the ability to lock memory into RAM, +preventing swapping from occurring. Typically this operation is +restricted to privileged users (root or admin), however some OSes +including Linux and FreeBSD allow normal users to lock a small amount +of memory. On these systems, allocations first attempt to allocate out +of this small locked pool, and then if that fails will fall back to +normal heap allocations. + +The ``secure_vector`` template is only meant for primitive data types +(bytes or ints): if you want a container of higher level Botan +objects, you can just use a ``std::vector``, since these objects know +how to clear themselves when they are destroyed. You cannot, however, +have a ``std::vector`` (or any other container) of ``Pipe`` objects or +filters, because these types have pointers to other filters, and +implementing copy constructors for these types would be both hard and +quite expensive (vectors of pointers to such objects is fine, though). diff --git a/doc/api_ref/srp.rst b/doc/api_ref/srp.rst new file mode 100644 index 000000000..9fcb1a196 --- /dev/null +++ b/doc/api_ref/srp.rst @@ -0,0 +1,67 @@ +Secure Remote Password +======================================== + +The library contains an implementation of the +`SRP6-a <http://srp.stanford.edu/design.html>`_ password authenticated +key exchange protocol in ``srp6.h``. + +A SRP client provides what is called a SRP *verifier* to the server. +This verifier is based on a password, but the password cannot be +easily derived from the verifier. Later, the client and server can +perform an SRP exchange, which results in a shared key. + +SRP works in a discrete logarithm group. Special parameter sets for +SRP6 are defined, denoted in the library as "modp/srp/<size>", for +example "modp/srp/2048". + +.. warning:: + + While knowledge of the verifier does not easily allow an attacker + to get the raw password, they could still use the verifier to + impersonate the server to the client, so verifiers should be + carefully protected. + +.. cpp:function:: BigInt generate_srp6_verifier( \ + const std::string& identifier, \ + const std::string& password, \ + const std::vector<uint8_t>& salt, \ + const std::string& group_id, \ + const std::string& hash_id) + + Generates a new verifier using the specified password and salt. + This is stored by the server. The salt must also be stored. + +.. cpp:function:: std::string srp6_group_identifier( \ + const BigInt& N, const BigInt& g) + +.. cpp:class:: SRP6_Server_Session + + .. cpp:function:: BigInt step1(const BigInt& v, \ + const std::string& group_id, \ + const std::string& hash_id, \ + RandomNumberGenerator& rng) + + Takes a verifier (generated by generate_srp6_verifier) + along with the group_id (which must match + + .. cpp:function:: SymmetricKey step2(const BigInt& A) + + Takes the parameter A generated by srp6_client_agree, + and return the shared secret key. + +.. cpp:function:: std::pair<BigInt,SymmetricKey> srp6_client_agree( \ + const std::string& username, \ + const std::string& password, \ + const std::string& group_id, \ + const std::string& hash_id, \ + const std::vector<uint8_t>& salt, \ + const BigInt& B, \ + RandomNumberGenerator& rng) + + The client receives these parameters from the server, except for + the username and password which are provided by the user. The + parameter B is the output of `step1`. + + The client agreement step outputs a shared symmetric key along + with the parameter A which is returned to the server (and allows + it the compute the shared key). diff --git a/doc/api_ref/stream_ciphers.rst b/doc/api_ref/stream_ciphers.rst new file mode 100644 index 000000000..dfee40970 --- /dev/null +++ b/doc/api_ref/stream_ciphers.rst @@ -0,0 +1,211 @@ +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`). + +.. warning:: + + Using a stream cipher without an authentication code is extremely insecure, + because an attacker can trivially modify messages. Prefer using an + authenticated cipher mode such as GCM or SIV. + +.. warning:: + + Encrypting more than one message with the same key requires careful management + of initialization vectors. Otherwise the keystream will be reused, which causes + the security of the cipher to completely fail. + +.. cpp:class:: StreamCipher + + .. cpp:function:: std::string name() const + + Returns a human-readable string of the name of this algorithm. + + .. cpp:function:: void clear() + + Clear the key. + + .. cpp:function:: StreamCipher* clone() const + + Return a newly allocated object of the same type as this one. + + .. cpp:function:: void set_key(const uint8_t* key, size_t length) + + Set the stream cipher key. If the length is not accepted, an + ``Invalid_Key_Length`` exception is thrown. + + .. 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 acceptable for the + algorithm. + + .. cpp:function:: size_t maximum_keylength() const + + Return the largest key length (in bytes) that is acceptable for the + algorithm. + + .. 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. Some ciphers do not support IVs at all, and will return + false for any value except zero. + + .. cpp:function:: size_t default_iv_length() const + + Returns some default IV size, normally the largest IV supported by the cipher. + If this function returns zero, then IVs are not supported and any call to + ``set_iv`` with a non-empty value will fail. + + .. cpp:function:: void set_iv(const uint8_t*, 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. + + If the cipher does not support IVs, then a call with ``len`` equal to zero + will be accepted and any other length will cause a ``Invalid_IV_Length`` + exception. + + .. cpp:function:: void seek(uint64_t offset) + + Sets the state of the stream cipher and keystream according to the passed + *offset*, exactly as if *offset* bytes had first been encrypted. The key + and (if required) the IV have to be set before this can be called. Not all + ciphers support seeking; such objects will throw ``Not_Implemented`` in + this case. + + .. cpp:function:: void cipher(const uint8_t* in, uint8_t* out, size_t n) + + Processes *n* bytes plain/ciphertext from *in* and writes the result to *out*. + + .. cpp:function:: void cipher1(uint8_t* 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<uint8_t> inout) + .. cpp:function:: void encrypt(std::vector<uint8_t> inout) + .. cpp:function:: void decrypt(std::vector<uint8_t> inout) + + Processes plain/ciphertext *inout* in place. Acts like :cpp:func:`cipher`\ (inout.data(), inout.data(), inout.size()). + +Code Example +----------------- + +The following code encrypts a provided plaintext using ChaCha20. + +.. code-block:: cpp + + #include <botan/stream_cipher.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(20)")); + + //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()); + cipher->encipher(pt); + + std::cout << cipher->name() << " with iv " << Botan::hex_encode(iv) << ": " + << Botan::hex_encode(pt) << "\n"; + return 0; + } + +Available Stream Ciphers +---------------------------- + +Botan provides the following stream ciphers. If in doubt use ChaCha20 or CTR(AES-256). + +CTR-BE +~~~~~~~ + +A cipher mode that converts a block cipher into a stream cipher. It offers +parallel execution and can seek within the output stream, both useful +properties. + +CTR mode requires an IV which can be any length up to the block size of the +underlying cipher. If it is shorter than the block size, sufficient zero bytes +are appended. + +It is possible to choose the width of the counter portion, which can improve +performance somewhat, but limits the maximum number of bytes that can safely be +encrypted. Different protocols have different conventions for the width of the +counter portion. This is done by specifying with width (which must be at least 4 +bytes, allowing to encrypt 2\ :sup:`32` blocks of data) for example +"CTR(AES-256,8)" to select a 64-bit counter. + +(The ``-BE`` suffix refers to big-endian convention for the counter. +This is the most common case.) + +OFB +~~~~~ + +Another stream cipher based on a block cipher. Unlike CTR mode, it does not +allow parallel execution or seeking within the output stream. Prefer CTR. + +Available if ``BOTAN_HAS_OFB`` is defined. + +ChaCha +~~~~~~~~ + +A very fast cipher, now widely deployed in TLS as part of the ChaCha20Poly1305 +AEAD. Can be used with 8 (fast but dangerous), 12 (balance), or 20 rounds +(conservative). Even with 20 rounds, ChaCha is very fast. Use 20 rounds. + +ChaCha supports an optional IV (which defaults to all zeros). It can be of +length 64, 96 or (since 2.8) 192 bits. Using ChaCha with a 192 bit nonce is also +known as XChaCha. + +Available if ``BOTAN_HAS_CHACHA`` is defined. + +Salsa20 +~~~~~~~~~ + +An earlier iteration of the ChaCha design, this cipher is popular due to its use +in the libsodium library. Prefer ChaCha. + +Salsa supports an optional IV (which defaults to all zeros). It can be of length +64 or 192 bits. Using Salsa with a 192 bit nonce is also known as XSalsa. + +Available if ``BOTAN_HAS_SALSA20`` is defined. + +SHAKE-128 +~~~~~~~~~~~~ + +This is the SHAKE-128 XOF exposed as a stream cipher. It is slower than ChaCha +and somewhat obscure. It does not support IVs or seeking within the cipher +stream. + +Available if ``BOTAN_HAS_SHAKE_CIPHER`` is defined. + +RC4 +~~~~ + +An old and very widely deployed stream cipher notable for its simplicity. It +does not support IVs or seeking within the cipher stream. + +.. warning:: + + RC4 is now badly broken. **Avoid in new code** and use only if required for + compatibility with existing systems. + +Available if ``BOTAN_HAS_RC4`` is defined. diff --git a/doc/api_ref/tls.rst b/doc/api_ref/tls.rst new file mode 100644 index 000000000..74f8bf79a --- /dev/null +++ b/doc/api_ref/tls.rst @@ -0,0 +1,1844 @@ +Transport Layer Security (TLS) +======================================== + +.. versionadded:: 1.11.0 + +Botan has client and server implementations of various versions of the +TLS protocol, including TLS v1.0, TLS v1.1, and TLS v1.2. As of +version 1.11.13, support for the insecure SSLv3 protocol has been +removed. + +There is also support for DTLS (v1.0 and v1.2), a variant of TLS +adapted for operation on datagram transports such as UDP and +SCTP. DTLS support should be considered as beta quality and further +testing is invited. + +The TLS implementation does not know anything about sockets or the +network layer. Instead, it calls a user provided callback (hereafter +``output_fn``) whenever it has data that it would want to send to the +other party (for instance, by writing it to a network socket), and +whenever the application receives some data from the counterparty (for +instance, by reading from a network socket) it passes that information +to TLS using :cpp:func:`TLS::Channel::received_data`. If the data +passed in results in some change in the state, such as a handshake +completing, or some data or an alert being received from the other +side, then the appropriate user provided callback will be invoked. + +If the reader is familiar with OpenSSL's BIO layer, it might be analogous +to saying the only way of interacting with Botan's TLS is via a `BIO_mem` I/O +abstraction. This makes the library completely agnostic to how you +write your network layer, be it blocking sockets, libevent, asio, a +message queue, lwIP on RTOS, some carrier pidgeons, etc. + +Starting in 1.11.31, the application callbacks are encapsulated as the class +``TLS::Callbacks`` with the following members. The first four (``tls_emit_data``, +``tls_record_received``, ``tls_alert``, and ``tls_session_established``) are +mandatory for using TLS, all others are optional and provide additional +information about the connection. + + .. cpp:function:: void tls_emit_data(const uint8_t data[], size_t data_len) + + Mandatory. The TLS stack requests that all bytes of *data* be queued up to send to the + counterparty. After this function returns, the buffer containing *data* will + be overwritten, so a copy of the input must be made if the callback + cannot send the data immediately. + + As an example you could ``send`` to perform a blocking write on a socket, + or append the data to a queue managed by your application, and initiate + an asynchronous write. + + For TLS all writes must occur *in the order requested*. + For DTLS this ordering is not strictly required, but is still recommended. + + .. cpp:function:: void tls_record_received(uint64_t rec_no, const uint8_t data[], size_t data_len) + + Mandatory. Called once for each application_data record which is received, with the + matching (TLS level) record sequence number. + + Currently empty records are ignored and do not instigate a callback, + but this may change in a future release. + + As with ``tls_emit_data``, the array will be overwritten sometime after + the callback returns, so a copy should be made if needed. + + For TLS the record number will always increase. + + For DTLS, it is possible to receive records with the `rec_no` field out of + order, or with gaps, corresponding to reordered or lost datagrams. + + .. cpp:function:: void tls_alert(Alert alert) + + Mandatory. Called when an alert is received from the peer. Note that alerts + received before the handshake is complete are not authenticated and + could have been inserted by a MITM attacker. + + .. cpp:function:: bool tls_session_established(const TLS::Session& session) + + Mandatory. Called whenever a negotiation completes. This can happen more + than once on any connection, if renegotiation occurs. The *session* parameter + provides information about the session which was just established. + + If this function returns false, the session will not be cached + for later resumption. + + If this function wishes to cancel the handshake, it can throw an + exception which will send a close message to the counterparty and + reset the connection state. + + .. cpp::function:: void tls_verify_cert_chain(const std::vector<X509_Certificate>& cert_chain, \ + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses, \ + const std::vector<Certificate_Store*>& trusted_roots, \ + Usage_Type usage, \ + const std::string& hostname, \ + const Policy& policy) + + Optional - default implementation should work for many users. + It can be overridden for implementing extra validation routines + such as public key pinning. + + Verifies the certificate chain in *cert_chain*, assuming the leaf + certificate is the first element. Throws an exception if any + error makes this certificate chain unacceptable. + + If usage is `Usage_Type::TLS_SERVER_AUTH`, then *hostname* should + match the information in the server certificate. If usage is + `TLS_CLIENT_AUTH`, then *hostname* specifies the host the client + is authenticating against (from SNI); the callback can use this for + any special site specific auth logic. + + The `ocsp_responses` is a possibly empty list of OCSP responses provided by + the server. In the current implementation of TLS OCSP stapling, only a + single OCSP response can be returned. A existing TLS extension allows the + server to send multiple OCSP responses, this extension may be supported in + the future in which case more than one OCSP response may be given during + this callback. + + The `trusted_roots` parameter was returned by a call from the associated + `Credentials_Manager`. + + The `policy` provided is the policy for the TLS session which is + being authenticated using this certificate chain. It can be consulted + for values such as allowable signature methods and key sizes. + + .. cpp::function:: std::chrono::milliseconds tls_verify_cert_chain_ocsp_timeout() const + + Called by default `tls_verify_cert_chain` to set timeout for online OCSP requests + on the certificate chain. Return 0 to disable OCSP. Current default is 0. + + .. cpp:function:: std::string tls_server_choose_app_protocol(const std::vector<std::string>& client_protos) + + Optional. Called by the server when a client includes a list of protocols in the ALPN extension. + The server then choose which protocol to use, or "" to disable sending any ALPN response. + The default implementation returns the empty string all of the time, effectively disabling + ALPN responses. + + .. cpp:function:: void tls_inspect_handshake_msg(const Handshake_Message&) + + This callback is optional, and can be used to inspect all handshake messages + while the session establishment occurs. + + .. cpp:function:: void tls_modify_extensions(Extensions& extn, Connection_Side which_side) + + This callback is optional, and can be used to modify extensions before they + are sent to the peer. For example this enables adding a custom extension, + or replacing or removing an extension set by the library. + + .. cpp:function:: void tls_examine_extensions(const Extensions& extn, Connection_Side which_side) + + This callback is optional, and can be used to examine extensions sent by + the peer. + + .. cpp:function:: void tls_log_error(const char* msg) + + Optional logging for an error message. (Not currently used) + + .. cpp:function:: void tls_log_debug(const char* msg) + + Optional logging for an debug message. (Not currently used) + + .. cpp:function:: void tls_log_debug_bin(const char* descr, const uint8_t val[], size_t len) + + Optional logging for an debug value. (Not currently used) + + .. cpp:function:: std::string tls_decode_group_param(TLS::Group_Params group_param) + + Optional. Called by the server when a client hello includes a list of supported groups in the + supported_groups extension and by the client when decoding the server key exchange including the selected curve identifier. + The function should return the name of the DH group or elliptic curve the passed + TLS group identifier should be mapped to. Therefore this callback enables the use of custom + elliptic curves or DH groups in TLS, if both client and server map the custom identifiers correctly. + Please note that it is required to allow the group TLS identifier in + in the used :cpp:class:`TLS::Policy`. + +Versions from 1.11.0 to 1.11.30 did not have ``TLS::Callbacks`` and instead +used independent std::functions to pass the various callback functions. +This interface is currently still included but is deprecated and will be removed +in a future release. For the documentation for this interface, please check +the docs for 1.11.30. This version of the manual only documents the new interface +added in 1.11.31. + +TLS Channels +---------------------------------------- + +TLS servers and clients share an interface called `TLS::Channel`. A +TLS channel (either client or server object) has these methods +available: + +.. cpp:class:: TLS::Channel + + .. cpp:function:: size_t received_data(const uint8_t buf[], size_t buf_size) + .. cpp:function:: size_t received_data(const std::vector<uint8_t>& buf) + + This function is used to provide data sent by the counterparty + (eg data that you read off the socket layer). Depending on the + current protocol state and the amount of data provided this may + result in one or more callback functions that were provided to + the constructor being called. + + The return value of ``received_data`` specifies how many more + bytes of input are needed to make any progress, unless the end of + the data fell exactly on a message boundary, in which case it + will return 0 instead. + + .. cpp:function:: void send(const uint8_t buf[], size_t buf_size) + .. cpp:function:: void send(const std::string& str) + .. cpp:function:: void send(const std::vector<uint8_t>& vec) + + Create one or more new TLS application records containing the + provided data and send them. This will eventually result in at + least one call to the ``output_fn`` callback before ``send`` + returns. + + If the current TLS connection state is unable to transmit new + application records (for example because a handshake has not + yet completed or the connection has already ended due to an + error) an exception will be thrown. + + .. cpp:function:: void close() + + A close notification is sent to the counterparty, and the + internal state is cleared. + + .. cpp:function:: void send_alert(const Alert& alert) + + Some other alert is sent to the counterparty. If the alert is + fatal, the internal state is cleared. + + .. cpp:function:: bool is_active() + + Returns true if and only if a handshake has been completed on + this connection and the connection has not been subsequently + closed. + + .. cpp:function:: bool is_closed() + + Returns true if and only if either a close notification or a + fatal alert message have been either sent or received. + + .. cpp:function:: bool timeout_check() + + This function does nothing unless the channel represents a DTLS + connection and a handshake is actively in progress. In this case + it will check the current timeout state and potentially initiate + retransmission of handshake packets. Returns true if a timeout + condition occurred. + + .. cpp:function:: void renegotiate(bool force_full_renegotiation = false) + + Initiates a renegotiation. The counterparty is allowed by the + protocol to ignore this request. If a successful renegotiation + occurs, the *handshake_cb* callback will be called again. + + If *force_full_renegotiation* is false, then the client will + attempt to simply renew the current session - this will refresh + the symmetric keys but will not change the session master + secret. Otherwise it will initiate a completely new session. + + For a server, if *force_full_renegotiation* is false, then a + session resumption will be allowed if the client attempts + it. Otherwise the server will prevent resumption and force the + creation of a new session. + + .. cpp:function:: std::vector<X509_Certificate> peer_cert_chain() + + Returns the certificate chain of the counterparty. When acting + as a client, this value will be non-empty unless the client's + policy allowed anonymous connections and the server then chose + an anonymous ciphersuite. Acting as a server, this value will + ordinarily be empty, unless the server requested a certificate + and the client responded with one. + + .. cpp:function:: SymmetricKey key_material_export( \ + const std::string& label, \ + const std::string& context, \ + size_t length) + + Returns an exported key of *length* bytes derived from *label*, + *context*, and the session's master secret and client and server + random values. This key will be unique to this connection, and + as long as the session master secret remains secure an attacker + should not be able to guess the key. + + Per :rfc:`5705`, *label* should begin with "EXPERIMENTAL" unless + the label has been standardized in an RFC. + +.. _tls_client: + +TLS Clients +---------------------------------------- + +.. cpp:class:: TLS::Client + + .. cpp:function:: Client( \ + Callbacks& callbacks, \ + Session_Manager& session_manager, \ + Credentials_Manager& creds, \ + const Policy& policy, \ + RandomNumberGenerator& rng, \ + const Server_Information& server_info = Server_Information(), \ + const Protocol_Version offer_version = Protocol_Version::latest_tls_version(), \ + const std::vector<std::string>& next_protocols = std::vector<std::string>(), \ + size_t reserved_io_buffer_size = 16*1024 \ + ) + + Initialize a new TLS client. The constructor will immediately + initiate a new session. + + The *callbacks* parameter specifies the various application callbacks + which pertain to this particular client connection. + + The *session_manager* is an interface for storing TLS sessions, + which allows for session resumption upon reconnecting to a server. + In the absence of a need for persistent sessions, use + :cpp:class:`TLS::Session_Manager_In_Memory` which caches + connections for the lifetime of a single process. See + :ref:`tls_session_managers` for more about session managers. + + The *credentials_manager* is an interface that will be called to + retrieve any certificates, secret keys, pre-shared keys, or SRP + information; see :doc:`credentials_manager` for more information. + + Use the optional *server_info* to specify the DNS name of the + server you are attempting to connect to, if you know it. This helps + the server select what certificate to use and helps the client + validate the connection. + + Note that the server name indicator name must be a FQDN. IP + addresses are not allowed by RFC 6066 and may lead to interoperability + problems. + + Use the optional *offer_version* to control the version of TLS you + wish the client to offer. Normally, you'll want to offer the most + recent version of (D)TLS that is available, however some broken + servers are intolerant of certain versions being offered, and for + classes of applications that have to deal with such servers + (typically web browsers) it may be necessary to implement a version + backdown strategy if the initial attempt fails. + + .. warning:: + + Implementing such a backdown strategy allows an attacker to + downgrade your connection to the weakest protocol that both you + and the server support. + + Setting *offer_version* is also used to offer DTLS instead of TLS; + use :cpp:func:`TLS::Protocol_Version::latest_dtls_version`. + + Optionally, the client will advertise *app_protocols* to the + server using the ALPN extension. + + The optional *reserved_io_buffer_size* specifies how many bytes to + pre-allocate in the I/O buffers. Use this if you want to control + how much memory the channel uses initially (the buffers will be + resized as needed to process inputs). Otherwise some reasonable + default is used. + +Code Example +^^^^^^^^^^^^ +A minimal example of a TLS client is provided below. +The full code for a TLS client using BSD sockets is in `src/cli/tls_client.cpp` + +.. code-block:: cpp + + #include <botan/tls_client.h> + #include <botan/tls_callbacks.h> + #include <botan/tls_session_manager.h> + #include <botan/tls_policy.h> + #include <botan/auto_rng.h> + #include <botan/certstor.h> + + /** + * @brief Callbacks invoked by TLS::Channel. + * + * Botan::TLS::Callbacks is an abstract class. + * For improved readability, only the functions that are mandatory + * to implement are listed here. See src/lib/tls/tls_callbacks.h. + */ + class Callbacks : public Botan::TLS::Callbacks + { + public: + void tls_emit_data(const uint8_t data[], size_t size) override + { + // send data to tls server, e.g., using BSD sockets or boost asio + } + + void tls_record_received(uint64_t seq_no, const uint8_t data[], size_t size) override + { + // process full TLS record received by tls server, e.g., + // by passing it to the application + } + + void tls_alert(Botan::TLS::Alert alert) override + { + // handle a tls alert received from the tls server + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + // the session with the tls server was established + // return false to prevent the session from being cached, true to + // cache the session in the configured session manager + return false; + } + }; + + /** + * @brief Credentials storage for the tls client. + * + * It returns a list of trusted CA certificates from a local directory. + * TLS client authentication is disabled. See src/lib/tls/credentials_manager.h. + */ + class Client_Credentials : public Botan::Credentials_Manager + { + public: + std::vector<Botan::Certificate_Store*> trusted_certificate_authorities( + const std::string& type, + const std::string& context) override + { + // return a list of certificates of CAs we trust for tls server certificates, + // e.g., all the certificates in the local directory "cas" + return { new Botan::Certificate_Store_In_Memory("cas") }; + } + + std::vector<Botan::X509_Certificate> cert_chain( + const std::vector<std::string>& cert_key_types, + const std::string& type, + const std::string& context) override + { + // when using tls client authentication (optional), return + // a certificate chain being sent to the tls server, + // else an empty list + return std::vector<Botan::X509_Certificate>(); + } + + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert, + const std::string& type, + const std::string& context) override + { + // when returning a chain in cert_chain(), return the private key + // associated with the leaf certificate here + return nullptr; + } + }; + + int main() + { + // prepare all the parameters + Callbacks callbacks; + Botan::AutoSeeded_RNG rng; + Botan::TLS::Session_Manager_In_Memory session_mgr(rng); + Client_Credentials creds; + Botan::TLS::Strict_Policy policy; + + // open the tls connection + Botan::TLS::Client client(callbacks, + session_mgr, + creds, + policy, + rng, + Botan::TLS::Server_Information("botan.randombit.net", 443), + Botan::TLS::Protocol_Version::TLS_V12); + + while(!client.is_closed()) + { + // read data received from the tls server, e.g., using BSD sockets or boost asio + // ... + + // send data to the tls server using client.send_data() + } + } + +TLS Servers +---------------------------------------- + +.. cpp:class:: TLS::Server + + .. cpp:function:: Server( \ + Callbacks& callbacks, \ + Session_Manager& session_manager, \ + Credentials_Manager& creds, \ + const Policy& policy, \ + RandomNumberGenerator& rng, \ + bool is_datagram = false, \ + size_t reserved_io_buffer_size = 16*1024 \ + ) + +The first 5 arguments as well as the final argument +*reserved_io_buffer_size*, are treated similarly to the :ref:`client +<tls_client>`. + +If a client sends the ALPN extension, the ``callbacks`` function +``tls_server_choose_app_protocol`` will be called and the result +sent back to the client. If the empty string is returned, the server +will not send an ALPN response. The function can also throw an exception +to abort the handshake entirely, the ALPN specification says that if this +occurs the alert should be of type `NO_APPLICATION_PROTOCOL`. + +The optional argument *is_datagram* specifies if this is a TLS or DTLS +server; unlike clients, which know what type of protocol (TLS vs DTLS) +they are negotiating from the start via the *offer_version*, servers +would not until they actually received a client hello. + +Code Example +^^^^^^^^^^^^ +A minimal example of a TLS server is provided below. +The full code for a TLS server using asio is in `src/cli/tls_proxy.cpp`. + +.. code-block:: cpp + + #include <botan/tls_client.h> + #include <botan/tls_callbacks.h> + #include <botan/tls_session_manager.h> + #include <botan/tls_policy.h> + #include <botan/auto_rng.h> + #include <botan/certstor.h> + #include <botan/pk_keys.h> + + #include <memory> + + /** + * @brief Callbacks invoked by TLS::Channel. + * + * Botan::TLS::Callbacks is an abstract class. + * For improved readability, only the functions that are mandatory + * to implement are listed here. See src/lib/tls/tls_callbacks.h. + */ + class Callbacks : public Botan::TLS::Callbacks + { + public: + void tls_emit_data(const uint8_t data[], size_t size) override + { + // send data to tls client, e.g., using BSD sockets or boost asio + } + + void tls_record_received(uint64_t seq_no, const uint8_t data[], size_t size) override + { + // process full TLS record received by tls client, e.g., + // by passing it to the application + } + + void tls_alert(Botan::TLS::Alert alert) override + { + // handle a tls alert received from the tls server + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + // the session with the tls client was established + // return false to prevent the session from being cached, true to + // cache the session in the configured session manager + return false; + } + }; + + /** + * @brief Credentials storage for the tls server. + * + * It returns a certificate and the associated private key to + * authenticate the tls server to the client. + * TLS client authentication is not requested. + * See src/lib/tls/credentials_manager.h. + */ + class Server_Credentials : public Botan::Credentials_Manager + { + public: + Server_Credentials() : m_key(Botan::PKCS8::load_key("botan.randombit.net.key")) + { + } + + std::vector<Botan::Certificate_Store*> trusted_certificate_authorities( + const std::string& type, + const std::string& context) override + { + // if client authentication is required, this function + // shall return a list of certificates of CAs we trust + // for tls client certificates, otherwise return an empty list + return std::vector<Certificate_Store*>(); + } + + std::vector<Botan::X509_Certificate> cert_chain( + const std::vector<std::string>& cert_key_types, + const std::string& type, + const std::string& context) override + { + // return the certificate chain being sent to the tls client + // e.g., the certificate file "botan.randombit.net.crt" + return { Botan::X509_Certificate("botan.randombit.net.crt") }; + } + + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert, + const std::string& type, + const std::string& context) override + { + // return the private key associated with the leaf certificate, + // in this case the one associated with "botan.randombit.net.crt" + return &m_key; + } + + private: + std::unique_ptr<Botan::Private_Key> m_key; + }; + + int main() + { + // prepare all the parameters + Callbacks callbacks; + Botan::AutoSeeded_RNG rng; + Botan::TLS::Session_Manager_In_Memory session_mgr(rng); + Server_Credentials creds; + Botan::TLS::Strict_Policy policy; + + // accept tls connection from client + Botan::TLS::Server server(callbacks, + session_mgr, + creds, + policy, + rng); + + // read data received from the tls client, e.g., using BSD sockets or boost asio + // and pass it to server.received_data(). + // ... + + // send data to the tls client using server.send_data() + // ... + } + +.. _tls_sessions: + +TLS Sessions +---------------------------------------- + +TLS allows clients and servers to support *session resumption*, where +the end point retains some information about an established session +and then reuse that information to bootstrap a new session in way that +is much cheaper computationally than a full handshake. + +Every time your handshake callback is called, a new session has been +established, and a ``TLS::Session`` is included that provides +information about that session: + +.. cpp:class:: TLS::Session + + .. cpp:function:: Protocol_Version version() const + + Returns the :cpp:class:`protocol version <TLS::Protocol_Version>` + that was negotiated + + .. cpp:function:: Ciphersuite ciphersite() const + + Returns the :cpp:class:`ciphersuite <TLS::Ciphersuite>` that + was negotiated. + + .. cpp:function:: Server_Information server_info() const + + Returns information that identifies the server side of the + connection. This is useful for the client in that it + identifies what was originally passed to the constructor. For + the server, it includes the name the client specified in the + server name indicator extension. + + .. cpp:function:: std::vector<X509_Certificate> peer_certs() const + + Returns the certificate chain of the peer + + .. cpp:function:: std::string srp_identifier() const + + If an SRP ciphersuite was used, then this is the identifier + that was used for authentication. + + .. cpp:function:: bool secure_renegotiation() const + + Returns ``true`` if the connection was negotiated with the + correct extensions to prevent the renegotiation attack. + + .. cpp:function:: std::vector<uint8_t> encrypt(const SymmetricKey& key, \ + RandomNumberGenerator& rng) + + Encrypts a session using a symmetric key *key* and returns a raw + binary value that can later be passed to ``decrypt``. The key + may be of any length. + + Currently the implementation encrypts the session using AES-256 + in GCM mode with a random nonce. + + .. cpp:function:: static Session decrypt(const uint8_t ciphertext[], \ + size_t length, \ + const SymmetricKey& key) + + Decrypts a session that was encrypted previously with ``encrypt`` and + ``key``, or throws an exception if decryption fails. + + .. cpp:function:: secure_vector<uint8_t> DER_encode() const + + Returns a serialized version of the session. + + .. warning:: The return value of ``DER_encode`` contains the + master secret for the session, and an attacker who + recovers it could recover plaintext of previous + sessions or impersonate one side to the other. + +.. _tls_session_managers: + +TLS Session Managers +---------------------------------------- + +You may want sessions stored in a specific format or storage type. To +do so, implement the ``TLS::Session_Manager`` interface and pass your +implementation to the ``TLS::Client`` or ``TLS::Server`` constructor. + +.. cpp:class:: TLS::Session_Mananger + + .. cpp:function:: void save(const Session& session) + + Save a new *session*. It is possible that this sessions session + ID will replicate a session ID already stored, in which case the + new session information should overwrite the previous information. + + .. cpp:function:: void remove_entry(const std::vector<uint8_t>& session_id) + + Remove the session identified by *session_id*. Future attempts + at resumption should fail for this session. + + .. cpp:function:: bool load_from_session_id(const std::vector<uint8_t>& session_id, \ + Session& session) + + Attempt to resume a session identified by *session_id*. If + located, *session* is set to the session data previously passed + to *save*, and ``true`` is returned. Otherwise *session* is not + modified and ``false`` is returned. + + .. cpp:function:: bool load_from_server_info(const Server_Information& server, \ + Session& session) + + Attempt to resume a session with a known server. + + .. cpp:function:: std::chrono::seconds session_lifetime() const + + Returns the expected maximum lifetime of a session when using + this session manager. Will return 0 if the lifetime is unknown + or has no explicit expiration policy. + +.. _tls_session_manager_inmem: + +In Memory Session Manager +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``TLS::Session_Manager_In_Memory`` implementation saves sessions +in memory, with an upper bound on the maximum number of sessions and +the lifetime of a session. + +It is safe to share a single object across many threads as it uses a +lock internally. + +.. cpp:class:: TLS::Session_Managers_In_Memory + + .. cpp:function:: Session_Manager_In_Memory(RandomNumberGenerator& rng, \ + size_t max_sessions = 1000, \ + std::chrono::seconds session_lifetime = 7200) + + Limits the maximum number of saved sessions to *max_sessions*, and + expires all sessions older than *session_lifetime*. + +Noop Session Mananger +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The ``TLS::Session_Manager_Noop`` implementation does not save +sessions at all, and thus session resumption always fails. Its +constructor has no arguments. + +SQLite3 Session Manager +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This session manager is only available if support for SQLite3 was +enabled at build time. If the macro +``BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER`` is defined, then +``botan/tls_session_manager_sqlite.h`` contains +``TLS::Session_Manager_SQLite`` which stores sessions persistently to +a sqlite3 database. The session data is encrypted using a passphrase, +and stored in two tables, named ``tls_sessions`` (which holds the +actual session information) and ``tls_sessions_metadata`` (which holds +the PBKDF information). + +.. warning:: The hostnames associated with the saved sessions are + stored in the database in plaintext. This may be a + serious privacy risk in some applications. + +.. cpp:class:: TLS::Session_Manager_SQLite + + .. cpp:function:: Session_Manager_SQLite( \ + const std::string& passphrase, \ + RandomNumberGenerator& rng, \ + const std::string& db_filename, \ + size_t max_sessions = 1000, \ + std::chrono::seconds session_lifetime = 7200) + + Uses the sqlite3 database named by *db_filename*. + +TLS Policies +---------------------------------------- + +``TLS::Policy`` is how an application can control details of what will +be negotiated during a handshake. The base class acts as the default +policy. There is also a ``Strict_Policy`` (which forces only secure +options, reducing compatibility) and ``Text_Policy`` which reads +policy settings from a file. + +.. cpp:class:: TLS::Policy + + .. cpp:function:: std::vector<std::string> allowed_ciphers() const + + Returns the list of ciphers we are willing to negotiate, in order + of preference. + + Clients send a list of ciphersuites in order of preference, + servers are free to choose any of them. Some servers will use the + clients preferences, others choose from the clients list + prioritizing based on its preferences. + + No export key exchange mechanisms or ciphersuites are supported + by botan. The null encryption ciphersuites (which provide only + authentication, sending data in cleartext) are also not supported + by the implementation and cannot be negotiated. + + Cipher names without an explicit mode refers to CBC+HMAC ciphersuites. + + Default value: "ChaCha20Poly1305", "AES-256/GCM", "AES-128/GCM" + + Also allowed: "AES-256", "AES-128", + "AES-256/CCM", "AES-128/CCM", "AES-256/CCM(8)", "AES-128/CCM(8)", + "Camellia-256/GCM", "Camellia-128/GCM", "ARIA-256/GCM", "ARIA-128/GCM", + "Camellia-256", "Camellia-128" + + Also allowed (though currently experimental): "AES-128/OCB(12)", + "AES-256/OCB(12)" + + In versions up to 2.8.0, the CBC and CCM ciphersuites "AES-256", + "AES-128", "AES-256/CCM" and "AES-128/CCM" were enabled by default. + + Also allowed (although **not recommended**): "SEED", "3DES" + + .. note:: + + Before 1.11.30 only the non-standard ChaCha20Poly1305 ciphersuite + was implemented. The RFC 7905 ciphersuites are supported in 1.11.30 + onwards. + + .. note:: + + Support for the broken RC4 cipher was removed in 1.11.17 + + .. note:: + + SEED and 3DES are deprecated and will be removed in a future release. + + .. cpp:function:: std::vector<std::string> allowed_macs() const + + Returns the list of algorithms we are willing to use for + message authentication, in order of preference. + + Default: "AEAD", "SHA-256", "SHA-384", "SHA-1" + + A plain hash function indicates HMAC + + .. note:: + + SHA-256 is preferred over SHA-384 in CBC mode because the + protections against the Lucky13 attack are somewhat more + effective for SHA-256 than SHA-384. + + .. cpp:function:: std::vector<std::string> allowed_key_exchange_methods() const + + Returns the list of key exchange methods we are willing to use, + in order of preference. + + Default: "CECPQ1", "ECDH", "DH" + + .. note:: + + CECPQ1 key exchange provides post-quantum security to the key exchange + by combining NewHope with a standard x25519 ECDH exchange. This prevents + an attacker, even one with a quantum computer, from later decrypting the + contents of a recorded TLS transcript. The NewHope algorithm is very + fast, but adds roughly 4 KiB of additional data transfer to every TLS + handshake. And even if NewHope ends up completely broken, the 'extra' + x25519 exchange secures the handshake. + + For applications where the additional data transfer size is unacceptable, + simply allow only ECDH key exchange in the application policy. DH + exchange also often involves transferring several additional Kb (without + the benefit of post quantum security) so if CECPQ1 is being disabled for + traffic overhead reasons, DH should also be avoid. + + Also allowed: "RSA", "SRP_SHA", "ECDHE_PSK", "DHE_PSK", "PSK" + + .. note:: + + Static RSA ciphersuites are disabled by default since 1.11.34. + In addition to not providing forward security, any server which is + willing to negotiate these ciphersuites exposes themselves to a variety + of chosen ciphertext oracle attacks which are all easily avoided by + signing (as in PFS) instead of decrypting. + + .. note:: + + In order to enable RSA, SRP, or PSK ciphersuites one must also enable + authentication method "IMPLICIT", see :cpp:func:`allowed_signature_methods`. + + .. cpp:function:: std::vector<std::string> allowed_signature_hashes() const + + Returns the list of hash algorithms we are willing to use for + public key signatures, in order of preference. + + Default: "SHA-512", "SHA-384", "SHA-256" + + Also allowed (although **not recommended**): "SHA-1" + + .. note:: + + This is only used with TLS v1.2. In earlier versions of the + protocol, signatures are fixed to using only SHA-1 (for + DSA/ECDSA) or a MD5/SHA-1 pair (for RSA). + + .. cpp:function:: std::vector<std::string> allowed_signature_methods() const + + Default: "ECDSA", "RSA" + + Also allowed (disabled by default): "DSA", "IMPLICIT", "ANONYMOUS" + + "IMPLICIT" enables ciphersuites which are authenticated not by a signature + but through a side-effect of the key exchange. In particular this setting + is required to enable PSK, SRP, and static RSA ciphersuites. + + "ANONYMOUS" allows purely anonymous DH/ECDH key exchanges. **Enabling this + is not recommended** + + .. note:: + + Both DSA authentication and anonymous DH ciphersuites are deprecated, + and will be removed in a future release. + + .. cpp:function:: std::vector<Group_Params> key_exchange_groups() const + + Return a list of ECC curve and DH group TLS identifiers we are willing to use, in order of preference. + The default ordering puts the best performing ECC first. + + Default: + Group_Params::X25519, + Group_Params::SECP256R1, Group_Params::BRAINPOOL256R1, + Group_Params::SECP384R1, Group_Params::BRAINPOOL384R1, + Group_Params::SECP521R1, Group_Params::BRAINPOOL512R1, + Group_Params::FFDHE_2048, Group_Params::FFDHE_3072, Group_Params::FFDHE_4096, + Group_Params::FFDHE_6144, Group_Params::FFDHE_8192 + + No other values are currently defined. + + .. cpp:function:: bool use_ecc_point_compression() const + + Prefer ECC point compression. + + Signals that we prefer ECC points to be compressed when transmitted to us. + The other party may not support ECC point compression and therefore may still + send points uncompressed. + + Note that the certificate used during authentication must also follow the other + party's preference. + + Default: false + + .. cpp:function:: bool acceptable_protocol_version(Protocol_Version version) + + Return true if this version of the protocol is one that we are + willing to negotiate. + + Default: Accepts TLS v1.0 or higher and DTLS v1.2 or higher. + + .. cpp:function:: bool server_uses_own_ciphersuite_preferences() const + + If this returns true, a server will pick the cipher it prefers the + most out of the client's list. Otherwise, it will negotiate the + first cipher in the client's ciphersuite list that it supports. + + .. cpp:function:: bool negotiate_heartbeat_support() const + + If this function returns true, clients will offer the heartbeat + support extension, and servers will respond to clients offering + the extension. Otherwise, clients will not offer heartbeat + support and servers will ignore clients offering heartbeat + support. + + If this returns true, callers should expect to handle heartbeat + data in their ``alert_cb``. + + Default: false + + .. cpp:function:: bool allow_client_initiated_renegotiation() const + + If this function returns true, a server will accept a + client-initiated renegotiation attempt. Otherwise it will send + the client a non-fatal ``no_renegotiation`` alert. + + Default: true + + .. cpp:function:: bool allow_server_initiated_renegotiation() const + + If this function returns true, a client will accept a + server-initiated renegotiation attempt. Otherwise it will send + the server a non-fatal ``no_renegotiation`` alert. + + Default: false + + .. cpp:function:: bool allow_insecure_renegotiation() const + + If this function returns true, we will allow renegotiation attempts + even if the counterparty does not support the RFC 5746 extensions. + + .. warning:: Returning true here could expose you to attacks + + Default: false + + .. cpp:function:: size_t minimum_signature_strength() const + + Return the minimum strength (as ``n``, representing ``2**n`` work) + we will accept for a signature algorithm on any certificate. + + Use 80 to enable RSA-1024 (*not recommended*), or 128 to require + either ECC or large (~3000 bit) RSA keys. + + Default: 110 (allowing 2048 bit RSA) + + .. cpp:function:: bool require_cert_revocation_info() const + + If this function returns true, and a ciphersuite using certificates was + negotiated, then we must have access to a valid CRL or OCSP response in + order to trust the certificate. + + .. warning:: Returning false here could expose you to attacks + + Default: true + + .. cpp:function:: Group_Params default_dh_group() const + + For ephemeral Diffie-Hellman key exchange, the server sends a + group parameter. Return the 2 Byte TLS group identifier specifying the group parameter a + server should use. + + Default: 2048 bit IETF IPsec group ("modp/ietf/2048") + + .. cpp:function:: size_t minimum_dh_group_size() const + + Return the minimum size in bits for a Diffie-Hellman group that a + client will accept. Due to the design of the protocol the client + has only two options - accept the group, or reject it with a + fatal alert then attempt to reconnect after disabling ephemeral + Diffie-Hellman. + + Default: 2048 bits + + .. cpp:function:: bool allow_tls10() const + + Return true from here to allow TLS v1.0. Since 2.8.0, returns + ``false`` by default. + + .. cpp:function:: bool allow_tls11() const + + Return true from here to allow TLS v1.1. Since 2.8.0, returns + ``false`` by default. + + .. cpp:function:: bool allow_tls12() const + + Return true from here to allow TLS v1.2. Returns ``true`` by default. + + .. cpp:function:: size_t minimum_rsa_bits() const + + Minimum accepted RSA key size. Default 2048 bits. + + .. cpp:function:: size_t minimum_dsa_group_size() const + + Minimum accepted DSA key size. Default 2048 bits. + + .. cpp:function:: size_t minimum_ecdsa_group_size() const + + Minimum size for ECDSA keys (256 bits). + + .. cpp:function:: size_t minimum_ecdh_group_size() const + + Minimum size for ECDH keys (255 bits). + + .. cpp:function:: void check_peer_key_acceptable(const Public_Key& public_key) const + + Allows the policy to examine peer public keys. Throw an exception + if the key should be rejected. Default implementation checks + against policy values `minimum_dh_group_size`, `minimum_rsa_bits`, + `minimum_ecdsa_group_size`, and `minimum_ecdh_group_size`. + + .. cpp:function:: bool hide_unknown_users() const + + The SRP and PSK suites work using an identifier along with a + shared secret. If this function returns true, when an identifier + that the server does not recognize is provided by a client, a + random shared secret will be generated in such a way that a + client should not be able to tell the difference between the + identifier not being known and the secret being wrong. This can + help protect against some username probing attacks. If it + returns false, the server will instead send an + ``unknown_psk_identity`` alert when an unknown identifier is + used. + + Default: false + + .. cpp:function:: u32bit session_ticket_lifetime() const + + Return the lifetime of session tickets. Each session includes the + start time. Sessions resumptions using tickets older than + ``session_ticket_lifetime`` seconds will fail, forcing a full + renegotiation. + + Default: 86400 seconds (1 day) + +TLS Ciphersuites +---------------------------------------- + +.. cpp:class:: TLS::Ciphersuite + + .. cpp:function:: uint16_t ciphersuite_code() const + + Return the numerical code for this ciphersuite + + .. cpp:function:: std::string to_string() const + + Return the full name of ciphersuite (for example + "RSA_WITH_RC4_128_SHA" or "ECDHE_RSA_WITH_AES_128_GCM_SHA256") + + .. cpp:function:: std::string kex_algo() const + + Return the key exchange algorithm of this ciphersuite + + .. cpp:function:: std::string sig_algo() const + + Return the signature algorithm of this ciphersuite + + .. cpp:function:: std::string cipher_algo() const + + Return the cipher algorithm of this ciphersuite + + .. cpp:function:: std::string mac_algo() const + + Return the authentication algorithm of this ciphersuite + + .. cpp:function:: bool acceptable_ciphersuite(const Ciphersuite& suite) const + + Return true if ciphersuite is accepted by the policy. + + Allows an application to reject any ciphersuites, which are + undesirable for whatever reason without having to reimplement + :cpp:func:`TLS::Ciphersuite::ciphersuite_list` + + .. cpp:function:: std::vector<uint16_t> ciphersuite_list(Protocol_Version version, bool have_srp) const + + Return allowed ciphersuites in order of preference + + Allows an application to have full control over ciphersuites + by returning desired ciphersuites in preference order. + +.. _tls_alerts: + +TLS Alerts +---------------------------------------- + +A ``TLS::Alert`` is passed to every invocation of a channel's *alert_cb*. + +.. cpp:class:: TLS::Alert + + .. cpp:function:: is_valid() const + + Return true if this alert is not a null alert + + .. cpp:function:: is_fatal() const + + Return true if this alert is fatal. A fatal alert causes the + connection to be immediately disconnected. Otherwise, the alert + is a warning and the connection remains valid. + + .. cpp:function:: Type type() const + + Returns the type of the alert as an enum + + .. cpp:function:: std::string type_string() + + Returns the type of the alert as a string + +TLS Protocol Version +---------------------------------------- + +TLS has several different versions with slightly different behaviors. +The ``TLS::Protocol_Version`` class represents a specific version: + +.. cpp:class:: TLS::Protocol_Version + + .. cpp:enum:: Version_Code + + ``TLS_V10``, ``TLS_V11``, ``TLS_V12``, ``DTLS_V10``, ``DTLS_V12`` + + .. cpp:function:: Protocol_Version(Version_Code named_version) + + Create a specific version + + .. cpp:function:: uint8_t major_version() const + + Returns major number of the protocol version + + .. cpp:function:: uint8_t minor_version() const + + Returns minor number of the protocol version + + .. cpp:function:: std::string to_string() const + + Returns string description of the version, for instance "TLS + v1.1" or "DTLS v1.0". + + .. cpp:function:: static Protocol_Version latest_tls_version() + + Returns the latest version of the TLS protocol known to the library + (currently TLS v1.2) + + .. cpp:function:: static Protocol_Version latest_dtls_version() + + Returns the latest version of the DTLS protocol known to the + library (currently DTLS v1.2) + +TLS Custom Curves +---------------------------------------- + +The supported_groups TLS extension is used in the client hello to advertise a list of supported elliptic curves +and DH groups. The server subsequently selects one of the groups, which is supported by both endpoints. +The groups are represented by their TLS identifier. This 2 Byte identifier is standardized for commonly used groups and curves. +In addition, the standard reserves the identifiers 0xFE00 to 0xFEFF for custom groups or curves. + +Using non standardized custom curves is however not recommended and can be a serious risk if an +insecure curve is used. Still, it might be desired in some scenarios to use custom curves or groups in the TLS handshake. + +To use custom curves with the Botan :cpp:class:`TLS::Client` or :cpp:class:`TLS::Server` the following additional adjustments have to be implemented +as shown in the following code examples. + +1. Registration of the custom curve +2. Implementation TLS callback ``tls_decode_group_param`` +3. Adjustment of the TLS policy by allowing the custom curve + +Client Code Example +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: cpp + + #include <botan/tls_client.h> + #include <botan/tls_callbacks.h> + #include <botan/tls_session_manager.h> + #include <botan/tls_policy.h> + #include <botan/auto_rng.h> + #include <botan/certstor.h> + + #include <botan/ec_group.h> + #include <botan/oids.h> + + + /** + * @brief Callbacks invoked by TLS::Channel. + * + * Botan::TLS::Callbacks is an abstract class. + * For improved readability, only the functions that are mandatory + * to implement are listed here. See src/lib/tls/tls_callbacks.h. + */ + class Callbacks : public Botan::TLS::Callbacks + { + public: + void tls_emit_data(const uint8_t data[], size_t size) override + { + // send data to tls server, e.g., using BSD sockets or boost asio + } + + void tls_record_received(uint64_t seq_no, const uint8_t data[], size_t size) override + { + // process full TLS record received by tls server, e.g., + // by passing it to the application + } + + void tls_alert(Botan::TLS::Alert alert) override + { + // handle a tls alert received from the tls server + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + // the session with the tls server was established + // return false to prevent the session from being cached, true to + // cache the session in the configured session manager + return false; + } + std::string tls_decode_group_param(Botan::TLS::Group_Params group_param) override + { + // handle TLS group identifier decoding and return name as string + // return empty string to indicate decoding failure + + switch(static_cast<uint16_t>(group_param)) + { + case 0xFE00: + return "testcurve1102"; + default: + //decode non-custom groups + return Botan::TLS::Callbacks::tls_decode_group_param(group_param); + } + } + }; + + /** + * @brief Credentials storage for the tls client. + * + * It returns a list of trusted CA certificates from a local directory. + * TLS client authentication is disabled. See src/lib/tls/credentials_manager.h. + */ + class Client_Credentials : public Botan::Credentials_Manager + { + public: + std::vector<Botan::Certificate_Store*> trusted_certificate_authorities( + const std::string& type, + const std::string& context) override + { + // return a list of certificates of CAs we trust for tls server certificates, + // e.g., all the certificates in the local directory "cas" + return { new Botan::Certificate_Store_In_Memory("cas") }; + } + + std::vector<Botan::X509_Certificate> cert_chain( + const std::vector<std::string>& cert_key_types, + const std::string& type, + const std::string& context) override + { + // when using tls client authentication (optional), return + // a certificate chain being sent to the tls server, + // else an empty list + return std::vector<Botan::X509_Certificate>(); + } + + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert, + const std::string& type, + const std::string& context) override + { + // when returning a chain in cert_chain(), return the private key + // associated with the leaf certificate here + return nullptr; + } + }; + + class Client_Policy : public Botan::TLS::Strict_Policy + { + public: + std::vector<Botan::TLS::Group_Params> key_exchange_groups() const override + { + // modified strict policy to allow our custom curves + return + { + static_cast<Botan::TLS::Group_Params>(0xFE00) + }; + } + }; + + int main() + { + // prepare rng + Botan::AutoSeeded_RNG rng; + + // prepare custom curve + + // prepare curve parameters + const Botan::BigInt p("0x92309a3e88b94312f36891a2055725bb35ab51af96b3a651d39321b7bbb8c51575a76768c9b6b323"); + const Botan::BigInt a("0x4f30b8e311f6b2dce62078d70b35dacb96aa84b758ab5a8dff0c9f7a2a1ff466c19988aa0acdde69"); + const Botan::BigInt b("0x9045A513CFFF9AE1F1CC84039D852D240344A1D5C9DB203C844089F855C387823EB6FCDDF49C909C"); + + const Botan::BigInt x("0x9120f3779a31296cefcb5a5a08831f1a6d438ad5a3f2ce60585ac19c74eebdc65cadb96bb92622c7"); + const Botan::BigInt y("0x836db8251c152dfee071b72c6b06c5387d82f1b5c30c5a5b65ee9429aa2687e8426d5d61276a4ede"); + const Botan::BigInt order("0x248c268fa22e50c4bcda24688155c96ecd6ad46be5c82d7a6be6e7068cb5d1ca72b2e07e8b90d853"); + + const Botan::BigInt cofactor(4); + + const Botan::OID oid("1.2.3.1"); + + // create EC_Group object to register the curve + Botan::EC_Group testcurve1102(p, a, b, x, y, order, cofactor, oid); + + if(!testcurve1102.verify_group(rng)) + { + // Warning: if verify_group returns false the curve parameters are insecure + } + + // register name to specified oid + Botan::OIDS::add_oid(oid, "testcurve1102"); + + // prepare all the parameters + Callbacks callbacks; + Botan::TLS::Session_Manager_In_Memory session_mgr(rng); + Client_Credentials creds; + Client_Policy policy; + + // open the tls connection + Botan::TLS::Client client(callbacks, + session_mgr, + creds, + policy, + rng, + Botan::TLS::Server_Information("botan.randombit.net", 443), + Botan::TLS::Protocol_Version::TLS_V12); + + + while(!client.is_closed()) + { + // read data received from the tls server, e.g., using BSD sockets or boost asio + // ... + + // send data to the tls server using client.send_data() + + } + } + +Server Code Example +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: cpp + + #include <botan/tls_server.h> + #include <botan/tls_callbacks.h> + #include <botan/tls_session_manager.h> + #include <botan/tls_policy.h> + #include <botan/auto_rng.h> + #include <botan/certstor.h> + #include <botan/pk_keys.h> + #include <botan/pkcs8.h> + + #include <botan/ec_group.h> + #include <botan/oids.h> + + #include <memory> + + /** + * @brief Callbacks invoked by TLS::Channel. + * + * Botan::TLS::Callbacks is an abstract class. + * For improved readability, only the functions that are mandatory + * to implement are listed here. See src/lib/tls/tls_callbacks.h. + */ + class Callbacks : public Botan::TLS::Callbacks + { + public: + void tls_emit_data(const uint8_t data[], size_t size) override + { + // send data to tls client, e.g., using BSD sockets or boost asio + } + + void tls_record_received(uint64_t seq_no, const uint8_t data[], size_t size) override + { + // process full TLS record received by tls client, e.g., + // by passing it to the application + } + + void tls_alert(Botan::TLS::Alert alert) override + { + // handle a tls alert received from the tls server + } + + bool tls_session_established(const Botan::TLS::Session& session) override + { + // the session with the tls client was established + // return false to prevent the session from being cached, true to + // cache the session in the configured session manager + return false; + } + + std::string tls_decode_group_param(Botan::TLS::Group_Params group_param) override + { + // handle TLS group identifier decoding and return name as string + // return empty string to indicate decoding failure + + switch(static_cast<uint16_t>(group_param)) + { + case 0xFE00: + return "testcurve1102"; + default: + //decode non-custom groups + return Botan::TLS::Callbacks::tls_decode_group_param(group_param); + } + } + }; + + /** + * @brief Credentials storage for the tls server. + * + * It returns a certificate and the associated private key to + * authenticate the tls server to the client. + * TLS client authentication is not requested. + * See src/lib/tls/credentials_manager.h. + */ + class Server_Credentials : public Botan::Credentials_Manager + { + public: + Server_Credentials() : m_key(Botan::PKCS8::load_key("botan.randombit.net.key") + { + } + + std::vector<Botan::Certificate_Store*> trusted_certificate_authorities( + const std::string& type, + const std::string& context) override + { + // if client authentication is required, this function + // shall return a list of certificates of CAs we trust + // for tls client certificates, otherwise return an empty list + return std::vector<Botan::Certificate_Store*>(); + } + + std::vector<Botan::X509_Certificate> cert_chain( + const std::vector<std::string>& cert_key_types, + const std::string& type, + const std::string& context) override + { + // return the certificate chain being sent to the tls client + // e.g., the certificate file "botan.randombit.net.crt" + return { Botan::X509_Certificate("botan.randombit.net.crt") }; + } + + Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert, + const std::string& type, + const std::string& context) override + { + // return the private key associated with the leaf certificate, + // in this case the one associated with "botan.randombit.net.crt" + return m_key.get(); + } + + private: + std::unique_ptr<Botan::Private_Key> m_key; + }; + + class Server_Policy : public Botan::TLS::Strict_Policy + { + public: + std::vector<Botan::TLS::Group_Params> key_exchange_groups() const override + { + // modified strict policy to allow our custom curves + return + { + static_cast<Botan::TLS::Group_Params>(0xFE00) + }; + } + }; + + int main() + { + + // prepare rng + Botan::AutoSeeded_RNG rng; + + // prepare custom curve + + // prepare curve parameters + const Botan::BigInt p("0x92309a3e88b94312f36891a2055725bb35ab51af96b3a651d39321b7bbb8c51575a76768c9b6b323"); + const Botan::BigInt a("0x4f30b8e311f6b2dce62078d70b35dacb96aa84b758ab5a8dff0c9f7a2a1ff466c19988aa0acdde69"); + const Botan::BigInt b("0x9045A513CFFF9AE1F1CC84039D852D240344A1D5C9DB203C844089F855C387823EB6FCDDF49C909C"); + + const Botan::BigInt x("0x9120f3779a31296cefcb5a5a08831f1a6d438ad5a3f2ce60585ac19c74eebdc65cadb96bb92622c7"); + const Botan::BigInt y("0x836db8251c152dfee071b72c6b06c5387d82f1b5c30c5a5b65ee9429aa2687e8426d5d61276a4ede"); + const Botan::BigInt order("0x248c268fa22e50c4bcda24688155c96ecd6ad46be5c82d7a6be6e7068cb5d1ca72b2e07e8b90d853"); + + const Botan::BigInt cofactor(4); + + const Botan::OID oid("1.2.3.1"); + + // create EC_Group object to register the curve + Botan::EC_Group testcurve1102(p, a, b, x, y, order, cofactor, oid); + + if(!testcurve1102.verify_group(rng)) + { + // Warning: if verify_group returns false the curve parameters are insecure + } + + // register name to specified oid + Botan::OIDS::add_oid(oid, "testcurve1102"); + + // prepare all the parameters + Callbacks callbacks; + Botan::TLS::Session_Manager_In_Memory session_mgr(rng); + Server_Credentials creds; + Server_Policy policy; + + // accept tls connection from client + Botan::TLS::Server server(callbacks, + session_mgr, + creds, + policy, + rng); + + // read data received from the tls client, e.g., using BSD sockets or boost asio + // and pass it to server.received_data(). + // ... + + // send data to the tls client using server.send_data() + // ... + } + +TLS Stream +---------------------------------------- + +:cpp:class:`TLS::Stream` offers a Boost.Asio compatible wrapper around :cpp:class:`TLS::Client`. +It can be used as an alternative to Boost.Asio's `ssl::stream <https://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/reference/ssl__stream.html>`_ with minor adjustments to the using code. +It offers the following interface: + +.. cpp:class:: template <class StreamLayer, class ChannelT> TLS::Stream + + *StreamLayer* specifies the type of the stream's *next layer*, for example a `Boost.Asio TCP socket <https://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/reference/ip__tcp/socket.html>`_. + *ChannelT* is the type of the stream's *native handle*; it defaults to :cpp:class:`TLS::Channel` and should not be specified manually. + + .. cpp:function:: template <typename... Args> \ + explicit Stream(Context& context, Args&& ... args) + + Construct a new TLS stream. + The *context* parameter will be used to set up the underlying *native handle*, i.e. the :ref:`TLS::Client <tls_client>`, when :cpp:func:`handshake` is called. + The further *args* will be forwarded to the *next layer*'s constructor. + + .. cpp:function:: template <typename... Args> \ + explicit Stream(Arg&& arg, Context& context) + + Convenience constructor for :cpp:class:`boost::asio::ssl::stream` compatibility. + The parameters have the same meaning as for the first constructor, but their order is changed and only one argument can be passed to the *next layer* constructor. + + + .. cpp:function:: void handshake(Connection_Side side, boost::system::error_code& ec) + + Set up the *native handle* and perform the TLS handshake. + As only the client side of the stream is currently implemented, *side* should be ``Connection_Side::CLIENT``. + + .. cpp:function:: void handshake(Connection_Side side) + + Overload of :cpp:func:`handshake` that throws an exception if an error occurs. + + .. cpp:function:: template <typename HandshakeHandler> \ + DEDUCED async_handshake(Connection_Side side, HandshakeHandler&& handler) + + Asynchronous variant of :cpp:func:`handshake`. + The function returns immediately and calls the *handler* callback function after performing asynchronous I/O to complete the TLS handshake. + The return type is an automatically deduced specialization of :cpp:class:`boost::asio::async_result`, depending on the *HandshakeHandler* type. + + + .. cpp:function:: void shutdown(boost::system::error_code& ec) + + Calls :cpp:func:`TLS::Channel::close` on the native handle and writes the TLS alert to the *next layer*. + + .. cpp:function:: void shutdown() + + Overload of :cpp:func:`shutdown` that throws an exception if an error occurs. + + + .. cpp:function:: template <typename MutableBufferSequence> \ + std::size_t read_some(const MutableBufferSequence& buffers, boost::system::error_code& ec) + + Reads encrypted data from the *next layer*, decrypts it, and writes it into the provided *buffers*. + If an error occurs, *error_code* is set. + Returns the number of bytes read. + + .. cpp:function:: template <typename MutableBufferSequence> \ + std::size_t read_some(const MutableBufferSequence& buffers) + + Overload of :cpp:func:`read_some` that throws an exception if an error occurs. + + .. cpp:function:: template <typename MutableBufferSequence, typename ReadHandler> \ + DEDUCED async_read_some(const MutableBufferSequence& buffers, ReadHandler&& handler) + + Asynchronous variant of :cpp:func:`read_some`. + The function returns immediately and calls the *handler* callback function after writing the decrypted data into the provided *buffers*. + The return type is an automatically deduced specialization of :cpp:class:`boost::asio::async_result`, depending on the *ReadHandler* type. + *ReadHandler* should suffice the `requirements to a Boost.Asio read handler <https://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/reference/ReadHandler.html>`_. + + + .. cpp:function:: template <typename ConstBufferSequence> \ + std::size_t write_some(const ConstBufferSequence& buffers, boost::system::error_code& ec) + + Encrypts data from the provided *buffers* and writes it to the *next layer*. + If an error occurs, *error_code* is set. + Returns the number of bytes written. + + .. cpp:function:: template <typename ConstBufferSequence> \ + std::size_t write_some(const ConstBufferSequence& buffers) + + Overload of :cpp:func:`write_some` that throws an exception rather than setting an error code. + + .. cpp:function:: template <typename ConstBufferSequence, typename WriteHandler> \ + DEDUCED async_write_some(const ConstBufferSequence& buffers, WriteHandler&& handler) + + Asynchronous variant of :cpp:func:`write_some`. + The function returns immediately and calls the *handler* callback function after writing the encrypted data to the *next layer*. + The return type is an automatically deduced specialization of :cpp:class:`boost::asio::async_result`, depending on the *WriteHandler* type. + *WriteHandler* should suffice the `requirements to a Boost.Asio write handler <https://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/reference/WriteHandler.html>`_. + +.. cpp:struct:: TLS::Context + + A helper struct to collect the initialization parameters for the Stream's underlying *native handle* (see :cpp:class:`TLS::Client`). + `TLS::Context` is defined as + + .. code-block:: cpp + + struct Context + { + Credentials_Manager* credentialsManager; + RandomNumberGenerator* randomNumberGenerator; + Session_Manager* sessionManager; + Policy* policy; + Server_Information serverInfo; + }; + + +Stream Code Example +^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: cpp + + #include <iostream> + + #include <botan/asio_stream.h> + #include <botan/auto_rng.h> + #include <botan/certstor_system.h> + + #include <boost/asio.hpp> + #include <boost/beast.hpp> + #include <boost/bind.hpp> + + namespace http = boost::beast::http; + namespace _ = boost::asio::placeholders; + + // very basic credentials manager + class Credentials_Manager : public Botan::Credentials_Manager + { + public: + Credentials_Manager() {} + + std::vector<Botan::Certificate_Store*> + trusted_certificate_authorities(const std::string&, const std::string&) override + { + return {&cert_store_}; + } + + private: + Botan::System_Certificate_Store cert_store_; + }; + + // a simple https client based on TLS::Stream + class client + { + public: + client(boost::asio::io_context& io_context, + boost::asio::ip::tcp::resolver::iterator endpoint_iterator, + http::request<http::string_body> req) + : request_(req) + , ctx_{&credentials_mgr_, + &rng_, + &session_mgr_, + &policy_, + Botan::TLS::Server_Information()} + , stream_(io_context, ctx_) + { + boost::asio::async_connect(stream_.lowest_layer(), endpoint_iterator, + boost::bind(&client::handle_connect, this, _::error)); + } + + void handle_connect(const boost::system::error_code& error) + { + if(error) + { + std::cout << "Connect failed: " << error.message() << "\n"; + return; + } + stream_.async_handshake(Botan::TLS::Connection_Side::CLIENT, + boost::bind(&client::handle_handshake, this, _::error)); + } + + void handle_handshake(const boost::system::error_code& error) + { + if(error) + { + std::cout << "Handshake failed: " << error.message() << "\n"; + return; + } + http::async_write(stream_, request_, + boost::bind(&client::handle_write, this, _::error, _::bytes_transferred)); + } + + void handle_write(const boost::system::error_code& error, size_t) + { + if(error) + { + std::cout << "Write failed: " << error.message() << "\n"; + return; + } + http::async_read(stream_, reply_, response_, + boost::bind(&client::handle_read, this, _::error, _::bytes_transferred)); + } + + void handle_read(const boost::system::error_code& error, size_t) + { + if(!error) + { + std::cout << "Reply: "; + std::cout << response_.body() << "\n"; + } + else + { + std::cout << "Read failed: " << error.message() << "\n"; + } + } + + private: + http::request<http::dynamic_body> request_; + http::response<http::string_body> response_; + boost::beast::flat_buffer reply_; + + Botan::TLS::Session_Manager_Noop session_mgr_; + Botan::AutoSeeded_RNG rng_; + Credentials_Manager credentials_mgr_; + Botan::TLS::Policy policy_; + + Botan::TLS::Context ctx_; + Botan::TLS::Stream<boost::asio::ip::tcp::socket> stream_; + }; + + int main() + { + boost::asio::io_context io_context; + + boost::asio::ip::tcp::resolver resolver(io_context); + boost::asio::ip::tcp::resolver::query query("botan.randombit.net", "443"); + boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); + + http::request<http::string_body> req; + req.version(11); + req.method(http::verb::get); + req.target("/news.html"); + req.set(http::field::host, "botan.randombit.net"); + + client c(io_context, iterator, req); + + io_context.run(); + } diff --git a/doc/api_ref/tpm.rst b/doc/api_ref/tpm.rst new file mode 100644 index 000000000..7598c4bd8 --- /dev/null +++ b/doc/api_ref/tpm.rst @@ -0,0 +1,113 @@ +Trusted Platform Module (TPM) +========================================== + +.. versionadded:: 1.11.26 + +Some computers come with a TPM, which is a small side processor which can +perform certain operations which include RSA key generation and signing, a +random number generator, accessing a small amount of NVRAM, and a set of PCRs +which can be used to measure software state (this is TPMs most famous use, for +authenticating a boot sequence). + +The TPM NVRAM and PCR APIs are not supported by Botan at this time, patches welcome. + +Currently only v1.2 TPMs are supported, and the only TPM library supported is +TrouSerS (http://trousers.sourceforge.net/). Hopefully both of these limitations +will be removed in a future release, in order to support newer TPM v2.0 systems. +The current code has been tested with an ST TPM running in a Lenovo laptop. + +Test for TPM support with the macro ``BOTAN_HAS_TPM``, include ``<botan/tpm.h>``. + +First, create a connection to the TPM with a ``TPM_Context``. The context is +passed to all other TPM operations, and should remain alive as long as any other +TPM object which the context was passed to is still alive, otherwise errors or +even an application crash are possible. In the future, the API may change to +using ``shared_ptr`` to remove this problem. + +.. cpp:class:: TPM_Context + + .. cpp:function:: TPM_Context(pin_cb cb, const char* srk_password) + + The (somewhat improperly named) pin_cb callback type takes a std::string as + an argument, which is an informative message for the user. It should return + a string containing the password entered by the user. + + Normally the SRK password is null. Use nullptr to signal this. + +The TPM contains a RNG of unknown design or quality. If that doesn't scare you +off, you can use it with ``TPM_RNG`` which implements the standard +``RandomNumberGenerator`` interface. + +.. cpp:class:: TPM_RNG + + .. cpp:function:: TPM_RNG(TPM_Context& ctx) + + Initialize a TPM RNG object. After initialization, reading from + this RNG reads from the hardware? RNG on the TPM. + +The v1.2 TPM uses only RSA, but because this key is implemented completely in +hardware it uses a different private key type, with a somewhat different API to +match the TPM's behavior. + +.. cpp:class:: TPM_PrivateKey + + .. cpp:function:: TPM_PrivateKey(TPM_Context& ctx, size_t bits, const char* key_password) + + Create a new RSA key stored on the TPM. The bits should be either 1024 + or 2048; the TPM interface hypothetically allows larger keys but in + practice no v1.2 TPM hardware supports them. + + The TPM processor is not fast, be prepared for this to take a while. + + The key_password is the password to the TPM key ? + + .. cpp:function:: std::string register_key(TPM_Storage_Type storage_type) + + Registers a key with the TPM. The storage_type can be either + `TPM_Storage_Type::User` or `TPM_Storage_Type::System`. If System, the + key is stored on the TPM itself. If User, it is stored on the local hard + drive in a database maintained by an intermediate piece of system + software (which actual interacts with the physical TPM on behalf of any + number of applications calling the TPM API). + + The TPM has only some limited space to store private keys and may reject + requests to store the key. + + In either case the key is encrypted with an RSA key which was generated + on the TPM and which it will not allow to be exported. Thus (so goes the + theory) without physically attacking the TPM + + Returns a UUID which can be passed back to constructor below. + + .. cpp:function:: TPM_PrivateKey(TPM_Context& ctx, const std::string& uuid, \ + TPM_Storage_Type storage_type) + + Load a registered key. The UUID was returned by the ``register_key`` function. + + .. cpp:function:: std::vector<uint8_t> export_blob() const + + Export the key as an encrypted blob. This blob can later be presented + back to the same TPM to load the key. + + .. cpp:function:: TPM_PrivateKey(TPM_Context& ctx, const std::vector<uint8_t>& blob) + + Load a TPM key previously exported as a blob with ``export_blob``. + + .. cpp:function:: std::unique_ptr<Public_Key> public_key() const + + Return the public key associated with this TPM private key. + + TPM does not store public keys, nor does it support signature verification. + + .. cpp:function:: TSS_HKEY handle() const + + Returns the bare TSS key handle. Use if you need to call the raw TSS API. + +A ``TPM_PrivateKey`` can be passed to a ``PK_Signer`` constructor and used to +sign messages just like any other key. Only PKCS #1 v1.5 signatures are supported +by the v1.2 TPM. + +.. cpp:function:: std::vector<std::string> TPM_PrivateKey::registered_keys(TPM_Context& ctx) + + This static function returns the list of all keys (in URL format) + registered with the system diff --git a/doc/api_ref/tss.rst b/doc/api_ref/tss.rst new file mode 100644 index 000000000..947b835d0 --- /dev/null +++ b/doc/api_ref/tss.rst @@ -0,0 +1,45 @@ +Threshold Secret Sharing +======================================== + +.. versionadded:: 1.9.1 + +Threshold secret sharing allows splitting a secret into ``N`` shares such that +``M`` (for specified ``M`` <= ``N``) is sufficient to recover the secret, but an +attacker with ``M - 1`` shares cannot derive any information about the secret. + +The implementation in Botan follows an expired Internet draft +"draft-mcgrew-tss-03". Several other implementations of this TSS format exist. + +.. cpp:class:: RTSS_Share + + .. cpp:function:: static std::vector<RTSS_Share> split(uint8_t M, uint8_t N, \ + const uint8_t secret[], uint16_t secret_len, \ + const std::vector<uint8_t>& identifier, \ + const std::string& hash_fn, \ + RandomNumberGenerator& rng) + + Split a secret. The identifier is an optional key identifier which may be + up to 16 bytes long. Shorter identifiers are padded with zeros. + + The hash function must be either "SHA-1", "SHA-256", or "None" to disable + the checksum. + + This will return a vector of length ``N``, any ``M`` of these shares is + sufficient to reconstruct the data. + + .. cpp:function:: static secure_vector<uint8_t> reconstruct(const std::vector<RTSS_Share>& shares) + + Given a sufficient number of shares, reconstruct a secret. + + .. cpp:function:: RTSS_Share(const uint8_t data[], size_t len) + + Read a TSS share as a sequence of bytes. + + .. cpp:function:: const secure_vector<uint8>& data() const + + Return the data of this share. + + .. cpp:function:: uint8_t share_id() const + + Return the share ID which will be in the range 1...255 + diff --git a/doc/api_ref/versions.rst b/doc/api_ref/versions.rst new file mode 100644 index 000000000..511141b75 --- /dev/null +++ b/doc/api_ref/versions.rst @@ -0,0 +1,100 @@ + +Versioning +======================================== + +All versions are of the tuple (major,minor,patch). + +As of Botan 2.0.0, Botan uses semantic versioning. The minor number increases if +any feature addition is made. The patch version is used to indicate a release +where only bug fixes were applied. If an incompatible API change is required, +the major version will be increased. + +The library has functions for checking compile-time and runtime versions. + +The build-time version information is defined in `botan/build.h` + +.. c:macro:: BOTAN_VERSION_MAJOR + + The major version of the release. + +.. c:macro:: BOTAN_VERSION_MINOR + + The minor version of the release. + +.. c:macro:: BOTAN_VERSION_PATCH + + The patch version of the release. + +.. c:macro:: BOTAN_VERSION_DATESTAMP + + Expands to an integer of the form YYYYMMDD if this is an official + release, or 0 otherwise. For instance, 1.10.1, which was released + on July 11, 2011, has a `BOTAN_VERSION_DATESTAMP` of 20110711. + +.. c:macro:: BOTAN_DISTRIBUTION_INFO + + .. versionadded:: 1.9.3 + + A macro expanding to a string that is set at build time using the + ``--distribution-info`` option. It allows a packager of the library + to specify any distribution-specific patches. If no value is given + at build time, the value is the string "unspecified". + +.. c:macro:: BOTAN_VERSION_VC_REVISION + + .. versionadded:: 1.10.1 + + A macro expanding to a string that is set to a revision identifier + corresponding to the source, or "unknown" if this could not be + determined. It is set for all official releases, and for builds that + originated from within a git checkout. + +The runtime version information, and some helpers for compile time +version checks, are included in `botan/version.h` + +.. cpp:function:: std::string version_string() + + Returns a single-line string containing relevant information about + this build and version of the library in an unspecified format. + +.. cpp:function:: uint32_t version_major() + + Returns the major part of the version. + +.. cpp:function:: uint32_t version_minor() + + Returns the minor part of the version. + +.. cpp:function:: uint32_t version_patch() + + Returns the patch part of the version. + +.. cpp:function:: uint32_t version_datestamp() + + Return the datestamp of the release (or 0 if the current version is + not an official release). + +.. cpp:function:: std::string runtime_version_check(uint32_t major, uint32_t minor, uint32_t patch) + + Call this function with the compile-time version being built against, eg:: + + Botan::runtime_version_check(BOTAN_VERSION_MAJOR, BOTAN_VERSION_MINOR, BOTAN_VERSION_PATCH) + + It will return an empty string if the versions match, or otherwise + an error message indicating the discrepancy. This only is useful in + dynamic libraries, where it is possible to compile and run against + different versions. + +.. c:macro:: BOTAN_VERSION_CODE_FOR(maj,min,patch) + + Return a value that can be used to compare versions. The current + (compile-time) version is available as the macro + `BOTAN_VERSION_CODE`. For instance, to choose one code path for + version 2.1.0 and later, and another code path for older releases:: + + #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(2,1,0) + // 2.1+ code path + #else + // code path for older versions + #endif + diff --git a/doc/api_ref/x509.rst b/doc/api_ref/x509.rst new file mode 100644 index 000000000..fac9ae838 --- /dev/null +++ b/doc/api_ref/x509.rst @@ -0,0 +1,906 @@ +.. _x509_certificates: + +X.509 Certificates and CRLs +================================= + +A certificate is a binding between some identifying information +(called a *subject*) and a public key. This binding is asserted by a +signature on the certificate, which is placed there by some authority +(the *issuer*) that at least claims that it knows the subject named in +the certificate really "owns" the private key corresponding to the +public key in the certificate. + +The major certificate format in use today is X.509v3, used for instance in the +:doc:`tls` protocol. A X.509 certificate is represented by the class +``X509_Certificate``. The data of an X.509 certificate is stored as a +``shared_ptr`` to a structure containing the decoded information. So copying +``X509_Certificate`` objects is quite cheap. + + +.. cpp:class:: X509_Certificate + + .. cpp:function:: X509_Certificate(const std::string& filename) + + Load a certificate from a file. PEM or DER is accepted. + + .. cpp:function:: X509_Certificate(const std::vector<uint8_t>& in) + + Load a certificate from a byte string. + + .. cpp:function:: X509_Certificate(DataSource& source) + + Load a certificate from an abstract ``DataSource``. + + .. cpp:function:: X509_DN subject_dn() const + + Returns the distinguished name (DN) of the certificate's subject. This is + the primary place where information about the subject of the certificate is + stored. However "modern" information that doesn't fit in the X.500 + framework, such as DNS name, email, IP address, or XMPP address, appears + instead in the subject alternative name. + + .. cpp:function:: X509_DN issuer_dn() const + + Returns the distinguished name (DN) of the certificate's issuer, ie the CA + that issued this certificate. + + .. cpp:function:: const AlternativeName& subject_alt_name() const + + Return the subjects alternative name. This is used to store + values like associated URIs, DNS addresses, and email addresses. + + .. cpp:function:: const AlternativeName& issuer_alt_name() const + + Return alternative names for the issuer. + + .. cpp:function:: std::unique_ptr<Public_Key> load_subject_public_key() const + + Deserialize the stored public key and return a new object. This + might throw, if it happens that the public key object stored in + the certificate is malformed in some way, or in the case that the + public key algorithm used is not supported by the library. + + See :ref:`serializing_public_keys` for more information about what to do + with the returned object. It may be any type of key, in principle, though + RSA and ECDSA are most common. + + .. cpp:function:: std::vector<uint8_t> subject_public_key_bits() const + + Return the binary encoding of the subject public key. This value (or a hash of + it) is used in various protocols, eg for public key pinning. + + .. cpp:function:: AlgorithmIdentifier subject_public_key_algo() const + + Return an algorithm identifier that identifies the algorithm used in the + subject's public key. + + .. cpp:function:: std::vector<uint8_t> serial_number() const + + Return the certificates serial number. The tuple of issuer DN and + serial number should be unique. + + .. cpp:function:: std::vector<uint8> raw_subject_dn() const + + Return the binary encoding of the subject DN. + + .. cpp:function:: std::vector<uint8> raw_issuer_dn() const + + Return the binary encoding of the issuer DN. + + .. cpp:function:: X509_Time not_before() const + + Returns the point in time the certificate becomes valid + + .. cpp:function:: X509_Time not_after() const + + Returns the point in time the certificate expires + + .. cpp:function:: const Extensions& v3_extensions() const + + Returns all extensions of this certificate. You can use this + to examine any extension data associated with the certificate, + including custom extensions the library doesn't know about. + + .. cpp:function:: std::vector<uint8_t> authority_key_id() const + + Return the authority key id, if set. This is an arbitrary string; in the + issuing certificate this will be the subject key id. + + .. cpp:function:: std::vector<uint8_t> subject_key_id() const + + Return the subject key id, if set. + + .. cpp:function:: bool allowed_extended_usage(const OID& usage) const + + Return true if and only if the usage OID appears in the extended key usage + extension. Also will return true if the extended key usage extension is + not used in the current certificate. + + .. cpp:function: std::vector<OID> extended_key_usage() const + + Return the list of extended key usages. May be empty. + + .. cpp:function:: std::string fingerprint(const std::string& hash_fn = "SHA-1") const + + Return a fingerprint for the certificate, which is basically just a hash + of the binary contents. Normally SHA-1 or SHA-256 is used, but any hash + function is allowed. + + .. cpp:function:: Key_Constraints constraints() const + + Returns either an enumeration listing key constraints (what the + associated key can be used for) or ``NO_CONSTRAINTS`` if the + relevant extension was not included. Example values are + ``DIGITAL_SIGNATURE`` and ``KEY_CERT_SIGN``. More than one value + might be specified. + + .. cpp:function:: bool matches_dns_name(const std::string& name) const + + Check if the certificate's subject alternative name DNS fields + match ``name``. This function also handles wildcard certificates. + + .. cpp:function:: std::string to_string() const + + Returns a free-form human readable string describing the certificate. + +X.509 Distinguished Names +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. cpp:class:: X509_DN + + .. cpp:function:: bool has_field(const std::string& attr) const + + Returns true if ``get_attribute`` or ``get_first_attribute`` will return a value. + + .. cpp:function:: std::vector<std::string> get_attribute(const std::string& attr) const + + Return all attributes associated with a certain attribute type. + + .. cpp:function:: std::string get_first_attribute(const std::string& attr) const + + Like ``get_attribute`` but returns just the first attribute, or + empty if the DN has no attribute of the specified type. + + .. cpp:function:: std::multimap<OID, std::string> get_attributes() const + + Get all attributes of the DN. The OID maps to a DN component such as + 2.5.4.10 ("Organization"), and the strings are UTF-8 encoded. + + .. cpp:function:: std::multimap<std::string, std::string> contents() const + + Similar to ``get_attributes``, but the OIDs are decoded to strings. + + .. cpp:function:: void add_attribute(const std::string& key, const std::string& val) + + Add an attribute to a DN. + + .. cpp:function:: void add_attribute(const OID& oid, const std::string& val) + + Add an attribute to a DN using an OID instead of string-valued attribute type. + +The ``X509_DN`` type also supports iostream extraction and insertion operators, +for formatted input and output. + +X.509v3 Extensions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +X.509v3 specifies a large number of possible extensions. Botan supports some, +but by no means all of them. The following listing lists which X.509v3 +extensions are supported and notes areas where there may be problems with the +handling. + + - Key Usage and Extended Key Usage: No problems known. + + - Basic Constraints: No problems known. A self-signed v1 certificate + is assumed to be a CA, while a v3 certificate is marked as a CA if + and only if the basic constraints extension is present and set for + a CA cert. + + - Subject Alternative Names: Only the "rfc822Name", "dNSName", and + "uniformResourceIdentifier" and raw IPv4 fields will be stored; all + others are ignored. + + - Issuer Alternative Names: Same restrictions as the Subject + Alternative Names extension. New certificates generated by Botan + never include the issuer alternative name. + + - Authority Key Identifier: Only the version using KeyIdentifier is + supported. If the GeneralNames version is used and the extension is + critical, an exception is thrown. If both the KeyIdentifier and GeneralNames + versions are present, then the KeyIdentifier will be used, and the + GeneralNames ignored. + + - Subject Key Identifier: No problems known. + + - Name Constraints: No problems known (though encoding is not supported). + +Any unknown critical extension in a certificate will lead to an +exception during path validation. + +Extensions are handled by a special class taking care of encoding +and decoding. It also supports encoding and decoding of custom extensions. +To do this, it internally keeps two lists of extensions. Different lookup +functions are provided to search them. + +.. note:: + + Validation of custom extensions during path validation is currently not supported. + +.. cpp:class:: Extensions + + .. cpp:function:: void add(Certificate_Extension* extn, bool critical = false) + + Adds a new extension to the extensions object. If an extension of the same + type already exists, ``extn`` will replace it. If ``critical`` is true the + extension will be marked as critical in the encoding. + + .. cpp:function:: bool add_new(Certificate_Extension* extn, bool critical = false) + + Like ``add`` but an existing extension will not be replaced. Returns true if the + extension was used, false if an extension of the same type was already in place. + + .. cpp:function:: void replace(Certificate_Extension* extn, bool critical = false) + + Adds an extension to the list or replaces it, if the same + extension was already added + + .. cpp:function:: std::unique_ptr<Certificate_Extension> get(const OID& oid) const + + Searches for an extension by OID and returns the result + + .. cpp:function:: template<typename T> \ + std::unique_ptr<T> get_raw(const OID& oid) + + Searches for an extension by OID and returns the result. + Only the unknown extensions, that is, extensions types that are not + listed above, are searched for by this function. + + .. cpp:function:: std::vector<std::pair<std::unique_ptr<Certificate_Extension>, bool>> extensions() const + + Returns the list of extensions together with the corresponding + criticality flag. Only contains the supported extension types + listed above. + + .. cpp:function:: std::map<OID, std::pair<std::vector<uint8_t>, bool>> extensions_raw() const + + Returns the list of extensions as raw, encoded bytes + together with the corresponding criticality flag. + Contains all extensions, known as well as unknown extensions. + +Certificate Revocation Lists +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It will occasionally happen that a certificate must be revoked before +its expiration date. Examples of this happening include the private +key being compromised, or the user to which it has been assigned +leaving an organization. Certificate revocation lists are an answer to +this problem (though online certificate validation techniques are +starting to become somewhat more popular). Every once in a while the +CA will release a new CRL, listing all certificates that have been +revoked. Also included is various pieces of information like what time +a particular certificate was revoked, and for what reason. In most +systems, it is wise to support some form of certificate revocation, +and CRLs handle this easily. + +For most users, processing a CRL is quite easy. All you have to do is +call the constructor, which will take a filename (or a +``DataSource&``). The CRLs can either be in raw BER/DER, or in PEM +format; the constructor will figure out which format without any extra +information. For example:: + + X509_CRL crl1("crl1.der"); + + DataSource_Stream in("crl2.pem"); + X509_CRL crl2(in); + +After that, pass the ``X509_CRL`` object to a ``Certificate_Store`` object +with + +.. cpp:function:: void Certificate_Store::add_crl(const X509_CRL& crl) + +and all future verifications will take into account the provided CRL. + +Certificate Stores +---------------------------------------- + +An object of type ``Certificate_Store`` is a generalized interface to +an external source for certificates (and CRLs). Examples of such a +store would be one that looked up the certificates in a SQL database, +or by contacting a CGI script running on a HTTP server. There are +currently three mechanisms for looking up a certificate, and one for +retrieving CRLs. By default, most of these mechanisms will return an +empty ``std::shared_ptr`` of ``X509_Certificate``. This storage mechanism +is *only* queried when doing certificate validation: it allows you to +distribute only the root key with an application, and let some online +method handle getting all the other certificates that are needed to +validate an end entity certificate. In particular, the search routines +will not attempt to access the external database. + +The certificate lookup methods are ``find_cert`` (by Subject +Distinguished Name and optional Subject Key Identifier) and +``find_cert_by_pubkey_sha1`` (by SHA-1 hash of the certificate's +public key). The Subject Distinguished Name is given as a ``X509_DN``, +while the SKID parameter takes a ``std::vector<uint8_t>`` containing +the subject key identifier in raw binary. Both lookup methods are +mandatory to implement. + +Finally, there is a method for finding a CRL, called ``find_crl_for``, +that takes an ``X509_Certificate`` object, and returns a +``std::shared_ptr`` of ``X509_CRL``. The ``std::shared_ptr`` return +type makes it easy to return no CRLs by returning ``nullptr`` +(eg, if the certificate store doesn't support retrieving CRLs). +Implementing the function is optional, and by default will return +``nullptr``. + +Certificate stores are used in the :doc:`tls` module to store a +list of trusted certificate authorities. + +In Memory Certificate Store +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The in memory certificate store keeps all objects in memory only. +Certificates can be loaded from disk initially, but also added +later. + +.. cpp:class:: Certificate_Store_In_Memory + + .. cpp:function:: Certificate_Store_In_Memory(const std::string& dir) + + Attempt to parse all files in ``dir`` (including subdirectories) + as certificates. Ignores errors. + + .. cpp:function:: Certificate_Store_In_Memory(const X509_Certificate& cert) + + Adds given certificate to the store + + .. cpp:function:: Certificate_Store_In_Memory() + + Create an empty store + + .. cpp:function:: void add_certificate(const X509_Certificate& cert) + + Add a certificate to the store + + .. cpp:function:: void add_certificate(std::shared_ptr<const X509_Certificate> cert) + + Add a certificate already in a shared_ptr to the store + + .. cpp:function:: void add_crl(const X509_CRL& crl) + + Add a certificate revocation list (CRL) to the store. + + .. cpp:function:: void add_crl(std::shared_ptr<const X509_CRL> crl) + + Add a certificate revocation list (CRL) to the store as a shared_ptr + +SQL-backed Certificate Stores +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The SQL-backed certificate stores store all objects in an SQL database. They +also additionally provide private key storage and revocation of individual +certificates. + +.. cpp:class:: Certificate_Store_In_SQL + + .. cpp:function:: Certificate_Store_In_SQL(const std::shared_ptr<SQL_Database> db, \ + const std::string& passwd, RandomNumberGenerator& rng, const std::string& table_prefix = "") + + Create or open an existing certificate store from an SQL database. + The password in ``passwd`` will be used to encrypt private keys. + + .. cpp:function:: bool insert_cert(const X509_Certificate& cert) + + Inserts ``cert`` into the store. Returns `false` if the certificate is + already known and `true` if insertion was successful. + + .. cpp:function:: remove_cert(const X509_Certificate& cert) + + Removes ``cert`` from the store. Returns `false` if the certificate could not + be found and `true` if removal was successful. + + .. cpp:function:: std::shared_ptr<const Private_Key> find_key(const X509_Certificate&) const + + Returns the private key for "cert" or an empty shared_ptr if none was found + + .. cpp:function:: std::vector<std::shared_ptr<const X509_Certificate>> \ + find_certs_for_key(const Private_Key& key) const + + Returns all certificates for private key ``key`` + + .. cpp:function:: bool insert_key(const X509_Certificate& cert, const Private_Key& key) + + Inserts ``key`` for ``cert`` into the store, returns `false` if the key is + already known and `true` if insertion was successful. + + .. cpp:function:: void remove_key(const Private_Key& key) + + Removes ``key`` from the store + + .. cpp:function:: void revoke_cert(const X509_Certificate&, CRL_Code, \ + const X509_Time& time = X509_Time()) + + Marks ``cert`` as revoked starting from ``time`` + + .. cpp:function:: void affirm_cert(const X509_Certificate&) + + Reverses the revocation for ``cert`` + + .. cpp:function:: std::vector<X509_CRL> generate_crls() const + + Generates CRLs for all certificates marked as revoked. + A CRL is returned for each unique issuer DN. + +The ``Certificate_Store_In_SQL`` class operates on an abstract ``SQL_Database`` +object. If support for sqlite3 was enabled at build time, Botan includes an +implementation of this interface for sqlite3, and a subclass of +``Certificate_Store_In_SQL`` which creates or opens a sqlite3 database. + +.. cpp:class:: Certificate_Store_In_SQLite + + .. cpp:function:: Certificate_Store_In_SQLite(const std::string& db_path, \ + const std::string& passwd, RandomNumberGenerator& rng, const std::string& table_prefix = "") + + Create or open an existing certificate store from an sqlite database file. + The password in ``passwd`` will be used to encrypt private keys. + +Path Validation +---------------------------------------- + +The process of validating a certificate chain up to a trusted root is +called `path validation`, and in botan that operation is handled by a +set of functions in ``x509path.h`` named ``x509_path_validate``: + +.. cpp:function:: Path_Validation_Result \ + x509_path_validate(const X509_Certificate& end_cert, \ + const Path_Validation_Restrictions& restrictions, \ + const Certificate_Store& store, const std::string& hostname = "", \ + Usage_Type usage = Usage_Type::UNSPECIFIED, \ + std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(), \ + std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0), \ + const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp = std::vector<std::shared_ptr<const OCSP::Response>>()) + + The last five parameters are optional. ``hostname`` specifies a hostname which is + matched against the subject DN in ``end_cert`` according to RFC 6125. + An empty hostname disables hostname validation. + ``usage`` specifies key usage restrictions that are compared + to the key usage fields in `end_cert` according to RFC 5280, if not set to + ``UNSPECIFIED``. ``validation_time`` allows setting the time point at which all certificates + are validated. This is really only useful for testing. The default is the + current system clock's current time. ``ocsp_timeout`` sets the timeout for + OCSP requests. The default of 0 disables OCSP checks completely. + ``ocsp_resp`` allows adding additional OCSP responses retrieved from outside + of the path validation. Note that OCSP online checks are done only + as long as the http_util module was compiled in. Availability of online + OCSP checks can be checked using the macro BOTAN_HAS_ONLINE_REVOCATION_CHECKS. + + For the different flavors of ``x509_path_validate``, check ``x509path.h``. + +The result of the validation is returned as a class: + +.. cpp:class:: Path_Validation_Result + + Specifies the result of the validation + + .. cpp:function:: bool successful_validation() const + + Returns true if a certificate path from *end_cert* to a trusted + root was found and all path validation checks passed. + + .. cpp:function:: std::string result_string() const + + Returns a descriptive string of the validation status (for + instance "Verified", "Certificate is not yet valid", or + "Signature error"). This is the string value of + the `result` function below. + + .. cpp:function:: const X509_Certificate& trust_root() const + + If the validation was successful, returns the certificate which + is acting as the trust root for *end_cert*. + + .. cpp:function:: const std::vector<X509_Certificate>& cert_path() const + + Returns the full certificate path starting with the end entity + certificate and ending in the trust root. + + .. cpp:function:: Certificate_Status_Code result() const + + Returns the 'worst' error that occurred during validation. For + instance, we do not want an expired certificate with an invalid + signature to be reported to the user as being simply expired (a + relatively innocuous and common error) when the signature isn't + even valid. + + .. cpp:function:: const std::vector<std::set<Certificate_Status_Code>>& all_statuses() const + + For each certificate in the chain, returns a set of status which + indicate all errors which occurred during validation. This is + primarily useful for diagnostic purposes. + + .. cpp:function:: std::set<std::string> trusted_hashes() const + + Returns the set of all cryptographic hash functions which are + implicitly trusted for this validation to be correct. + + +A ``Path_Validation_Restrictions`` is passed to the path +validator and specifies restrictions and options for the validation +step. The two constructors are: + + .. cpp:function:: Path_Validation_Restrictions(bool require_rev, \ + size_t minimum_key_strength, \ + bool ocsp_all_intermediates, \ + const std::set<std::string>& trusted_hashes) + + If `require_rev` is true, then any path without revocation + information (CRL or OCSP check) is rejected with the code + `NO_REVOCATION_DATA`. The `minimum_key_strength` parameter + specifies the minimum strength of public key signature we will + accept is. The set of hash names `trusted_hashes` indicates which + hash functions we'll accept for cryptographic signatures. Any + untrusted hash will cause the error case `UNTRUSTED_HASH`. + + .. cpp:function:: Path_Validation_Restrictions(bool require_rev = false, \ + size_t minimum_key_strength = 80, \ + bool ocsp_all_intermediates = false) + + A variant of the above with some convenient defaults. The current + default `minimum_key_strength` of 80 roughly corresponds to 1024 + bit RSA. The set of trusted hashes is set to all SHA-2 variants, + and, if `minimum_key_strength` is less than or equal to 80, then + SHA-1 signatures will also be accepted. + +Creating New Certificates +--------------------------------- + +A CA is represented by the type ``X509_CA``, which can be found in +``x509_ca.h``. A CA always needs its own certificate, which can either +be a self-signed certificate (see below on how to create one) or one +issued by another CA (see the section on PKCS #10 requests). Creating +a CA object is done by the following constructor: + +.. cpp:function:: X509_CA::X509_CA(const X509_Certificate& cert, \ + const Private_Key& key, \ + const std::string& hash_fn, \ + RandomNumberGenerator& rng) + +The private ``key`` is the private key corresponding to the public key in the +CA's certificate. ``hash_fn`` is the name of the hash function to use +for signing, e.g., `SHA-256`. ``rng`` is queried for random during signing. + +There is an alternative constructor that lets you set additional options, namely +the padding scheme that will be used by the X509_CA object to sign certificates +and certificate revocation lists. If the padding is not set explicitly, the CA +will use the padding scheme that was used when signing the CA certificate. + +.. cpp:function:: X509_CA::X509_CA(const X509_Certificate& cert, \ + const Private_Key& key, \ + const std::map<std::string,std::string>& opts, \ + const std::string& hash_fn, \ + RandomNumberGenerator& rng) + +The only option valid at this moment is "padding". The supported padding schemes +can be found in src/lib/pubkey/padding.cpp. Some alternative names for the +padding schemes are understood, as well. + +Requests for new certificates are supplied to a CA in the form of PKCS +#10 certificate requests (called a ``PKCS10_Request`` object in +Botan). These are decoded in a similar manner to +certificates/CRLs/etc. A request is vetted by humans (who somehow +verify that the name in the request corresponds to the name of the +entity who requested it), and then signed by a CA key, generating a +new certificate: + +.. cpp:function:: X509_Certificate \ + X509_CA::sign_request(const PKCS10_Request& req, \ + RandomNumberGenerator& rng, \ + const X509_Time& not_before, \ + const X509_Time& not_after) + +Generating CRLs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As mentioned previously, the ability to process CRLs is highly +important in many PKI systems. In fact, according to strict X.509 +rules, you must not validate any certificate if the appropriate CRLs +are not available (though hardly any systems are that strict). In any +case, a CA should have a valid CRL available at all times. + +Of course, you might be wondering what to do if no certificates have +been revoked. Never fear; empty CRLs, which revoke nothing at all, can +be issued. To generate a new, empty CRL, just call + +.. cpp:function:: X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng, \ + uint32_t next_update = 0) + + This function will return a new, empty CRL. The ``next_update`` parameter is + the number of seconds before the CRL expires. If it is set to the (default) + value of zero, then a reasonable default (currently 7 days) will be used. + +On the other hand, you may have issued a CRL before. In that case, you will +want to issue a new CRL that contains all previously revoked +certificates, along with any new ones. This is done by calling + +.. cpp:function:: X509_CRL X509_CA::update_crl(const X509_CRL& last_crl, \ + std::vector<CRL_Entry> new_entries, RandomNumberGenerator& rng, \ + size_t next_update = 0) + + Where ``last_crl`` is the last CRL this CA issued, and + ``new_entries`` is a list of any newly revoked certificates. The + function returns a new ``X509_CRL`` to make available for + clients. + +The ``CRL_Entry`` type is a structure that contains, at a minimum, the serial +number of the revoked certificate. As serial numbers are never repeated, the +pairing of an issuer and a serial number (should) distinctly identify any +certificate. In this case, we represent the serial number as a +``secure_vector<uint8_t>`` called ``serial``. There are two additional (optional) +values, an enumeration called ``CRL_Code`` that specifies the reason for +revocation (``reason``), and an object that represents the time that the +certificate became invalid (if this information is known). + +If you wish to remove an old entry from the CRL, insert a new entry for the +same cert, with a ``reason`` code of ``REMOVE_FROM_CRL``. For example, if a +revoked certificate has expired 'normally', there is no reason to continue to +explicitly revoke it, since clients will reject the cert as expired in any +case. + +Self-Signed Certificates +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Generating a new self-signed certificate can often be useful, for +example when setting up a new root CA, or for use in specialized +protocols. The library provides a utility function for this: + +.. cpp:function:: X509_Certificate create_self_signed_cert( \ + const X509_Cert_Options& opts, const Private_Key& key, \ + const std::string& hash_fn, RandomNumberGenerator& rng) + + Where ``key`` is the private key you wish to use (the public key, + used in the certificate itself is extracted from the private key), + and ``opts`` is an structure that has various bits of information + that will be used in creating the certificate (this structure, and + its use, is discussed below). + +Creating PKCS #10 Requests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Also in ``x509self.h``, there is a function for generating new PKCS #10 +certificate requests: + +.. cpp:function:: PKCS10_Request create_cert_req( \ + const X509_Cert_Options& opts, const Private_Key& key, \ + const std::string& hash_fn, RandomNumberGenerator& rng) + +This function acts quite similarly to +:cpp:func:`create_self_signed_cert`, except it instead returns a PKCS +#10 certificate request. After creating it, one would typically +transmit it to a CA, who signs it and returns a freshly minted X.509 +certificate. + +.. cpp:function:: PKCS10_Request PKCS10_Request::create(const Private_Key& key, \ + const X509_DN& subject_dn, \ + const Extensions& extensions, \ + const std::string& hash_fn, \ + RandomNumberGenerator& rng, \ + const std::string& padding_scheme = "", \ + const std::string& challenge = "") + + This function (added in 2.5) is similar to ``create_cert_req`` but allows + specifying all the parameters directly. In fact ``create_cert_req`` just + creates the DN and extensions from the options, then uses this call to + actually create the ``PKCS10_Request`` object. + + +Certificate Options +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +What is this ``X509_Cert_Options`` thing we've been passing around? +It's a class representing a bunch of information that will end up +being stored into the certificate. This information comes in 3 major +flavors: information about the subject (CA or end-user), the validity +period of the certificate, and restrictions on the usage of the +certificate. For special cases, you can also add custom X.509v3 +extensions. + +First and foremost is a number of ``std::string`` members, which +contains various bits of information about the user: ``common_name``, +``serial_number``, ``country``, ``organization``, ``org_unit``, +``locality``, ``state``, ``email``, ``dns_name``, and ``uri``. As many +of these as possible should be filled it (especially an email +address), though the only required ones are ``common_name`` and +``country``. + +Additionally there are a small selection of ``std::vector<std::string>`` +members, which allow space for repeating elements: +``more_org_units`` and ``more_dns``. + +There is another value that is only useful when creating a PKCS #10 +request, which is called ``challenge``. This is a challenge password, +which you can later use to request certificate revocation (*if* the CA +supports doing revocations in this manner). + +Then there is the validity period; these are set with ``not_before`` +and ``not_after``. Both of these functions also take a +``std::string``, which specifies when the certificate should start +being valid, and when it should stop being valid. If you don't set the +starting validity period, it will automatically choose the current +time. If you don't set the ending time, it will choose the starting +time plus a default time period. The arguments to these functions +specify the time in the following format: "2002/11/27 1:50:14". The +time is in 24-hour format, and the date is encoded as +year/month/day. The date must be specified, but you can omit the time +or trailing parts of it, for example "2002/11/27 1:50" or +"2002/11/27". + +Third, you can set constraints on a key. The one you're mostly likely +to want to use is to create (or request) a CA certificate, which can +be done by calling the member function ``CA_key``. This should only be +used when needed. + +Moreover, you can specify the padding scheme to be used when digital signatures +are computed by calling function ``set_padding_scheme`` with a string +representing the padding scheme. This way, you can control the padding scheme +for self-signed certificates and PKCS #10 requests. The padding scheme used by +a CA when building a certificate or a certificate revocation list can be set in +the ``X509_CA`` constructor. The supported padding schemes can be found in +src/lib/pubkey/padding.cpp. Some alternative names for the padding schemes are +understood, as well. + +Other constraints can be set by calling the member functions +``add_constraints`` and ``add_ex_constraints``. The first takes a +``Key_Constraints`` value, and replaces any previously set value. If +no value is set, then the certificate key is marked as being valid for +any usage. You can set it to any of the following (for more than one +usage, OR them together): ``DIGITAL_SIGNATURE``, ``NON_REPUDIATION``, +``KEY_ENCIPHERMENT``, ``DATA_ENCIPHERMENT``, ``KEY_AGREEMENT``, +``KEY_CERT_SIGN``, ``CRL_SIGN``, ``ENCIPHER_ONLY``, +``DECIPHER_ONLY``. Many of these have quite special semantics, so you +should either consult the appropriate standards document (such as RFC +5280), or just not call ``add_constraints``, in which case the +appropriate values will be chosen for you. + +The second function, ``add_ex_constraints``, allows you to specify an +OID that has some meaning with regards to restricting the key to +particular usages. You can, if you wish, specify any OID you like, but +there is a set of standard ones that other applications will be able +to understand. These are the ones specified by the PKIX standard, and +are named "PKIX.ServerAuth" (for TLS server authentication), +"PKIX.ClientAuth" (for TLS client authentication), "PKIX.CodeSigning", +"PKIX.EmailProtection" (most likely for use with S/MIME), +"PKIX.IPsecUser", "PKIX.IPsecTunnel", "PKIX.IPsecEndSystem", and +"PKIX.TimeStamping". You can call "add_ex_constraints" any number of +times - each new OID will be added to the list to include in the +certificate. + +Lastly, you can add any X.509v3 extensions in the `extensions` member, which is +useful if you want to encode a custom extension, or encode an extension in a way +differently from how Botan defaults. + +OCSP Requests +---------------------------------------- + +A client makes an OCSP request to what is termed an 'OCSP responder'. This +responder returns a signed response attesting that the certificate in question +has not been revoked. The most recent OCSP specification is as of this +writing :rfc:`6960`. + +Normally OCSP validation happens automatically as part of X.509 certificate +validation, as long as OCSP is enabled (by setting a non-zero ``ocsp_timeout`` +in the call to ``x509_path_validate``, or for TLS by implementing the related +``tls_verify_cert_chain_ocsp_timeout`` callback and returning a non-zero value +from that). So most applications should not need to directly manipulate OCSP +request and response objects. + +For those that do, the primary ocsp interface is in ``ocsp.h``. First a request +must be formed, using information contained in the subject certificate and in +the subject's issuing certificate. + +.. cpp:class:: OCSP::Request + + .. cpp:function:: OCSP::Request(const X509_Certificate& issuer_cert, \ + const BigInt& subject_serial) + + Create a new OCSP request + + .. cpp:function:: OCSP::Request(const X509_Certificate& issuer_cert, \ + const X509_Certificate& subject_cert) + + Variant of the above, using serial number from ``subject_cert``. + + .. cpp:function:: std::vector<uint8_t> BER_encode() const + + Encode the current OCSP request as a binary string. + + .. cpp:function:: std::string base64_encode() const + + Encode the current OCSP request as a base64 string. + +Then the response is parsed and validated, and if valid, can be consulted +for certificate status information. + +.. cpp:class:: OCSP::Response + + .. cpp:function:: OCSP::Response(const uint8_t response_bits[], size_t response_bits_len) + + Attempts to parse ``response_bits`` as an OCSP response. Throws an + exception if parsing fails. Note that this does not verify that the OCSP + response is valid (ie that the signature is correct), merely that the + ASN.1 structure matches an OCSP response. + + .. cpp:function:: Certificate_Status_Code check_signature( \ + const std::vector<Certificate_Store*>& trust_roots, \ + const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path = const std::vector<std::shared<const X509_Certificate>>()) const + + Find the issuing certificate of the OCSP response, and check the signature. + + If possible, pass the full certificate path being validated in + the optional ``cert_path`` argument: this additional information + helps locate the OCSP signer's certificate in some cases. If this + does not return ``Certificate_Status_Code::OCSP_SIGNATURE_OK``, + then the request must not be be used further. + + .. cpp:function:: Certificate_Status_Code verify_signature(const X509_Certificate& issuing_cert) const + + If the certificate that issued the OCSP response is already known (eg, + because in some specific application all the OCSP responses will always + be signed by a single trusted issuer whose cert is baked into the code) + this provides an alternate version of `check_signature`. + + .. cpp:function:: Certificate_Status_Code status_for(const X509_Certificate& issuer, \ + const X509_Certificate& subject, \ + std::chrono::system_clock::time_point ref_time = std::chrono::system_clock::now()) const + + Assuming the signature is valid, returns the status for the subject certificate. + Make sure to get the ordering of the issuer and subject certificates correct. + + The ``ref_time`` is normally just the system clock, but can be used if + validation against some other reference time is desired (such as for + testing, to verify an old previously valid OCSP response, or to use an + alternate time source such as the Roughtime protocol instead of the local + client system clock). + + .. cpp:function:: const X509_Time& produced_at() const + + Return the time this OCSP response was (claimed to be) produced at. + + .. cpp:function:: const X509_DN& signer_name() const + + Return the distinguished name of the signer. This is used to help + find the issuing certificate. + + This field is optional in OCSP responses, and may not be set. + + .. cpp:function:: const std::vector<uint8_t>& signer_key_hash() const + + Return the SHA-1 hash of the public key of the signer. This is used to + help find the issuing certificate. The ``Certificate_Store`` API + ``find_cert_by_pubkey_sha1`` can search on this value. + + This field is optional in OCSP responses, and may not be set. + + .. cpp:function:: const std::vector<uint8_t>& raw_bits() const + + Return the entire raw ASN.1 blob (for debugging or specialized decoding needs) + +One common way of making OCSP requests is via HTTP, see :rfc:`2560` +Appendix A for details. A basic implementation of this is the function +``online_check``, which is available as long as the ``http_util`` module +was compiled in; check by testing for the macro ``BOTAN_HAS_HTTP_UTIL``. + +.. cpp:function:: OCSP::Response online_check(const X509_Certificate& issuer, \ + const BigInt& subject_serial, \ + const std::string& ocsp_responder, \ + const Certificate_Store* trusted_roots) + + Assemble a OCSP request for serial number ``subject_serial`` and attempt to request + it to responder at URI ``ocsp_responder`` over a new HTTP socket, parses and returns + the response. If trusted_roots is not null, then the response is additionally + validated using OCSP response API ``check_signature``. Otherwise, this call must be + performed later by the application. + +.. cpp:function:: OCSP::Response online_check(const X509_Certificate& issuer, \ + const X509_Certificate& subject, \ + const Certificate_Store* trusted_roots) + + Variant of the above but uses serial number and OCSP responder URI from ``subject``. |