Rewrote the server in cpp with the frontend in svelte

This commit is contained in:
2023-10-20 13:02:21 +02:00
commit 03b22ebb61
4168 changed files with 831370 additions and 0 deletions

View File

@@ -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``.

View File

@@ -0,0 +1,318 @@
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:: std::unique_ptr<BlockCipher> new_object() const
Return a newly allocated BlockCipher object of the same type as this one.
The new object is unkeyed.
.. 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.
.. literalinclude:: /../src/examples/aes.cpp
:language: cpp
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. If you are developing new code and have no particular
opinion, use AES-256. If you desire an alternative to AES, consider Serpent, SHACAL2 or
Threefish.
.. 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.
Camellia
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Comes in three variants, Camellia-128, Camellia-192, and Camellia-256.
A Japanese design standardized by ISO, NESSIE and CRYPTREC.
Rarely used outside of Japan.
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 and 3DES
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Originally designed by IBM and NSA in the 1970s. Today, DES's 56-bit key renders
it insecure to any well-resourced attacker. 3DES extends the key length,
and is 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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Aka "Magma". An old 64-bit Russian cipher. Possible security issues, avoid
unless compatibility is needed.
Available if ``BOTAN_HAS_GOST_28147_89`` is defined.
.. warning::
Support for this cipher is deprecated and will be removed in a future major release.
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.
Kuznyechik
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 3.2
Newer Russian national cipher, also known as GOST R 34.12-2015 or "Grasshopper".
.. warning::
The sbox of this cipher is supposedly random, but was found to have a
mathematical structure which is exceedingly unlikely to have occured by
chance. This may indicate the existence of a backdoor or other issue. Avoid
using this cipher unless strictly required.
Available if ``BOTAN_HAS_KUZNYECHIK`` 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.
Noekeon
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A fast 128-bit cipher by the designers of AES. Easily secured against side
channels. Quite obscure however.
Available if ``BOTAN_HAS_NOEKEON`` is defined.
.. warning::
Noekeon support is deprecated and will be removed in a future major release.
SEED
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A older South Korean cipher, widely used in industry there. No reason to choose it otherwise.
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
unless SIMD instructions are 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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A 128-bit block cipher that was one of the AES finalists. Has a somewhat complicated key
setup and a "kitchen sink" design.
Available if ``BOTAN_HAS_TWOFISH`` is defined.

View File

@@ -0,0 +1,377 @@
.. _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. Will return 1 if the mode implementation
does not require buffering.
.. cpp:function:: virtual size_t ideal_granularity() const
Returns a multiple of update_granularity sized for ideal performance.
In fact this is not truly the "ideal" buffer size but just reflects the
smallest possible buffer that can reasonably take advantage of available
parallelism (due to SIMD execution, etc). If you are concerned about
performance, it may be advisable to take this return value and scale it to
approximately 4 KB, and use buffers of that size.
.. 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`. This is used for
example when processing an AEAD message, to ensure the tag is available. In
that case, the encryption side will return 0 (since the tag is generated,
rather than being provided) while the decryption mode will return the size
of the tag.
.. 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.
.. literalinclude:: /../src/examples/aes_cbc.cpp
:language: cpp
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.
.. warning::
Using CBC with padding without an authentication mode exposes your
application to CBC padding oracle attacks, which allow recovering
the plaintext of arbitrary messages. Always pair CBC with a MAC such
as HMAC (or, preferably, use an AEAD such as GCM).
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`.
.. 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 until 2021 it was patented in the United States. The patent
was allowed to lapse in early 2021.
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.

View File

@@ -0,0 +1,97 @@
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
``Compression_Algorithm::create`` and
``Decompression_Algorithm::create`` which both accept a string
argument which can take values 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.
Two older functions for this are
.. cpp:function:: Compression_Algorithm* make_compressor(std::string type)
.. cpp:function:: Decompression_Algorithm* make_decompressor(std::string type)
which call the relevant ``create`` function and then ``release`` the
returned ``unique_ptr``. Avoid these in new code.
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.

View File

@@ -0,0 +1,41 @@
API Reference
===================
.. toctree::
:maxdepth: 1
footguns
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
roughtime
zfec
ffi
env_vars
python

View File

@@ -0,0 +1,197 @@
Credentials Manager
==================================================
A ``Credentials_Manager`` is a way to abstract how the application
stores credentials. The main user is the :doc:`tls` implementation.
.. cpp:class:: Credentials_Manager
.. cpp:function:: std::vector<Certificate_Store*> \
trusted_certificate_authorities( \
const std::string& type, \
const std::string& context)
Return the list of certificate stores, each of which is assumed
to contain (only) trusted certificate authorities. The
``Credentials_Manager`` retains ownership of the
Certificate_Store pointers.
.. note::
It would have been a better API to return a vector of
``shared_ptr`` here. This may change in a future major release.
When *type* is "tls-client", *context* will be the hostname of
the server, or empty if the hostname is not known. This allows
using a different set of certificate stores in different contexts,
for example using the system certificate store unless contacting
one particular server which uses a cert issued by an internal CA.
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.
.. warning::
If this function returns a certificate that is not one of the
types given in ``cert_key_types`` confusing handshake
failures will result.
.. 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*.
For servers *type* will be "tls-server" and the *context* will
be the server name that the client requested via SNI (or empty,
if the client did not send SNI).
.. warning::
To avoid cross-protocol attacks it is recommended that if a server
receives an SNI request for a name it does not expect, it should close
the connection with an alert. This can be done by throwing an exception
from the implementation of this function.
.. cpp:function:: std::shared_ptr<Private_Key> private_key_for(const X509_Certificate& cert, \
const std::string& type, \
const std::string& context)
Return a shared pointer to 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.
.. note::
Support for TLS-SRP is deprecated, and will be removed in a future
major release. When that occurs these APIs will be removed. Prefer
instead performing a standard TLS handshake, then perform a PAKE
authentication inside of (and cryptographically bound to) the TLS
channel.
.. 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 supports 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.
A similar special case exists for DTLS cookie verification. In
this case *type* will be "tls-server" and *context* is
"dtls-cookie-secret". If no key is returned, then DTLS cookies are
not used. Similar to the session ticket key, the DTLS cookie
secret can be chosen during server startup and rotated at any time
with no ill effect.
.. warning::
If DTLS cookies are not used then the server is prone to be
abused as a DoS amplifier, where the attacker sends a
relatively small client hello in a UDP packet with a forged
return address, and then the server replies to the victim with
several messages that are larger. This not only hides the
attackers address from the victim, but increases their
effective bandwidth. This is not an issue when using DTLS over
SCTP or TCP.
.. 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.

View File

@@ -0,0 +1,34 @@
Cryptobox
========================================
Encryption using a passphrase
----------------------------------------
.. versionadded:: 1.8.6
.. deprecated:: 3.0
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.

View File

@@ -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 EC_Point& 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 EC_Point& 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:: EC_Point 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:: EC_Point point_multiply(const BigInt& x, const EC_Point& pt, const BigInt& y) const
Multi-exponentiation. Returns base_point*x + pt*y. Not constant time.
(Ordinarily used for signature verification.)
.. cpp:function:: EC_Point 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:: EC_Point blinded_var_point_multiply(const EC_Point& 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:: EC_Point zero_point() const
Return the zero point (aka the point at infinity).
.. cpp:function:: EC_Point 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:: EC_Point
Stores elliptic curve points in Jacobian representation.
.. cpp:function:: std::vector<uint8_t> encode(EC_Point::Compression_Type format) const
Encode a point in a way that can later be decoded with `EC_Group::OS2ECP`.
.. cpp:function:: EC_Point& operator+=(const EC_Point& rhs)
Point addition.
.. cpp:function:: EC_Point& operator-=(const EC_Point& rhs)
Point subtraction.
.. cpp:function:: EC_Point& operator*=(const BigInt& scalar)
Point multiplication using Montgomery ladder.
.. warning::
Prefer the blinded functions in ``EC_Group``
.. cpp:function:: EC_Point& 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<EC_Point>& 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 EC_Point& other) const
Point equality. This compares the affine representations.
.. cpp:function:: void add(const EC_Point& other, std::vector<BigInt>& workspace)
Point addition, taking a workspace.
.. cpp:function:: void add_affine(const EC_Point& 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:: EC_Point plus(const EC_Point& other, std::vector<BigInt>& workspace) const
Point addition, returning the result.
.. cpp:function:: EC_Point double_of(std::vector<BigInt>& workspace) const
Point doubling, returning the result.
.. cpp:function:: EC_Point zero() const
Return the point at infinity

View File

@@ -0,0 +1,35 @@
.. _env_vars:
Environment Variables
======================
Certain environment variables can affect or tune the behavior of the
library. The variables and their behavior are described here.
* ``BOTAN_THREAD_POOL_SIZE`` controls the number of threads which will be
created for a thread pool used for some purposes within the library. If not
set, or set to 0, then it defaults to the number of CPUs available on the
system. If it is set to the string "none" then the thread pool is disabled;
instead all work passed to the thread pool will be executed immediately
by the calling thread.
As of version 3.2.0, on MinGW the thread pool is by default disabled, due to a
bug which causes deadlock on application shutdown. Enabling the pool can be
explicitly requested by setting ``BOTAN_THREAD_POOL_SIZE`` to an integer
value.
* ``BOTAN_MLOCK_POOL_SIZE`` controls the total amount of memory, in bytes, which
will be locked in memory using ``mlock`` or ``VirtualLock`` and managed in a
memory pool. This should be a multiple of the system page size. If set to
``0``, then the memory pool is disabled.
* ``BOTAN_FFI_PRINT_EXCEPTIONS`` if this variable is set (to any value), then
if an exception is caught by the FFI layer, before returning an error code, it
will print the text message of the exception to stderr. This is primarily
intended for debugging.
* ``BOTAN_CLEAR_CPUID``: this variable can be set to a comma-separated list of
CPUID fields to ignore. For example setting ``BOTAN_CLEAR_CPUID=avx2,avx512``
will cause AVX2 and AVX-512 codepaths to be avoided. Note that disabling basic
features (notably NEON or SSE2/SSSE3) can cause other higher level features
like AES-NI to also become disabled.

File diff suppressed because it is too large Load Diff

View File

@@ -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, Cipher_Dir::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, Cipher_Dir::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, Cipher_Dir::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 ``Cipher_Dir::Encryption`` or ``Cipher_Dir::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.

View File

@@ -0,0 +1,60 @@
========================================
Footguns
========================================
This section notes areas where certain usages can cause confusing bugs or problems.
Static Objects
------------------
If you maintain ``static`` variables which hold Botan objects, you will perhaps
find that in some circumstances your application crashes in strange ways on
shutdown. That is because, at least on some operating systems, Botan uses a
locked memory pool as backing storage for the ``secure_vector`` type. This pool
allocates out of pages which have been locked into memory using ``mlock`` or
``VirtualLock`` system calls.
If your variable happens to be destroyed before the pool, all is well. If the
pool happens to be destroyed before the variable, then when the object goes to
free its memory, a crash will occur.
This is basically the famous C++ "Static Initialization Order Fiasco", except
in reverse.
The best course of action is to avoid ``static`` variables. If that is
impossible or inconvenient, one option is to disable the pool, either at build
time (disable the ``locking_allocator`` module) or at runtime. Unfortunately the
runtime setting requires setting an environment variable (see :ref:`env_vars`),
and doing so consistently *prior to static intialization* is not trivial, due to
the previously mentioned fiasco. One option might be to use GCC's
``constructor`` function attribute.
Another approach is to use the utility class ``Allocator_Initializer`` (declared
in ``mem_ops.h``) as an associated ``static`` variable in your code. As long as
the ``Allocator_Initializer`` is created *before* your static variables, that
means the allocator is created before your object, and thus will be destroyed
after your object is destroyed.
Ideally a more satisfactory solution to this issue could be found, especially
given the difficulty of disabling the pool at runtime.
Multithreaded Access
----------------------
It is perfectly safe to use the library from multiple threads.
It is *not* safe to use the same object from multiple threads, without some form
of external serialization or locking.
There are a few exceptions to this rule, where the type itself maintains an
internal mutexes. This will be noted in the respective documentation for that type.
Use of `fork`
----------------------
If you use the `fork` syscall in your code, and attempt to use the library in
both processes, likely bad things will happen due to internal locks. You can
avoid this problem by either at build time disabling the features associated
with these locks (namely ``locking_allocator`` and ``thread_utils``) or
disabling them at runtime using :ref:`env_vars`, ideally at the very start of
`main`.

View File

@@ -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

View File

@@ -0,0 +1,312 @@
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``.
.. cpp:function:: std::unique_ptr<HashFunction> new_object()
Return a newly allocated HashFunction object of the same type as this one.
.. cpp:function:: std::unique_ptr<HashFunction> copy_state()
Return a newly allocated HashFunction object of the same type as this one,
whose internal state matches the current state of this.
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.
.. literalinclude:: /../src/examples/hash.cpp
:language: cpp
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
^^^^^^^^^^^^^^^
.. deprecated:: 2.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.
.. warning::
As this hash function is no longer approved by the latest Russian standards,
support for GOST 34.11 hash is deprecated and will be removed in a future
major release.
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
^^^^^^^^^
An old and now broken hash function. Available if ``BOTAN_HAS_MD4`` is defined.
.. warning::
MD4 collisions can be easily created. There is no safe cryptographic use
for this function.
.. warning::
Support for MD4 is deprecated and will be removed in a future major release.
MD5
^^^^^^^^^
An old and now broken hash function. Available if ``BOTAN_HAS_MD5`` is defined.
.. warning::
MD5 collisions can be easily created. MD5 should never be used for signatures.
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. Prefer SHA-2 or SHA-3
in new code.
SHA-1
^^^^^^^^^^^^^^^
Available if ``BOTAN_HAS_SHA1`` is defined.
Widely adopted NSA designed hash function. Use SHA-2 or SHA-3 in new code.
.. warning::
SHA-1 collisions can now be created by moderately resourced attackers. It
must never be used for signatures.
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, which have the advantage
of avoiding message extension attacks.
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.
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.
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.

View File

@@ -0,0 +1,153 @@
.. _key_derivation_function:
Key Derivation Functions (KDF)
========================================
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.
Typically a KDF is also used with a *salt* and a *label*. The *salt* should be
some random information which is available to all of the parties that would need
to use the KDF; this could be performed by setting the salt to some kind of
session identifier, or by having one of the parties generate a random salt and
including it in a message.
The *label* is used to bind the KDF output to some specific context. For
instance if you were using the KDF to derive a specific key referred to as the
"message key" in the protocol description, you might use a label of "FooProtocol
v2 MessageKey". This labeling ensures that if you accidentally use the same
input key and salt in some other context, you still use different keys in the
two contexts.
.. cpp:class:: KDF
.. cpp:function:: std::unique_ptr<KDF> KDF::create(const std::string& algo)
Create a new KDF object. Returns nullptr if the named key derivation
function was not available
.. cpp:function:: std::unique_ptr<KDF> KDF::create_or_throw(const std::string& algo)
Create a new KDF object. Throws an exception if the named key derivation
function was not available
.. cpp:function:: template<concepts::resizable_byte_buffer T = secure_vector<uint8_t>> \
T derive_key(size_t key_len, \
std::span<const uint8_t> secret, \
std::span<const uint8_t> salt, \
std::span<const uint8_t> label) const
This version is parameterized to the output buffer type, so it can be used
to return a ``std::vector``, a ``secure_vector``, or anything else
satisfying the ``resizable_byte_buffer`` concept.
.. cpp:function:: secure_vector<uint8_t> derive_key( \
const uint8_t secret[], \
size_t secret_len, \
const uint8_t salt[], \
size_t salt_len, \
const uint8_t label[], \
size_t label_len) 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 std::vector<uint8_t>& label) 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*, *salt*, and *label*, whose
meaning is described above.
Code Example
------------
An example demonstrating using the API to hash a secret using HKDF
.. literalinclude:: /../src/examples/kdf.cpp
:language: cpp
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. There is no technical reason (besides compatability) to choose any
other KDF.
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. However it is
overly complicated and is fixed to use only SHA-1.
Available if ``BOTAN_HAS_X942_PRF`` is defined.
.. warning::
X9.42 PRF is deprecated and will be removed in a future major release.
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.

View File

@@ -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.

View File

@@ -0,0 +1,195 @@
.. _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:: std::unique_ptr<MessageAuthenticationCode> new_object() const
Return a newly allocated object of the same type as this one.
The new object is unkeyed.
.. 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.
.. literalinclude:: /../src/examples/hmac.cpp
:language: cpp
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*.
.. literalinclude:: /../src/examples/gmac.cpp
:language: cpp
The following example code computes a valid AES-128 CMAC tag and modifies the
data to demonstrate a MAC verification failure.
.. literalinclude:: /../src/examples/cmac.cpp
:language: cpp
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.
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.
.. warning::
Due to the nonce requirement, GMAC is exceptionally fragile. Avoid it unless
absolutely required.
HMAC
~~~~~~~~~~~~
A message authentication code based on a hash function. Very commonly used.
Available if ``BOTAN_HAS_HMAC`` is defined.
KMAC
~~~~~~~~~~~~
.. versionadded:: 3.2
A SHA-3 derived message authentication code defined by NIST in SP 800-185.
There are two variants, ``KMAC-128`` and ``KMAC-256``. Both take a parameter
which specifies the output length in bits, for example ``KMAC-128(256)``.
Available if ``BOTAN_HAS_KMAC`` 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.
.. warning::
Due to the nonce requirement, Poly1305 is exceptionally fragile. Avoid it unless
absolutely required.
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.
Sometimes called the "DES retail MAC", also standardized in ISO 9797-1.
It is slow and has known attacks. Avoid unless required.
Available if ``BOTAN_HAS_X919_MAC`` is defined.

View File

@@ -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.

View File

@@ -0,0 +1,215 @@
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.
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``

View File

@@ -0,0 +1,294 @@
.. _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.
PasswordHash
--------------
.. versionadded:: 2.8.0
This API, declared in ``pwdhash.h``, has two classes, ``PasswordHashFamily``
representing the general algorithm, such as "PBKDF2(SHA-256)", or "Scrypt", and
``PasswordHash`` representing a specific instance of the problem which is fully
specified with all parameters (say "Scrypt" with ``N`` = 8192, ``r`` = 64, and
``p`` = 8) and which can be used to derive keys.
.. cpp:class:: PasswordHash
.. cpp:function:: void hash(std::span<uint8_t> out, \
std::string_view password, \
std::span<uint8> salt)
Derive a key from the specified *password* and *salt*, placing it into *out*.
.. cpp:function:: void hash(std::span<uint8_t> out, \
std::string_view password, \
std::span<const uint8> salt, \
std::span<const uint8> ad, \
std::span<const uint8> key)
Derive a key from the specified *password*, *salt*, associated data (*ad*), and
secret *key*, placing it into *out*. The *ad* and *key* are both allowed
to be empty. Currently non-empty AD/key is only supported with Argon2.
.. 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
Same functionality as the 3 argument variant of :cpp:func:`PasswordHash::hash`.
.. 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 uint8_t ad[], size_t ad_len, \
const uint8_t key[], size_t key_len) const
Same functionality as the 5 argument variant of :cpp:func:`PasswordHash::hash`.
.. cpp:function:: std::string to_string() const
Return a descriptive string including the parameters (iteration count, etc)
.. cpp:function:: size_t iterations() const
Return the iteration parameter
.. cpp:function:: size_t memory_param() const
Return the memory usage parameter, or 0 if the algorithm does not offer
a memory usage option.
.. cpp:function:: size_t parallelism() const
Returns the parallelism parameter, or 0 if the algorithm does not offer a
parallelism option.
.. cpp:function:: size_t total_memory_usage() const
Return a guesstimate of the total number of bytes of memory consumed when
running this algorithm. If the function is not intended to be memory-hard
and uses an effictively fixed amount of memory when running, this function
returns 0.
.. cpp:function:: bool supports_keyed_operation() const
Returns true if this password hash supports supplying a secret key
to :cpp:func:`PasswordHash::hash`.
.. cpp:function:: bool supports_associated_data() const
Returns true if this password hash supports supplying associated data
to :cpp:func:`PasswordHash::hash`.
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", "Argon2id". Returns null if the
algorithm is 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, \
size_t max_memory_usage_mb = 0, \
std::chrono::milliseconds tuning_msec = std::chrono::milliseconds(10)) 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.)
The parameters will be selected to use at most *max_memory_usage_mb* megabytes
of memory, or if left as zero any size is allowed.
This function works by runing a short tuning loop to estimate the
performance of the algorithm, then scaling the parameters appropriately to
hit the target size. The length of time the tuning loop runs can be
controlled using the *tuning_msec* parameter.
.. 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. Parameters are as follows:
* For PBKDF2, PGP-S2K, and Bcrypt-PBKDF, ``i1`` is iterations
* Scrypt uses ``i1`` == ``N``, ``i2`` == ``r``, and ``i3`` == ``p``
* Argon2 family uses ``i1`` == ``M``, ``i2`` == ``t``, and ``i3`` == ``p``
All unneeded parameters should be set to 0 or left blank.
Code Example
------------
An example demonstrating using the API to hash a password using Argon2i:
.. literalinclude:: /../src/examples/pwdhash.cpp
:language: cpp
Available Schemes
----------------------
General Recommendations
^^^^^^^^^^^^^^^^^^^^^^^^^
If you need wide interoperability use PBKDF2 with HMAC-SHA256 and at least 50K
iterations. If you don't, use Argon2id with p=1, t=3 and M as large as you
can reasonably set (say 1 gigabyte).
You can test how long a particular PBKDF takes to execute using the cli tool
``pbkdf_tune``::
$ ./botan pbkdf_tune --algo=Argon2id 500 --max-mem=192 --check
For 500 ms selected Argon2id(196608,3,1) using 192 MiB took 413.159 msec to compute
This returns the parameters chosen by the fast auto-tuning algorithm, and
because ``--check`` was supplied the hash is also executed with the full set of
parameters and timed.
PBKDF2
^^^^^^^^^^^^
PBKDF2 is the "standard" password derivation scheme, widely implemented in many
different libraries. It uses HMAC internally and requires choosing a hash
function to use. (If in doubt use SHA-256 or SHA-512). It also requires choosing
an iteration count, which makes brute force attacks more expensive. Use *at
least* 50000 and preferably much more. Using 250,000 would not be unreasonable.
Scrypt
^^^^^^^^^^
.. versionadded:: 2.7.0
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 has three parameters, usually termed ``N``, ``r``, and ``p``. ``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 1 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. There are three minor variants
of Argon2 - Argon2d, Argon2i, and Argon2id. All three are implemented.
Bcrypt
^^^^^^^^^^^^
.. versionadded:: 2.11.0
Bcrypt-PBKDF is a variant of the well known ``bcrypt`` password hashing
function. Like ``bcrypt`` it is based around using Blowfish for the key
expansion, which requires 4 KiB of fast random access memory, making hardware
based attacks more expensive. Unlike Argon2 or Scrypt, the memory usage is not
tunable.
This function is relatively obscure but is used for example in OpenSSH.
Prefer Argon2 or Scrypt in new systems.
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.
PBKDF
---------
:cpp:class:`PBKDF` is the older API for this functionality, presented in header
``pbkdf.h``. It only supports PBKDF2 and the PGP S2K algorithm, not
Scrypt, Argon2, or bcrypt. This interface is deprecated and will be removed
in a future major release.
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:: static std::unique_ptr<PBKDF> create(const std::string& algo_spec, \
const std::string& provider = "")
Return a newly created PBKDF object. The name should be in the
format "PBKDF2(HASHNAME)", "PBKDF2(HMAC(HASHNAME))", or
"OpenPGP-S2K". Returns null if the algorithm is not available.
.. 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.

View File

@@ -0,0 +1,944 @@
.. _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 accessed by the ``Module::operator->()`` method.
----------
Code Example:
.. literalinclude:: /../src/examples/pkcs11_low_level.cpp
:language: cpp
.. _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:
.. literalinclude:: /../src/examples/pkcs11_module.cpp
:language: cpp
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:
.. literalinclude:: /../src/examples/pkcs11_slot.cpp
:language: cpp
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.
The session is passed to most other PKCS#11 operations, and must remain alive
as long as any other PKCS#11 object which the session 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:: 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:
.. literalinclude:: /../src/examples/pkcs11_session.cpp
:language: cpp
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::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::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::Object(Session& session, ObjectHandle handle)
Takes ownership over an existing object.
.. cpp:function:: Object::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::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:
.. literalinclude:: /../src/examples/pkcs11_objects.cpp
:language: cpp
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:
.. literalinclude:: /../src/examples/pkcs11_rsa.cpp
:language: cpp
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:
.. literalinclude:: /../src/examples/pkcs11_ecdsa.cpp
:language: cpp
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:
.. literalinclude:: /../src/examples/pkcs11_ecdh.cpp
:language: cpp
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:
.. literalinclude:: /../src/examples/pkcs11_rng.cpp
:language: cpp
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:
.. literalinclude:: /../src/examples/pkcs11_token_management.cpp
:language: cpp
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:
.. literalinclude:: /../src/examples/pkcs11_x509.cpp
:language: cpp
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]_ |
+-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+
| CardOS 5.3 | mostly works | Windows 10, 64-bit, version 1903 | API Version 5.5.1 (Cryptoki v2.11) | 2.12.0 unreleased, Cryptoki v2.40 | [53]_ |
+-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+
| 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 | [54]_ |
+-------------------------------------+-------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+---------------------------------------------------+
| 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 CardOS 5.3 (middelware 5.5.1)
- ecdh_privkey_export [2]_
- ecdh_generate_private_key [35]_
- ecdsa_privkey_export [2]_
- ecdsa_generate_private_key [36]_
- c_copy_object [4]_
- object_copy [4]_
- rng_add_entropy [5]_
- rsa_sign_verify [3]_
- rsa_privkey_export [2]_
- rsa_generate_private_key [9]_
.. [54] 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)
.. [9] CKR_TEMPLATE_INCOMPLETE (0xD0=208)
.. [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
.. [35] Invalid argument OS2ECP: Unknown format type 82
.. [36] Invalid argument OS2ECP: Unknown format type 102

View File

@@ -0,0 +1,110 @@
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, along with some implementations
of same, are 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, but will not be able to tell how many other
master keys are in use.
.. 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.
.. 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)``.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,667 @@
Python Binding
========================================
.. versionadded:: 1.11.14
.. highlight:: python
.. py:module:: botan3
The Python binding is based on the `ffi` module of botan and the
`ctypes` module of the Python standard library.
The versioning of the Python module follows the major versioning of
the C++ library. So for Botan 2, the module is named ``botan2`` while
for Botan 3 it is ``botan3``.
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 HMAC_DRBG 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.RandomNumberGenerator().get(32)`.
.. py:method:: get(length)
Return some bytes
.. 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``
The ``algo`` param is a string (eg 'SHA-1', 'SHA-384', 'BLAKE2b')
.. 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:classmethod:: load(val)
Load a public key. The value should be a PEM or DER blob.
.. py:classmethod:: load_rsa(n, e)
Load an RSA public key giving the modulus and public exponent
as integers.
.. py:classmethod:: load_dsa(p, q, g, y)
Load an DSA public key giving the parameters and public value
as integers.
.. py:classmethod:: load_dh(p, g, y)
Load an Diffie-Hellman public key giving the parameters and
public value as integers.
.. py:classmethod:: load_elgamal(p, q, g, y)
Load an ElGamal public key giving the parameters and
public value as integers.
.. py:classmethod:: load_ecdsa(curve, pub_x, pub_y)
Load an ECDSA public key giving the curve as a string
(like "secp256r1") and the public point as a pair of
integers giving the affine coordinates.
.. py:classmethod:: load_ecdh(curve, pub_x, pub_y)
Load an ECDH public key giving the curve as a string
(like "secp256r1") and the public point as a pair of
integers giving the affine coordinates.
.. py:classmethod:: load_sm2(curve, pub_x, pub_y)
Load a SM2 public key giving the curve as a string (like
"sm2p256v1") and the public point as a pair of integers giving
the affine coordinates.
.. py:method:: check_key(rng_obj, strong=True):
Test the key for consistency. If ``strong`` is ``True`` then
more expensive tests are performed.
.. py:method:: export(pem=False)
Exports the public key using the usual X.509 SPKI representation.
If ``pem`` is True, the result is a PEM encoded string. Otherwise
it is a binary DER value.
.. py:method:: to_der()
Like ``self.export(False)``
.. py:method:: to_pem()
Like ``self.export(True)``
.. py:method:: get_field(field_name)
Return an integer field related to the public key. The valid field names
vary depending on the algorithm. For example RSA public modulus can be
extracted with ``rsa_key.get_field("n")``.
.. 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)
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="")
Return a private key (DER or PEM formats accepted)
.. py:classmethod:: load_rsa(p, q, e)
Return a private RSA key
.. py:classmethod:: load_dsa(p, q, g, x)
Return a private DSA key
.. py:classmethod:: load_dh(p, g, x)
Return a private DH key
.. py:classmethod:: load_elgamal(p, q, g, x)
Return a private ElGamal key
.. py:classmethod:: load_ecdsa(curve, x)
Return a private ECDSA key
.. py:classmethod:: load_ecdh(curve, x)
Return a private ECDH key
.. py:classmethod:: load_sm2(curve, x)
Return a private SM2 key
.. py:method:: get_public_key()
Return a public_key object
.. py:method:: to_pem()
Return the PEM encoded private key (unencrypted). Like ``self.export(True)``
.. py:method:: to_der()
Return the PEM encoded private key (unencrypted). Like ``self.export(False)``
.. py:method:: check_key(rng_obj, strong=True):
Test the key for consistency. If ``strong`` is ``True`` then
more expensive tests are performed.
.. py:method:: algo_name()
Returns the algorithm name
.. py:method:: export(pem=False)
Exports the private key in PKCS8 format. If ``pem`` is True, the
result is a PEM encoded string. Otherwise it is a binary DER
value. The key will not be encrypted.
.. py:method:: export_encrypted(passphrase, rng, pem=False, msec=300, cipher=None, pbkdf=None)
Exports the private key in PKCS8 format, encrypted using the
provided passphrase. If ``pem`` is True, the result is a PEM
encoded string. Otherwise it is a binary DER value.
.. py:method:: get_field(field_name)
Return an integer field related to the public key. The valid field names
vary depending on the algorithm. For example first RSA secret prime can be
extracted with ``rsa_key.get_field("p")``. This function can also be
used to extract the public parameters.
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, radix=None)
Initialize an MPI object with specified value, left as zero otherwise. The
``initial_value`` should be an ``int``, ``str``, or ``MPI``.
The ``radix`` value should be set to 16 when initializing from a base 16 `str` value.
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``
.. py:method:: mod_mul(other, modulus):
Return the multiplication product of ``self`` and ``other`` modulo ``modulus``
.. py:method:: gcd(other):
Return the greatest common divisor of ``self`` and ``other``
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 botan3.MPI or an object which can be converted to one
.. py:method:: decrypt(msg, tweak)
The msg should be a botan3.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.
X509Cert
-----------------------------------------
.. py:class:: X509Cert(filename=None, buf=None)
.. py:method:: time_starts()
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.
.. py:method:: time_expires()
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.
.. py:method:: to_string()
Format the certificate as a free-form string.
.. py:method:: fingerprint(hash_algo='SHA-256')
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.
.. py:method:: serial_number()
Return the serial number of the certificate.
.. py:method:: authority_key_id()
Return the authority key ID set in the certificate, which may be empty.
.. py:method:: subject_key_id()
Return the subject key ID set in the certificate, which may be empty.
.. py:method:: subject_public_key_bits()
Get the serialized representation of the public key included in this certificate.
.. py:method:: subject_public_key()
Get the public key included in this certificate as an object of class ``PublicKey``.
.. py:method:: subject_dn(key, index)
Get a value from the subject DN field.
``key`` specifies a value to get, for instance ``"Name"`` or `"Country"`.
.. py:method:: issuer_dn(key, index)
Get a value from the issuer DN field.
``key`` specifies a value to get, for instance ``"Name"`` or `"Country"`.
.. py:method:: hostname_match(hostname)
Return True if the Common Name (CN) field of the certificate matches a given ``hostname``.
.. py:method:: not_before()
Return the time the certificate becomes valid, as seconds since epoch.
.. py:method:: not_after()
Return the time the certificate expires, as seconds since epoch.
.. py:method:: allowed_usage(usage_list)
Return True if the certificates Key Usage extension contains all constraints given in ``usage_list``.
Also return True if the certificate doesn't have this extension.
Example usage constraints are: ``"DIGITAL_SIGNATURE"``, ``"KEY_CERT_SIGN"``, ``"CRL_SIGN"``.
.. py:method:: verify(intermediates=None, \
trusted=None, \
trusted_path=None, \
required_strength=0, \
hostname=None, \
reference_time=0 \
crls=None)
Verify a certificate. Returns 0 if validation was successful, returns a positive error code
if the validation was unsuccesful.
``intermediates`` is a list of untrusted subauthorities.
``trusted`` is a list of trusted root CAs.
The `trusted_path` refers to a directory where one or more trusted CA
certificates are stored.
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.
If ``hostname`` is given, it will be checked against the certificates CN field.
Set ``reference_time`` to be the time which the certificate chain is
validated against. Use zero (default) to use the current system clock.
``crls`` is a list of CRLs issued by either trusted or untrusted authorities.
.. py:classmethod:: validation_status(error_code)
Return an informative string associated with the verification return code.
.. py:method:: is_revoked(self, crl)
Check if the certificate (``self``) is revoked on the given ``crl``.
X509CRL
-----------------------------------------
.. py:class:: X509CRL(filename=None, buf=None)
Class representing an X.509 Certificate Revocation List.
A CRL in PEM or DER format can be loaded from a file, with the ``filename`` argument,
or from a bytestring, with the ``buf`` argument.

View File

@@ -0,0 +1,289 @@
.. _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 ``System_RNG``, or if not available use ``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``, ``BCryptGenRandom``,
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 without locking, 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 again 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:: Starting in 2.16.0, AutoSeeded_RNG uses an internal lock and so is
safe to share among threads. However if possible it is still better to
use a RNG per thread as otherwise the RNG object needlessly creates a
point of contention. In previous versions, the RNG does not have an
internal lock and all access to it must be serialized.
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.
.. note::
There is no reason to use this class directly unless your application
requires HMAC-DRBG with specific parameters or options. Usually this
would be for some standards conformance reason. If you just want a
userspace RNG, use ``AutoSeeded_RNG``.
``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.
Processor_RNG
^^^^^^^^^^^^^^^^^
This RNG type directly invokes a CPU instruction capable of generating
a cryptographically secure random number. On x86 it uses ``rdrand``,
on POWER ``darn``. If the relevant instruction is not available, the
constructor of the class will throw at runtime. You can test
beforehand by checking the result of ``Processor_RNG::available()``.
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 (``/dev/urandom``, ``getrandom``, ``arc4random``,
``BCryptGenRandom``, or ``RtlGenRandom``).
* Processor provided RNG outputs (RDRAND, RDSEED, DARN) are used if available,
but not counted as contributing entropy
* The ``getentropy`` call is used on OpenBSD, FreeBSD, and macOS
* ``/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.

View File

@@ -0,0 +1,6 @@
Roughtime
===========
.. versionadded:: 2.13.0
Botan includes a Roughtime client, available in ``botan/roughtime.h``

View File

@@ -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).

View File

@@ -0,0 +1,77 @@
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 (however brute force attacks are
possible). Later, the client and server can perform an SRP exchange,
which results in a shared secret key. This key can be used for mutual
authentication and/or encryption.
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
protected as carefully as a plaintext password would be.
.. cpp:function:: BigInt generate_srp6_verifier( \
const std::string& username, \
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. Later,
the given username and password are used to by the client during
the key agreement step.
.. 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, and output a value `B` which is provided to
the client.
.. cpp:function:: SymmetricKey step2(const BigInt& A)
Takes the parameter A generated by srp6_client_agree,
and return the shared secret key.
In the event of an impersonation attack (or wrong username/password, etc)
no error occurs, but the key returned will be different on the two sides.
The two sides must verify each other, for example by using the shared
secret to key an HMAC and then exchanging authenticated messages.
.. 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).

View File

@@ -0,0 +1,194 @@
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:: std::unique_ptr<StreamCipher> new_object() const
Return a newly allocated object of the same type as this one.
The new object is unkeyed.
.. 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.
.. literalinclude:: /../src/examples/chacha.cpp
:language: cpp
Available Stream Ciphers
----------------------------
Botan provides the following stream ciphers. If in doubt, pick ChaCha20 or CTR(AES-256).
CTR-BE
~~~~~~~
Counter mode 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 a nonce, 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 the width (which must be at least 4
bytes, allowing to encrypt 2\ :sup:`32` blocks of data) for example using
"CTR(AES-256,8)" will select a 64-bit (8 byte) counter.
(The ``-BE`` suffix refers to big-endian convention for the counter.
Little-endian counter mode is rarely used and not currently implemented.)
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, and was primarily implemented to
support a particular post-quantum scheme which is no longer supported.
SHAKE does not support IVs, nor seeking within the cipher stream.
Available if ``BOTAN_HAS_SHAKE_CIPHER`` is defined.
.. warning::
SHAKE support (as a stream cipher) is deprecated and will be removed
in a future major release.
RC4
~~~~
An old and very widely deployed stream cipher notable for its simplicity. It
does not support IVs or seeking within the cipher stream. Compared to modern
algorithms like ChaCha20, it is also quite slow.
.. warning::
RC4 is prone to numerous attacks. **Avoid in new code** and use only if
required for compatibility with existing systems.
Available if ``BOTAN_HAS_RC4`` is defined.

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,102 @@
.. _versioning:
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

View File

@@ -0,0 +1,954 @@
.. _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 a basic list of constraints which govern usage of the
key embedded in this certificate.
The Key_Constraints is a class that behaves somewhat like an
``enum``. The easiest way to use it is with its ``includes``
method. For example::
constraints().includes(Key_Constraints::DigitalSignature)
checks if the certificate key is valid for generating digital
signatures.
.. 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.
.. cpp:function:: std::string PEM_encode() const
Returns the PEM encoding of the certificate
.. cpp:function:: std::vector<uint8_t> BER_encode() const
Returns the DER/BER encoding of 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::optional`` 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::optional`` of ``X509_CRL``. The ``std::optional`` return
type makes it easy to return no CRLs by returning ``nullopt``
(eg, if the certificate store doesn't support retrieving CRLs).
Implementing the function is optional, and by default will return
``nullopt``.
Certificate stores are used in the :doc:`tls` module to store a
list of trusted certificate authorities.
.. note::
In the 2.x library, the certificate store interface relied on
``shared_ptr<X509_Certificate>`` to avoid copies. However since
2.4.0, the ``X509_Certificate`` was internally shared, and thus the
outer ``shared_ptr`` was just a cause of needless runtime overhead
and API complexity. Starting in version 3.0, the certificate store
interface is defined in terms of plain ``X509_Certificate``.
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_crl(const X509_CRL& crl)
Add a certificate revocation list (CRL) to the store.
System Certificate Stores
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
An interface to use the system provided certificate stores is available for
Unix, macOS and Windows systems, ``System_Certificate_Store``
Flatfile Certificate Stores
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
``Flatfile_Certificate_Store`` is an implementation of certificate store that
reads certificates as files from a directory. This is also used as the
implementation of the Unix/Linux system certificate store.
The constructor takes a path to the directory to read, along with an optional
boolean indicating if non-CA certificates should be ignored.
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<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::optional<OCSP::Response>>& ocsp_resp = std::vector<std::optional<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 some default. The only time you need this alternate interface is
for creating RSA-PSS certificates.
.. cpp:function:: X509_CA::X509_CA(const X509_Certificate& cert, \
const Private_Key& key, \
const std::string& hash_fn, \
const std::string& padding_fn, \
RandomNumberGenerator& rng)
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)
If you need more control over the signing process, you can use the methods
.. cpp:function:: static X509_Certificate X509_CA::make_cert(PK_Signer& signer, \
RandomNumberGenerator& rng, \
const BigInt& serial_number, \
const AlgorithmIdentifier& sig_algo, \
const std::vector<uint8_t>& pub_key, \
const X509_Time& not_before, \
const X509_Time& not_after, \
const X509_DN& issuer_dn, \
const X509_DN& subject_dn, \
const Extensions& extensions)
.. cpp:function:: static Extensions X509_CA::choose_extensions(const PKCS10_Request& req, \
const X509_Certificate& ca_certificate, \
const std::string& hash_fn)
Returns the extensions that would be created by sign_request if it was used.
You can call this and then modify the extensions list before invoking
:cpp:func:`X509_CA::make_cert`
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): ``DigitalSignature``, ``NonRepudiation``,
``KeyEncipherment``, ``DataEncipherment``, ``KeyAgreement``,
``KeyCertSign``, ``CrlSign``, ``EncipherOnly``, or ``DecipherOnly``.
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 based on the key type.
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<X509_Certificate>& cert_path = const std::vector<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``.

View File

@@ -0,0 +1,62 @@
ZFEC Forward Error Correction
===============================
.. versionadded:: 3.0.0
The ``ZFEC`` class provides forward error correction compatible
with the `zfec <https://github.com/tahoe-lafs/zfec>`_ library.
Forward error correction takes an input and creates multiple "shares",
such that any ``K`` of ``N`` shares is sufficient to recover the
entire original input.
.. note::
Specific to the ZFEC format, the first ``K`` generated shares are
identical to the original input data, followed by ``N-K`` shares of
error correcting code. This is very different from threshold secret
sharing, where having fewer than ``K`` shares gives no information
about the original input.
.. warning::
If a corrupted share is provided to the decoding algorithm, the
resulting decoding will be invalid. It is recommended to protect
shares using a technique such as a MAC or public key signature, if
corruption is likely in your application.
``ZFEC`` requires that the input length be exactly divisible by ``K``;
if needed define a padding scheme to pad your input to the necessary
size.
An example application that adds padding and a hash checksum is available
in ``src/cli/zfec.cpp`` and invokable using ``botan fec_encode`` and
``botan fec_decode``.
.. cpp:class:: ZFEC
.. cpp:function:: ZFEC(size_t k, size_t n)
Set up for encoding or decoding using parameters ``k`` and ``n``.
Both must be less than 256, and ``k`` must be less than ``n``.
.. cpp:function:: void encode_shares(const std::vector<const uint8_t*>& shares, \
size_t share_size, \
std::function<void (size_t, const uint8_t[], size_t)> output_cb) const
Encode ``K`` shares in ``shares`` each of length ``share_size`` into ``N``
shares, also each of length ``share_size``. The ``output_cb`` function will
be called once for each output share (in some unspecified and possibly
non-deterministic order).
The parameters to ``output_cb`` are: the share being output, the share
contents, and the length of the encoded share (which will always be
equal to ``share_size``).
.. cpp:function:: void decode_shares(const std::map<size_t, const uint8_t*>& shares, \
size_t share_size, \
std::function<void (size_t, const uint8_t[], size_t)> output_cb) const
Decode some set of shares into the original input. Each share is
of ``share_size`` bytes. The shares are identified by a small
integer (between 0 and 255).
The parameters to ``output_cb`` are similar to that of ``encode_shares``.