[ < ] | [ > ] | [ << ] | [ 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:
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
[ < ] | [ > ] | [ << ] | [ 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 3.2 Modules.
const char *name
char **aliases
const char *elements_pkey
const char *element_skey
const char *elements_enc
const char *elements_sig
const char *elements_grip
int use
GCRY_PK_USAGE_SIGN
GCRY_PK_USAGE_ENCR
gcry_pk_generate_t generate
gcry_pk_check_secret_key_t check_secret_key
gcry_pk_encrypt_t encrypt
gcry_pk_decrypt_t decrypt
gcry_pk_sign_t sign
gcry_pk_verify_t verify
gcry_pk_get_nbits_t get_nbits
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 representhing this module is stored in module.
[ < ] | [ > ] | [ << ] | [ 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:
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:
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
GCRY_PK_USAGE_ENCR
GCRYCTL_GET_ALGO_USAGE:
GCRYCTL_GET_ALGO_NPKEY
GCRYCTL_GET_ALGO_NSKEY
GCRYCTL_GET_ALGO_NSIGN
GCRYCTL_GET_ALGO_NENC
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
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
rsa-use-e
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] | [ ? ] |