aboutsummaryrefslogtreecommitdiffstats
path: root/doc/pubkey.txt
diff options
context:
space:
mode:
Diffstat (limited to 'doc/pubkey.txt')
-rw-r--r--doc/pubkey.txt365
1 files changed, 222 insertions, 143 deletions
diff --git a/doc/pubkey.txt b/doc/pubkey.txt
index 2b765cc10..1be471e1b 100644
--- a/doc/pubkey.txt
+++ b/doc/pubkey.txt
@@ -4,80 +4,240 @@
Public Key Cryptography
=================================
-Quick Start
----------------------------------
+Public key cryptography (also called assymmetric cryptography) is a
+collection of techniques allowing for encryption, signatures, and key
+agreement.
-Let's create a 2048-bit RSA private key, serialize the public key as a
-PKCS #1 file with PEM encoding (which can be understood by many other
-cryptographic programs), and then load it on another machine::
+Key Objects
+----------------------------------------
- // everyone does:
- AutoSeeded_RNG rng;
+Public and private keys are represented by classes ``Public_Key`` and
+it's subclass ``Private_Key``. The use of inheritence here means that
+a ``Private_Key`` can be converted into a reference to a public key.
- // Alice
- RSA_PrivateKey priv_rsa(rng, 2048 /* bits */);
+None of the functions on ``Public_Key`` and ``Private_Key`` itself are
+particularly useful for users of the library, because 'bare' public key
+operations are *very insecure*. The only purpose of these functions is
+to provide a clean interface that higher level operations can be built
+on. So really the only thing you need to know is that when a function
+takes a reference to a ``Public_Key``, it can take any public key or
+private key, and similiarly for ``Private_Key``.
- std::string alice_pem = X509::PEM_encode(priv_rsa);
+Types of ``Public_Key`` include ``RSA_PublicKey``, ``DSA_PublicKey``,
+``ECDSA_PublicKey``, ``DH_PublicKey``, ``ECDH_PublicKey``,
+``RW_PublicKey``, ``NR_PublicKey``,, and ``GOST_3410_PublicKey``.
+There are cooresponding ``Private_Key`` classes for each of these
+algorithms.
- // send alice_pem to Bob, who does
+.. _creating_new_private_keys:
- // Bob
- std::auto_ptr<Public_Key> alice(load_key(alice_pem));
+Creating New Private Keys
+----------------------------------------
- RSA_PublicKey* alice_rsa = dynamic_cast<RSA_PublicKey>(alice);
- if(alice_rsa)
- {
- /* ... */
- }
+Creating a new private key requires two things: a source of
+random numbers (see :ref:`random_number_generators`) and some
+algorithm specific parameters that define the *security level*
+of the resulting key. For instance, the security level of an RSA
+key is (at least in part) defined by the length of the public key
+modulus in bits. So to create a new RSA private key, you would call
-Creating New Public Key Pairs
----------------------------------
+.. cpp:function:: RSA_PrivateKey::RSA_PrivateKey(RandomNumberGenerator& rng, size_t bits)
+
+ A constructor that creates a new random RSA private key with a modulus
+ of length *bits*.
+
+Algorithms based on the discrete-logarithm problem uses what is called
+a *group*; a group can safely be used with many keys, and for some
+operations, like key agreement, the two keys *must* use the same
+group. There are currently two kinds of discrete logarithm groups
+supported in botan: the integers modulo a prime, represented by
+:ref:`dl_group`, and elliptic curves in GF(p), represented by
+:ref:`ec_dompar`. A rough generalization is that the larger the group
+is, the more secure the algorithm is, but coorespondingly the slower
+the operations will be.
+
+Given a ``DL_Group``, you can create new DSA, Diffie-Hellman, and
+Nyberg-Rueppel key pairs with
+
+.. cpp:function:: DSA_PrivateKey::DSA_PrivateKey(RandomNumberGenerator& rng, const DL_Group& group, const BigInt& x = 0)
+
+.. cpp:function:: DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng, const DL_Group& group, const BigInt& x = 0)
+
+.. cpp:function:: NR_PrivateKey::NR_PrivateKey(RandomNumberGenerator& rng, const DL_Group& group, const BigInt& x = 0)
+
+.. cpp:function:: ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng, const DL_Group& group, const BigInt& x = 0)
+
+ The optional *x* parameter to each of these contructors is a private
+ key value. This allows you to create keys where the private key is
+ formed by some special technique; for instance you can use the hash
+ of a password (see :ref:`pbkdf` for how to do that) as a private key
+ value. Normally, you would leave the value as zero, letting the
+ class generate a new random key.
+
+Finally, given an ``EC_Domain_Params`` object, you can create a new
+ECDSA, ECDH, or GOST 34.10 private key with
+
+.. cpp:function:: ECDSA_PrivateKey::ECDSA_PrivateKey(RandomNumberGenerator& rng, const EC_Domain_Params& domain)
+
+.. cpp:function:: ECDH_PrivateKey::ECDH_PrivateKey(RandomNumberGenerator& rng, const EC_Domain_Params& domain)
+
+.. cpp:function:: GOST_3410_PrivateKey::GOST_3410_PrivateKey(RandomNumberGenerator& rng, const EC_Domain_Params& domain)
+
+Unlike the integer modulo a prime key types, the constructor that takes a
+predefined ``BigInt`` private key value is different:
+
+.. cpp:function:: ECDSA_PrivateKey::ECDSA_PrivateKey(const EC_Domain_Params& domain, const BigInt& x)
+
+.. cpp:function:: ECDH_PrivateKey::ECDH_PrivateKey(const EC_Domain_Params& domain, const BigInt& x)
+
+.. cpp:function:: GOST_3410_PrivateKey::GOST_3410_PrivateKey(const EC_Domain_Params& domain, const BigInt& x)
+
+.. note::
+
+ It is likely that these constructors will be removed in a future
+ release, and a third optional parameter will be added to the
+ constructors described above, to match the integer modulo prime
+ versions. Only use them if you really need them.
+
+
+Serializing Private Keys
+----------------------------------------
+
+The standard format for serializing a private key is PKCS #8, the
+operations for which are defined in ``pkcs8.h``. It supports both
+unencrypted and encrypted storage.
+
+.. cpp:function:: SecureVector<byte> PKCS8::BER_encode(const Private_Key& key, RandomNumberGenerator& rng, const std::string& password, const std::string& pbe_algo = "")
+
+ Takes any private key object, serializes it, encrypts it using
+ *password*, and returns a binary structure representing the private
+ key.
+
+ The final (optional) argument, *pbe_algo*, specifies a particular
+ password based encryption (or PBE) algorithm. If you don't specify a
+ PBE, a sensible default will be used.
+
+.. cpp:function:: std::string PKCS8::PEM_encode(const Private_Key& key, RandomNumberGenerator& rng, const std::string& pass, const std::string& pbe_algo = "")
+
+ This formats the key in the same manner as ``BER_encode``, but
+ additionally encodes it into a text format with identifying
+ headers. Using PEM encoding is *highly* recommended for many
+ reasons, including compatibility with other software, for
+ transmission over 8-bit unclean channels, because it can be
+ identified by a human without special tools, and because it
+ sometimes allows more sane behavior of tools that process the data.
+
+Unencrypted serialization is also supported.
+
+.. warning::
+
+ In most situations, using unecrypted private key storage is a bad
+ idea, because anyone can come along and grab the private key without
+ having to know any passwords or other secrets. Unless you have very
+ particular security requirements, always use the versions that
+ encrypt the key based on a passphrase, described above.
+
+.. cpp:function:: SecureVector<byte> PKCS8::BER_encode(const Private_Key& key)
+
+ Serializes the private key and returns the result.
+
+.. cpp:function:: std::string PKCS8::PEM_encode(const Private_Key& key)
+
+ Serializes the private key, base64 encodes it, and returns the
+ result.
+
+Last but not least, there are some functions that will load (and
+decrypt, if necessary) a PKCS #8 private key:
+
+.. cpp:function:: Private_Key* PKCS8::load_key(DataSource& in, RandomNumberGenerator& rng, const User_Interface& ui)
+
+.. cpp:function:: Private_Key* PKCS8::load_key(DataSource& in, RandomNumberGenerator& rng, std::string passphrase = "")
+
+.. cpp:function:: Private_Key* PKCS8::load_key(const std::string& filename, RandomNumberGenerator& rng, const User_Interface& ui)
+
+.. cpp:function:: Private_Key* PKCS8::load_key(const std::string& filename, RandomNumberGenerator& rng, const std::string& passphrase = "")
+
+The result is an object allocated using ``new``.
+
+The versions that pass the passphrase as a ``std::string`` are
+primarily for compatibility, but they are useful in limited
+circumstances. The ``User_Interface`` versions are how ``load_key`` is
+implemented, and provides for much more flexibility. If the passphrase
+passed in is not correct, then an exception is thrown and that is
+that. However, if you pass in an UI object, then the UI object can
+keep asking the user for the passphrase until they get it right (or
+until they cancel the action, though the UI interface). A
+``User_Interface`` has very little to do with talking to users; it's
+just a way to glue together Botan and whatever user interface you
+happen to be using. You can think of it as a user interface
+interface. The default ``User_Interface`` is rather dumb, and acts
+rather like the versions taking the ``std::string``; it tries the
+passphrase passed in first, and then it cancels.
+
+.. note::
+
+ In a future version, it is likely that ``User_Interface`` will be
+ replaced by a simple callback using ``std::function``.
+
+.. _dl_group:
-The library has interfaces for public key encryption, signatures, and
-key agreement that do not require knowing the exact algorithm in
-use. One place where we *do* need to know exactly what kind of
-algorithm is in use is when we are creating a key.
-
-There are currently three kinds of public key algorithms in Botan:
-ones based on integer factorization (RSA and Rabin-Williams), ones
-based on the discrete logarithm problem in the integers modulo a prime
-(DSA, Diffie-Hellman, Nyberg-Rueppel, and ElGamal), and ones based on
-the discrete logarithm problem in an elliptic curve (ECDSA, ECDH, and
-GOST 34.10). The systems based on discrete logarithms (in either
-regular integers or elliptic curves) use a group (a mathematical
-term), which can be shared among many keys. An elliptic curve group is
-represented by the class ``EC_Domain_Params``, while a modulo-prime
-group is represented by a ``DL_Group``.
-
-There are two ways to create a DL private key (such as
-``DSA_PrivateKey``). One is to pass in just a ``DL_Group`` object -- a
-new key will automatically be generated. The other involves passing in
-a group to use, along with both the public and private values (private
-value first).
-
-Since in integer factorization algorithms, the modulus used isn't
-shared by other keys, we don't use this notion. You can create a new
-key by passing in a ``size_t`` telling how long (in bits) the key
-should be, or you can copy an pre-existing key by passing in the
-appropriate parameters (primes, exponents, etc). For RSA and
-Rabin-Williams (the two IF schemes in Botan), the parameters are all
-``BigInt``: prime 1, prime 2, encryption exponent, decryption
-exponent, modulus. The last two are optional, since they can easily be
-derived from the first three.
-
-Creating a DL_Group
+DL_Group
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-There are quite a few ways to get a ``DL_Group`` object. The best is
-to use the function ``get_dl_group``, which takes a string naming a
-group; it will either return that group, if it knows about it, or
-throw an exception. Names it knows about include "modp/ietf/N" where N
-is 768, 1024, 1536, 2048, 3072, 4096, 6144, and 8192 for
-Diffie-Hellman and ElGamal. DSA-style groups are named "dsa/jce/N" for
-N 512, 768, 1024, and "dsa/botan/N" for 2048 and 3072.
+As described in :ref:`creating_new_private_keys`, a discrete logarithm
+group can be shared among many keys, even keys created by users who do
+not trust each other. However, it is necessary to trust the entity who
+created the group; that is why organization like NIST use algorithms
+which generate groups in a deterministic way such that creating a
+bogus group would require breaking some trusted cryptographic
+primitive like SHA-2.
+
+Instantiating a ``DL_Group`` simply requires calling
+
+.. cpp:function:: DL_Group::DL_Group(const std::string& name)
+
+ The *name* parameter is a specially formatted string that consists
+ of three things, the type of the group ("modp" or "dsa"), the
+ creator of the group, and the size of the group in bits, all
+ delimited by '/' characters.
+
+ Currently all "modp" groups included in botan are ones defined by
+ the Internet Engineering Task Force, so the provider is "ietf", and
+ the strings look like "modp/ietf/N" where N can be any of 768, 1024,
+ 1536, 2048, 3072, 4096, 6144, or 8192. This group type is used
+ for Diffie-Hellman and ElGamal algorithms.
+
+ The other type, "dsa" is used for DSA and Nyberg-Rueppel keys. They
+ can also be used with Diffie-Hellman and ElGamal, but this is less
+ common. The currently available groups are "dsa/jce/N" for N in 512,
+ 768, or 1024, and "dsa/botan/N" with N being 2048 or 3072. The
+ "jce" groups are the standard DSA groups used in the Java
+ Cryptography Extensions, while the "botan" groups were randomly
+ generated using the FIPS 186-3 algorithm by the library maintainers.
+
+You can generate a new random group using
+
+.. cpp:function:: DL_Group::DL_Group(RandomNumberGenerator& rng, PrimeType type, size_t pbits, size_t qbits = 0)
-You can also generate a new random group. This is not recommend,
-because it is quite slow, especially for safe primes.
+ The *type* can be either ``Strong``, ``Prime_Subgroup``, or
+ ``DSA_Kosherizer``. *pbits* specifies the size of the prime in
+ bits. If the *type* is ``Prime_Subgroup`` or ``DSA_Kosherizer``,
+ then *qbits* specifies the size of the subgroup.
+
+You can export a ``DL_Group`` using
+
+.. cpp:function:: SecureVector<byte> DL_Group::DER_Encode(Format format)
+
+or
+
+.. cpp:function:: std::string DL_Group::PEM_encode(Format format)
+
+where *format* is any of
+
+.. _ec_dompar:
+
+EC_Domain_Params
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Key Checking
---------------------------------
@@ -291,19 +451,9 @@ To import and export public keys, use:
.. cpp:function:: MemoryVector<byte> X509::BER_encode(const Public_Key& key)
- Takes any public key object, and returns a standard binary structure
- representing the key which can be read by many other crypto
- libraries.
.. cpp:function:: std::string X509::PEM_encode(const Public_Key& key)
- This formats the key the same as ``BER_encode``, but additionally
- encodes it into a text format with identifying headers. Using PEM
- encoding is *highly* recommended for many reasons, including
- compatibility with other software, for transmission over 8-bit
- unclean channels, because it can be identified by a human without
- special tools, and because it sometimes allows more sane behavior of
- tools that process the data.
.. cpp:function:: Public_Key* X509::load_key(DataSource& in)
@@ -325,74 +475,3 @@ To import and export public keys, use:
Importing/Exporting Private Keys
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-There are two different options for private key import/export. The
-first is a plaintext version of the private key. This is supported by
-the following functions:
-
-.. cpp:function:: SecureVector<byte> PKCS8::BER_encode(const Private_Key& key)
-
-.. cpp:function:: std::string PKCS8::PEM_encode(const Private_Key& key)
-
-These functions are similiar to the X.509 functions described in
-:ref:`import_export_public_keys`. The only difference is that they take
-a ``Private_Key`` object instead. In most situations, using these
-versions is a bad idea, because anyone can come along and grab the
-private key without having to know any passwords or other
-secrets. Unless you have very particular security requirements, always
-use the versions that encrypt the key based on a passphrase described
-below. For importing, the same functions can be used for encrypted and
-unencrypted keys.
-
-The other way to export a PKCS #8 key is to first encode it in the
-same manner as done above, then encrypt it using a passphrase, and
-store the whole thing into another structure. This method is
-definitely preferred, since otherwise the private key is
-unprotected. The algorithms and structures used here are standardized
-by PKCS #5 and PKCS #8, and can be read by many other crypto
-libraries:
-
-.. cpp:function:: SecureVector<byte> PKCS8::BER_encode(const Private_Key& key, RandomNumberGenerator& rng, const std::string& pass, const std::string& pbe_algo = "")
-
-.. cpp:function:: std::string PKCS8::PEM_encode(const Private_Key& key, RandomNumberGenerator& rng, const std::string& pass, const std::string& pbe_algo = "")
-
-
-There are three new arguments needed here to support the encryption
-process. The first is a ``RandomNumberGenerator``, which is used to
-generate salts to randomize the encryption. The ``pass`` argument is
-the passphrase that will be used to encrypt the key. Both of these are
-required. The final (optional) argument, ``pbe_algo``, specifies a
-particular password based encryption (or PBE) algorithm. If you don't
-specify a PBE, a sensible default will be used.
-
-Last but not least, there are some functions that will load (and
-decrypt, if necessary) a PKCS #8 private key:
-
-.. cpp:function:: Private_Key* PKCS8::load_key(DataSource& in, RandomNumberGenerator& rng, const User_Interface& ui)
-
-.. cpp:function:: Private_Key* PKCS8::load_key(DataSource& in, RandomNumberGenerator& rng, std::string passphrase = "")
-
-.. cpp:function:: Private_Key* PKCS8::load_key(const std::string& filename, RandomNumberGenerator& rng, const User_Interface& ui)
-
-.. cpp:function:: Private_Key* PKCS8::load_key(const std::string& filename, RandomNumberGenerator& rng, const std::string& passphrase = "")
-
-The versions that pass the passphrase as a ``std::string`` are
-primarily for compatibility, but they are useful in limited
-circumstances. The ``User_Interface`` versions are how ``load_key`` is
-implemented, and provides for much more flexibility. If the passphrase
-passed in is not correct, then an exception is thrown and that is
-that. However, if you pass in an UI object, then the UI object can
-keep asking the user for the passphrase until they get it right (or
-until they cancel the action, though the UI interface). A
-``User_Interface`` has very little to do with talking to users; it's
-just a way to glue together Botan and whatever user interface you
-happen to be using. You can think of it as a user interface
-interface. The default ``User_Interface`` is rather dumb, and acts
-rather like the versions taking the ``std::string``; it tries the
-passphrase passed in first, and then it cancels.
-
-All versions need access to a ``RandomNumberGenerator`` in order to
-perform probabilistic tests on the loaded key material.
-
-After loading a key, you can use ``dynamic_cast`` to find out what
-operations it supports, and use it appropriately. Remember to
-``delete`` the object once you are done with it.