[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Public key cryptography, also known as asymmetric cryptography, is an easy way for key management and to provide digital signatures. Libgcrypt provides two completely different interfaces to public key cryptography, this chapter explains the one based on S-expressions.
7.1 Available algorithms | Algorithms supported by the library. | |
7.2 Used S-expressions | Introduction into the used S-expression. | |
7.3 Public key modules | How to work with public key modules. | |
7.4 Cryptographic Functions | Functions for performing the cryptographic actions. | |
7.5 General public-key related Functions | General functions, not implementing any cryptography. |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Libgcrypt supports the RSA (Rivest-Shamir-Adleman) algorithms as well as DSA (Digital Signature Algorithm) and ElGamal. The versatile interface allows to add more algorithms in the future.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Libgcrypt's API for asymmetric cryptography is based on data structures called S-expressions (see XXXX) and does not work with contexts as most of the other building blocks of Libgcrypt do.
The following information are stored in S-expressions:
To describe how Libgcrypt expect keys, we use some examples. Note that words in uppercase indicate parameters whereas lowercase words are literals.
(private-key (dsa (p p-mpi) (q q-mpi) (g g-mpi) (y y-mpi) (x x-mpi))) |
This specifies a DSA private key with the following parameters:
DSA prime p.
DSA group order q (which is a prime divisor of p-1).
DSA group generator g.
DSA public key value y = g^x \bmod p.
DSA secret exponent x.
All the MPI values are expected to be in GCRYMPI_FMT_USG
format.
The public key is similar with "private-key" replaced by "public-key"
and no x-mpi.
An easy way to create such an S-expressions is by using
gcry_sexp_build
which allows to pass a string with printf-like
escapes to insert MPI values.
Here is an example for an RSA key:
(private-key (rsa (n n-mpi) (e e-mpi) (d d-mpi) (p p-mpi) (q q-mpi) (u u-mpi) |
with
RSA public modulus n.
RSA public exponent e.
RSA secret exponent d = e^{-1 \bmod (p-1)(q-1).
RSA secret prime p.
RSA secret prime q with q > p.
multiplicative inverse u = p^{-1 \bmod q.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Libgcrypt makes it possible to load additional `public key modules'; these public key algorithms can be used just like the algorithms that are built into the library directly. For an introduction into extension modules, see See section Modules.
This is the `module specification structure' needed for registering public key modules, which has to be filled in by the user before it can be used to register a module. It contains the following members:
const char *name
The primary name of this algorithm.
char **aliases
A list of strings that are `aliases' for the algorithm. The list must be terminated with a NULL element.
const char *elements_pkey
String containing the one-letter names of the MPI values contained in a public key.
const char *element_skey
String containing the one-letter names of the MPI values contained in a secret key.
const char *elements_enc
String containing the one-letter names of the MPI values that are the result of an encryption operation using this algorithm.
const char *elements_sig
String containing the one-letter names of the MPI values that are the result of a sign operation using this algorithm.
const char *elements_grip
String containing the one-letter names of the MPI values that are to be included in the `key grip'.
int use
The bitwise-OR of the following flags, depending on the abilities of the algorithm:
GCRY_PK_USAGE_SIGN
The algorithm supports signing and verifying of data.
GCRY_PK_USAGE_ENCR
The algorithm supports the encryption and decryption of data.
gcry_pk_generate_t generate
The function responsible for generating a new key pair. See below for a description of this type.
gcry_pk_check_secret_key_t check_secret_key
The function responsible for checking the sanity of a provided secret key. See below for a description of this type.
gcry_pk_encrypt_t encrypt
The function responsible for encrypting data. See below for a description of this type.
gcry_pk_decrypt_t decrypt
The function responsible for decrypting data. See below for a description of this type.
gcry_pk_sign_t sign
The function responsible for signing data. See below for a description of this type.
gcry_pk_verify_t verify
The function responsible for verifying that the provided signature matches the provided data. See below for a description of this type.
gcry_pk_get_nbits_t get_nbits
The function responsible for returning the number of bits of a provided key. See below for a description of this type.
Type for the `generate' function, defined as: gcry_err_code_t (*gcry_pk_generate_t) (int algo, unsigned int nbits, unsigned long use_e, gcry_mpi_t *skey, gcry_mpi_t **retfactors)
Type for the `check_secret_key' function, defined as: gcry_err_code_t (*gcry_pk_check_secret_key_t) (int algo, gcry_mpi_t *skey)
Type for the `encrypt' function, defined as: gcry_err_code_t (*gcry_pk_encrypt_t) (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *pkey, int flags)
Type for the `decrypt' function, defined as: gcry_err_code_t (*gcry_pk_decrypt_t) (int algo, gcry_mpi_t *result, gcry_mpi_t *data, gcry_mpi_t *skey, int flags)
Type for the `sign' function, defined as: gcry_err_code_t (*gcry_pk_sign_t) (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey)
Type for the `verify' function, defined as: gcry_err_code_t (*gcry_pk_verify_t) (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey, int (*cmp) (void *, gcry_mpi_t), void *opaquev)
Type for the `get_nbits' function, defined as: unsigned (*gcry_pk_get_nbits_t) (int algo, gcry_mpi_t *pkey)
Register a new public key module whose specification can be found in pubkey. On success, a new algorithm ID is stored in algorithm_id and a pointer representing this module is stored in module.
Unregister the public key module identified by module, which must have been registered with gcry_pk_register.
Get a list consisting of the IDs of the loaded pubkey modules. If list is zero, write the number of loaded pubkey modules to list_length and return. If list is non-zero, the first *list_length algorithm IDs are stored in list, which must be of according size. In case there are less pubkey modules than *list_length, *list_length is updated to the correct number.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Note, that we will in future allow to use keys without p,q and u specified and may also support other parameters for performance reasons.
Some functions operating on S-expressions support `flags', that influence the operation. These flags have to be listed in a sub-S-expression named `flags'; the following flags are known:
Use PKCS#1 block type 2 padding.
Do not use a technique called `blinding', which is used by default in order to prevent leaking of secret information. Blinding is only implemented by RSA, but it might be implemented by other algorithms in the future as well, when necessary.
Now that we know the key basics, we can carry on and explain how to encrypt and decrypt data. In almost all cases the data is a random session key which is in turn used for the actual encryption of the real data. There are 2 functions to do this:
Obviously a public key must be provided for encryption. It is expected as an appropriate S-expression (see above) in pkey. The data to be encrypted can either be in the simple old format, which is a very simple S-expression consisting only of one MPI, or it may be a more complex S-expression which also allows to specify flags for operation, like e.g. padding rules.
If you don't want to let Libgcrypt handle the padding, you must pass an appropriate MPI using this expression for data:
(data (flags raw) (value mpi)) |
This has the same semantics as the old style MPI only way. MPI is the actual data, already padded appropriate for your protocol. Most systems however use PKCS#1 padding and so you can use this S-expression for data:
(data (flags pkcs1) (value block)) |
Here, the "flags" list has the "pkcs1" flag which let the function know that it should provide PKCS#1 block type 2 padding. The actual data to be encrypted is passed as a string of octets in block. The function checks that this data actually can be used with the given key, does the padding and encrypts it.
If the function could successfully perform the encryption, the return
value will be 0 and a a new S-expression with the encrypted result is
allocated and assign to the variable at the address of r_ciph.
The caller is responsible to release this value using
gcry_sexp_release
. In case of an error, an error code is
returned and r_ciph will be set to NULL
.
The returned S-expression has this format when used with RSA:
(enc-val (rsa (a a-mpi))) |
Where a-mpi is an MPI with the result of the RSA operation. When using the ElGamal algorithm, the return value will have this format:
(enc-val (elg (a a-mpi) (b b-mpi))) |
Where a-mpi and b-mpi are MPIs with the result of the ElGamal encryption operation.
Obviously a private key must be provided for decryption. It is expected
as an appropriate S-expression (see above) in skey. The data to
be decrypted must match the format of the result as returned by
gcry_pk_encrypt
, but should be enlarged with a flags
element:
(enc-val (flags) (elg (a a-mpi) (b b-mpi))) |
Note, that this function currently does not know of any padding methods and the caller must do any un-padding on his own.
The function returns 0 on success or an error code. The variable at the
address of r_plain will be set to NULL on error or receive the
decrypted value on success. The format of r_plain is a
simple S-expression part (i.e. not a valid one) with just one MPI if
there was no flags
element in data; if at least an empty
flags
is passed in data, the format is:
(value plaintext) |
Another operation commonly performed using public key cryptography is signing data. In some sense this is even more important than encryption because digital signatures are an important instrument for key management. Libgcrypt supports digital signatures using 2 functions, similar to the encryption functions:
This function creates a digital signature for data using the private key skey and place it into the variable at the address of r_sig. data may either be the simple old style S-expression with just one MPI or a modern and more versatile S-expression which allows to let Libgcrypt handle padding:
(data (flags pkcs1) (hash hash-algo block)) |
This example requests to sign the data in block after applying PKCS#1 block type 1 style padding. hash-algo is a string with the hash algorithm to be encoded into the signature, this may be any hash algorithm name as supported by Libgcrypt. Most likely, this will be "sha1", "rmd160" or "md5". It is obvious that the length of block must match the size of that message digests; the function checks that this and other constraints are valid.
If PKCS#1 padding is not required (because the caller does already provide a padded value), either the old format or better the following format should be used:
(data (flags raw) (value mpi)) |
Here, the data to be signed is directly given as an MPI.
The signature is returned as a newly allocated S-expression in r_sig using this format for RSA:
(sig-val (rsa (s s-mpi))) |
Where s-mpi is the result of the RSA sign operation. For DSA the S-expression returned is:
(sig-val (dsa (r r-mpi) (s s-mpi))) |
Where r-mpi and s-mpi are the result of the DSA sign operation. For ElGamal signing (which is slow, yields large numbers and probably is not as secure as the other algorithms), the same format is used with "elg" replacing "dsa".
The operation most commonly used is definitely the verification of a signature. Libgcrypt provides this function:
This is used to check whether the signature sig matches the
data. The public key pkey must be provided to perform this
verification. This function is similar in its parameters to
gcry_pk_sign
with the exceptions that the public key is used
instead of the private key and that no signature is created but a
signature, in a format as created by gcry_pk_sign
, is passed to
the function in sig.
The result is 0 for success (i.e. the data matches the signature), or an
error code where the most relevant code is GCRYERR_BAD_SIGNATURE
to indicate that the signature does not match the provided data.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A couple of utility functions are available to retrieve the length of the key, map algorithm identifiers and perform sanity checks:
Map the public key algorithm id algo to a string representation of the algorithm name. For unknown algorithms this functions returns an empty string.
Map the algorithm name to a public key algorithm Id. Returns 0 if the algorithm name is not known.
Return 0 if the public key algorithm algo is available for use. Note, that this is implemented as a macro.
Return what is commonly referred as the key length for the given public or private in key.
Return the so called "keygrip" which is the SHA-1 hash of the public key
parameters expressed in a way depended on the algorithm. array
must either provide space for 20 bytes or NULL;
. In the latter
case a newly allocated array of that size is returned. On success a
pointer to the newly allocated space or to array is returned.
NULL
is returned to indicate an error which is most likely an unknown
algorithm or one where a "keygrip" has not yet been defined.
The function accepts public or secret keys in key.
Return zero if the private key key is `sane', an error code otherwise. Note, that it is not possible to chek the `saneness' of a public key.
Depending on the value of what return various information about
the public key algorithm with the id algo. Note, that the
function returns -1
on error and the actual error code must be
retrieved using the function gcry_errno
. The currently defined
values for what are:
GCRYCTL_TEST_ALGO:
Return 0 when the specified algorithm is available for use.
buffer must be NULL
, nbytes may be passed as
NULL
or point to a variable with the required usage of the
algorithm. This may be 0 for "don't care" or the bit-wise OR of these
flags:
GCRY_PK_USAGE_SIGN
Algorithm is usable for signing.
GCRY_PK_USAGE_ENCR
Algorithm is usable for encryption.
GCRYCTL_GET_ALGO_USAGE:
Return the usage flags for the given algorithm. An invalid algorithm return 0. Disabled algorithms are ignored here because we want to know whether the algorithm is at all capable of a certain usage.
GCRYCTL_GET_ALGO_NPKEY
Return the number of elements the public key for algorithm algo consist of. Return 0 for an unknown algorithm.
GCRYCTL_GET_ALGO_NSKEY
Return the number of elements the private key for algorithm algo consist of. Note that this value is always larger than that of the public key. Return 0 for an unknown algorithm.
GCRYCTL_GET_ALGO_NSIGN
Return the number of elements a signature created with the algorithm algo consists of. Return 0 for an unknown algorithm or for an algorithm not capable of creating signatures.
GCRYCTL_GET_ALGO_NENC
Return the number of elements a encrypted message created with the algorithm algo consists of. Return 0 for an unknown algorithm or for an algorithm not capable of encryption.
Please note that parameters not required should be passed as NULL
.
This is a general purpose function to perform certain control operations. cmd controls what is to be done. The return value is 0 for success or an error code. Currently supported values for cmd are:
GCRYCTL_DISABLE_ALGO
Disable the algorithm given as an algorithm id in buffer.
buffer must point to an int
variable with the algorithm id
and buflen must have the value sizeof (int)
.
Libgcrypt also provides a function for generating public key pairs:
This function create a new public key pair using information given in
the S-expression parms and stores the private and the public key
in one new S-expression at the address given by r_key. In case of
an error, r_key is set to NULL
. The return code is 0 for
success or an error code otherwise.
Here is an example for parms for creating a 1024 bit RSA key:
(genkey (rsa (nbits 4:1024))) |
To create an ElGamal key, substitute "elg" for "rsa" and to create a DSA key use "dsa". Valid ranges for the key length depend on the algorithms; all commonly used key lengths are supported. Currently supported parameters are:
nbits
This is always required to specify the length of the key. The argument is a string with a number in C-notation.
rsa-use-e
This is only used with RSA to give a hint for the public exponent. The value will be used as a base to test for a usable exponent. Some values are special:
Use a secure and fast value. This is currently the number 41.
Use a secure value as required by some specification. This is currently the number 65537.
Reserved
If this parameter is not used, Libgcrypt uses for historic reasons 65537.
The key pair is returned in a format depending on the algorithm. Both private and public keys are returned in one container and may be accompanied by some miscellaneous information.
As an example, here is what the ElGamal key generation returns:
(key-data (public-key (elg (p p-mpi) (g g-mpi) (y y-mpi))) (private-key (elg (p p-mpi) (g g-mpi) (y y-mpi) (x x-mpi))) (misc-key-info (pm1-factors n1 n2 ... nn))) |
As you can see, some of the information is duplicated, but this provides an easy way to extract either the public or the private key. Note that the order of the elements is not defined, e.g. the private key may be stored before the public key. n1 n2 ... nn is a list of prime numbers used to composite p-mpi; this is in general not a very useful information.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated by Super-User on June, 10 2008 using texi2html 1.78.