[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6. Public Key cryptography

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.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.1 Available algorithms

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] [ ? ]

6.2 Used S-expressions

Libgcrypt's API for asymmetric cryptography is based on data structures called S-expressions (see http://people.csail.mit.edu/rivest/sexp.html) 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 examples. Note that words in uppercase indicate parameters whereas lowercase words are literals.

Note that all MPI (multi-precision-integers) values are expected to be in GCRYMPI_FMT_USG format. An easy way to create S-expressions is by using gcry_sexp_build which allows to pass a string with printf-like escapes to insert MPI values.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.2.1 RSA key parameters

An RSA private key is described by this S-expression:

 
(private-key
  (rsa
    (n n-mpi)
    (e e-mpi)
    (d d-mpi)
    (p p-mpi)
    (q q-mpi)
    (u u-mpi)))

An RSA public key is described by this S-expression:

 
(public-key
  (rsa
    (n n-mpi)
    (e e-mpi)))
n-mpi

RSA public modulus n.

e-mpi

RSA public exponent e.

d-mpi

RSA secret exponent d = e^{-1 \bmod (p-1)(q-1).

p-mpi

RSA secret prime p.

q-mpi

RSA secret prime q with p < q.

u-mpi

Multiplicative inverse u = p^{-1 \bmod q.

For signing and decryption the parameters (p, q, u) are optional but greatly improve the performance. Either all of these optional parameters must be given or none of them. They are mandatory for gcry_pk_testkey.

Note that OpenSSL uses slighly different parameters: q < p and u = q^{-1 \bmod p. To use these parameters you will need to swap the values and recompute u. Here is example code to do this:

 
  if (gcry_mpi_cmp (p, q) > 0)
    {
      gcry_mpi_swap (p, q);
      gcry_mpi_invm (u, p, q);
    }

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.2.2 DSA key parameters

A DSA private key is described by this S-expression:

 
(private-key
  (dsa
    (p p-mpi)
    (q q-mpi)
    (g g-mpi)
    (y y-mpi)
    (x x-mpi)))
p-mpi

DSA prime p.

q-mpi

DSA group order q (which is a prime divisor of p-1).

g-mpi

DSA group generator g.

y-mpi

DSA public key value y = g^x \bmod p.

x-mpi

DSA secret exponent x.

The public key is similar with "private-key" replaced by "public-key" and no x-mpi.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.2.3 ECC key parameters

An ECC private key is described by this S-expression:

 
(private-key
  (ecc
    (p p-mpi)
    (a a-mpi)
    (b b-mpi)
    (g g-point)
    (n n-mpi)
    (q q-point)
    (d d-mpi)))
p-mpi

Prime specifying the field GF(p).

a-mpi
b-mpi

The two coefficients of the Weierstrass equation y^2 = x^3 + ax + b

g-point

Base point g.

n-mpi

Order of g

q-point

The point representing the public key Q = dP.

d-mpi

The private key d

All point values are encoded in standard format; Libgcrypt does currently only support uncompressed points, thus the first byte needs to be 0x04.

The public key is similar with "private-key" replaced by "public-key" and no d-mpi.

If the domain parameters are well-known, the name of this curve may be used. For example

 
(private-key
  (ecc
    (curve "NIST P-192")
    (q q-point)
    (d d-mpi)))

The curve parameter may be given in any case and is used to replace missing parameters.

Currently implemented curves are:

NIST P-192
1.2.840.10045.3.1.1
prime192v1
secp192r1

The NIST 192 bit curve, its OID, X9.62 and SECP aliases.

NIST P-224
secp224r1

The NIST 224 bit curve and its SECP alias.

NIST P-256
1.2.840.10045.3.1.7
prime256v1
secp256r1

The NIST 256 bit curve, its OID, X9.62 and SECP aliases.

NIST P-384
secp384r1

The NIST 384 bit curve and its SECP alias.

NIST P-521
secp521r1

The NIST 521 bit curve and its SECP alias.

As usual the OIDs may optionally be prefixed with the string OID. or oid..


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.3 Public key modules

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.

Data type: gcry_pk_spec_t

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.

Data type: gcry_pk_generate_t

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)

Data type: gcry_pk_check_secret_key_t

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)

Data type: gcry_pk_encrypt_t

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)

Data type: gcry_pk_decrypt_t

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)

Data type: gcry_pk_sign_t

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)

Data type: gcry_pk_verify_t

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)

Data type: gcry_pk_get_nbits_t

Type for the `get_nbits' function, defined as: unsigned (*gcry_pk_get_nbits_t) (int algo, gcry_mpi_t *pkey)

Function: gcry_error_t gcry_pk_register (gcry_pk_spec_t *pubkey, unsigned int *algorithm_id, gcry_module_t *module)

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.

Function: void gcry_pk_unregister (gcry_module_t module)

Unregister the public key module identified by module, which must have been registered with gcry_pk_register.

Function: gcry_error_t gcry_pk_list (int *list, int *list_length)

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] [ ? ]

6.4 Cryptographic Functions

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:

pkcs1

Use PKCS#1 block type 2 padding.

no-blinding

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:

Function: gcry_error_t gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t data, gcry_sexp_t pkey)

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 new S-expression with the encrypted result is allocated and assigned 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.

Function: gcry_error_t gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t data, gcry_sexp_t skey)

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:

Function: gcry_error_t gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t data, gcry_sexp_t skey)

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 "sha256" or "sha1". 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:

Function: gcry_error_t gcry_pk_verify (gcry_sexp_t sig, gcry_sexp_t data, gcry_sexp_t pkey)

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] [ ? ]

6.5 General public-key related Functions

A couple of utility functions are available to retrieve the length of the key, map algorithm identifiers and perform sanity checks:

Function: const char * gcry_pk_algo_name (int algo)

Map the public key algorithm id algo to a string representation of the algorithm name. For unknown algorithms this functions returns the string "?". This function should not be used to test for the availability of an algorithm.

Function: int gcry_pk_map_name (const char *name)

Map the algorithm name to a public key algorithm Id. Returns 0 if the algorithm name is not known.

Function: int gcry_pk_test_algo (int algo)

Return 0 if the public key algorithm algo is available for use. Note that this is implemented as a macro.

Function: unsigned int gcry_pk_get_nbits (gcry_sexp_t key)

Return what is commonly referred as the key length for the given public or private in key.

Function: unsigned char * gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)

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

Function: gcry_error_t gcry_pk_testkey (gcry_sexp_t key)

Return zero if the private key key is `sane', an error code otherwise. Note that it is not possible to check the `saneness' of a public key.

Function: gcry_error_t gcry_pk_algo_info (int algo, int what, void *buffer, size_t *nbytes)

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

Unless you need to test for the allowed usage, it is in general better to use the macro gcry_pk_test_algo instead.

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.

Function: gcry_error_t gcry_pk_ctl (int cmd, void *buffer, size_t buflen)

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 to generate public key pairs:

Function: gcry_error_t gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t parms)

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 to create an 2048 bit RSA key:

 
(genkey
  (rsa
    (nbits 4:2048)))

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. The value should be a multiple of 8.

curve name

For ECC a named curve may be used instead of giving the number of requested bits. This allows to request a specific curve to override a default selection Libgcrypt would have taken if nbits has been given. The available names are listed with the description of the ECC public key parameters.

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:

`0'

Use a secure and fast value. This is currently the number 41.

`1'

Use a value as required by some crypto policies. This is currently the number 65537.

`2'

Reserved

`> 2'

Use the given value.

If this parameter is not used, Libgcrypt uses for historic reasons 65537.

qbits

This is only meanigful for DSA keys. If it is given the DSA key is generated with a Q parameyer of this size. If it is not given or zero Q is deduced from NBITS in this way:

`512 <= N <= 1024'

Q = 160

`N = 2048'

Q = 224

`N = 3072'

Q = 256

`N = 7680'

Q = 384

`N = 15360'

Q = 512

Note that in this case only the values for N, as given in the table, are allowed. When specifying Q all values of N in the range 512 to 15680 are valid as long as they are multiples of 8.

transient-key

This is only meaningful for RSA and DSA keys. This is a flag with no value. If given the RSA or DSA key is created using a faster and a somewhat less secure random number generator. This flag may be used for keys which are only used for a short time and do not require full cryptographic strength.

domain

This is only meaningful for DLP algorithms. If specified keys are generated with domain parameters taken from this list. The exact format of this parameter depends on the actual algorithm. It is currently only implemented for DSA using this format:

 
(genkey
  (dsa
    (domain
      (p p-mpi)
      (q q-mpi)
      (g q-mpi))))

nbits and qbits may not be specified because they are derived from the domain parameters.

derive-parms

This is currently only implemented for RSA and DSA keys. It is not allowed to use this together with a domain specification. If given, it is used to derive the keys using the given parameters.

If given for an RSA key the X9.31 key generation algorithm is used even if libgcrypt is not in FIPS mode. If given for a DSA key, the FIPS 186 algorithm is used even if libgcrypt is not in FIPS mode.

 
(genkey
  (rsa
    (nbits 4:1024)
    (rsa-use-e 1:3)
    (derive-parms
      (Xp1 #1A1916DDB29B4EB7EB6732E128#)
      (Xp2 #192E8AAC41C576C822D93EA433#)
      (Xp  #D8CD81F035EC57EFE822955149D3BFF70C53520D
            769D6D76646C7A792E16EBD89FE6FC5B605A6493
            39DFC925A86A4C6D150B71B9EEA02D68885F5009
            B98BD984#)
      (Xq1 #1A5CF72EE770DE50CB09ACCEA9#)
      (Xq2 #134E4CAA16D2350A21D775C404#)
      (Xq  #CC1092495D867E64065DEE3E7955F2EBC7D47A2D
            7C9953388F97DDDC3E1CA19C35CA659EDC2FC325
            6D29C2627479C086A699A49C4C9CEE7EF7BD1B34
            321DE34A#))))
 
(genkey
  (dsa
    (nbits 4:1024)
    (derive-parms
      (seed seed-mpi))))
use-x931

Force the use of the ANSI X9.31 key generation algorithm instead of the default algorithm. This flag is only meaningful for RSA and usually not required. Note that this algorithm is implicitly used if either derive-parms is given or Libgcrypt is in FIPS mode.

use-fips186

Force the use of the FIPS 186 key generation algorithm instead of the default algorithm. This flag is only meaningful for DSA and usually not required. Note that this algorithm is implicitly used if either derive-parms is given or Libgcrypt is in FIPS mode. As of now FIPS 186-2 is implemented; after the approval of FIPS 186-3 the code will be changed to implement 186-3.

use-fips186-2

Force the use of the FIPS 186-2 key generation algorithm instead of the default algorithm. This algorithm is slighlty different from FIPS 186-3 and allows only 1024 bit keys. This flag is only meaningful for DSA and only required for FIPS testing backward compatibility.

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 and only available if the key generation algorithm provides them.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.6 Alternative Public Key Interface

This section documents the alternative interface to asymmetric cryptography (ac) that is not based on S-expressions, but on native C data structures. As opposed to the pk interface described in the former chapter, this one follows an open/use/close paradigm like other building blocks of the library.

This interface has a few known problems; most noteworthy an inherent tendency to leak memory. It might not be available in forthcoming versions of Libgcrypt.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.6.1 Available asymmetric algorithms

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.

Data type: gcry_ac_id_t

The following constants are defined for this type:

GCRY_AC_RSA

Rivest-Shamir-Adleman

GCRY_AC_DSA

Digital Signature Algorithm

GCRY_AC_ELG

Elgamal

GCRY_AC_ELG_E

Elgamal, encryption only.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.6.2 Working with sets of data

In the context of this interface the term `data set' refers to a list of `named MPI values' that is used by functions performing cryptographic operations; a named MPI value is a an MPI value, associated with a label.

Such data sets are used for representing keys, since keys simply consist of a variable amount of numbers. Furthermore some functions return data sets to the caller that are to be provided to other functions.

This section documents the data types, symbols and functions that are relevant for working with data sets.

Data type: gcry_ac_data_t

A single data set.

The following flags are supported:

GCRY_AC_FLAG_DEALLOC

Used for storing data in a data set. If given, the data will be released by the library. Note that whenever one of the ac functions is about to release objects because of this flag, the objects are expected to be stored in memory allocated through the Libgcrypt memory management. In other words: gcry_free() is used instead of free().

GCRY_AC_FLAG_COPY

Used for storing/retrieving data in/from a data set. If given, the library will create copies of the provided/contained data, which will then be given to the user/associated with the data set.

Function: gcry_error_t gcry_ac_data_new (gcry_ac_data_t *data)

Creates a new, empty data set and stores it in data.

Function: void gcry_ac_data_destroy (gcry_ac_data_t data)

Destroys the data set data.

Function: gcry_error_t gcry_ac_data_set (gcry_ac_data_t data, unsigned int flags, char *name, gcry_mpi_t mpi)

Add the value mpi to data with the label name. If flags contains GCRY_AC_FLAG_COPY, the data set will contain copies of name and mpi. If flags contains GCRY_AC_FLAG_DEALLOC or GCRY_AC_FLAG_COPY, the values contained in the data set will be deallocated when they are to be removed from the data set.

Function: gcry_error_t gcry_ac_data_copy (gcry_ac_data_t *data_cp, gcry_ac_data_t data)

Create a copy of the data set data and store it in data_cp. FIXME: exact semantics undefined.

Function: unsigned int gcry_ac_data_length (gcry_ac_data_t data)

Returns the number of named MPI values inside of the data set data.

Function: gcry_error_t gcry_ac_data_get_name (gcry_ac_data_t data, unsigned int flags, char *name, gcry_mpi_t *mpi)

Store the value labelled with name found in data in mpi. If flags contains GCRY_AC_FLAG_COPY, store a copy of the mpi value contained in the data set. mpi may be NULL (this might be useful for checking the existence of an MPI with extracting it).

Function: gcry_error_t gcry_ac_data_get_index (gcry_ac_data_t data, unsigned int flags, unsigned int index, const char **name, gcry_mpi_t *mpi)

Stores in name and mpi the named mpi value contained in the data set data with the index idx. If flags contains GCRY_AC_FLAG_COPY, store copies of the values contained in the data set. name or mpi may be NULL.

Function: void gcry_ac_data_clear (gcry_ac_data_t data)

Destroys any values contained in the data set data.

Function: gcry_error_t gcry_ac_data_to_sexp (gcry_ac_data_t data, gcry_sexp_t *sexp, const char **identifiers)

This function converts the data set data into a newly created S-Expression, which is to be stored in sexp; identifiers is a NULL terminated list of C strings, which specifies the structure of the S-Expression.

Example:

If identifiers is a list of pointers to the strings "foo" and "bar" and if data is a data set containing the values "val1 = 0x01" and "val2 = 0x02", then the resulting S-Expression will look like this: (foo (bar ((val1 0x01) (val2 0x02))).

Function: gcry_error gcry_ac_data_from_sexp (gcry_ac_data_t *data, gcry_sexp_t sexp, const char **identifiers)

This function converts the S-Expression sexp into a newly created data set, which is to be stored in data; identifiers is a NULL terminated list of C strings, which specifies the structure of the S-Expression. If the list of identifiers does not match the structure of the S-Expression, the function fails.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.6.3 Working with IO objects

Note: IO objects are currently only used in the context of message encoding/decoding and encryption/signature schemes.

Data type: gcry_ac_io_t

gcry_ac_io_t is the type to be used for IO objects.

IO objects provide an uniform IO layer on top of different underlying IO mechanisms; either they can be used for providing data to the library (mode is GCRY_AC_IO_READABLE) or they can be used for retrieving data from the library (mode is GCRY_AC_IO_WRITABLE).

IO object need to be initialized by calling on of the following functions:

Function: void gcry_ac_io_init (gcry_ac_io_t *ac_io, gcry_ac_io_mode_t mode, gcry_ac_io_type_t type, ...);

Initialize ac_io according to mode, type and the variable list of arguments. The list of variable arguments to specify depends on the given type.

Function: void gcry_ac_io_init_va (gcry_ac_io_t *ac_io, gcry_ac_io_mode_t mode, gcry_ac_io_type_t type, va_list ap);

Initialize ac_io according to mode, type and the variable list of arguments ap. The list of variable arguments to specify depends on the given type.

The following types of IO objects exist:

GCRY_AC_IO_STRING

In case of GCRY_AC_IO_READABLE the IO object will provide data from a memory string. Arguments to specify at initialization time:

unsigned char *

Pointer to the beginning of the memory string

size_t

Size of the memory string

In case of GCRY_AC_IO_WRITABLE the object will store retrieved data in a newly allocated memory string. Arguments to specify at initialization time:

unsigned char **

Pointer to address, at which the pointer to the newly created memory string is to be stored

size_t *

Pointer to address, at which the size of the newly created memory string is to be stored

GCRY_AC_IO_CALLBACK

In case of GCRY_AC_IO_READABLE the object will forward read requests to a provided callback function. Arguments to specify at initialization time:

gcry_ac_data_read_cb_t

Callback function to use

void *

Opaque argument to provide to the callback function

In case of GCRY_AC_IO_WRITABLE the object will forward write requests to a provided callback function. Arguments to specify at initialization time:

gcry_ac_data_write_cb_t

Callback function to use

void *

Opaque argument to provide to the callback function


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.6.4 Working with handles

In order to use an algorithm, an according handle must be created. This is done using the following function:

Function: gcry_error_t gcry_ac_open (gcry_ac_handle_t *handle, int algorithm, int flags)

Creates a new handle for the algorithm algorithm and stores it in handle. flags is not used currently.

algorithm must be a valid algorithm ID, see See section Available asymmetric algorithms, for a list of supported algorithms and the according constants. Besides using the listed constants directly, the functions gcry_pk_name_to_id may be used to convert the textual name of an algorithm into the according numeric ID.

Function: void gcry_ac_close (gcry_ac_handle_t handle)

Destroys the handle handle.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.6.5 Working with keys

Data type: gcry_ac_key_type_t

Defined constants:

GCRY_AC_KEY_SECRET

Specifies a secret key.

GCRY_AC_KEY_PUBLIC

Specifies a public key.

Data type: gcry_ac_key_t

This type represents a single `key', either a secret one or a public one.

Data type: gcry_ac_key_pair_t

This type represents a `key pair' containing a secret and a public key.

Key data structures can be created in two different ways; a new key pair can be generated, resulting in ready-to-use key. Alternatively a key can be initialized from a given data set.

Function: gcry_error_t gcry_ac_key_init (gcry_ac_key_t *key, gcry_ac_handle_t handle, gcry_ac_key_type_t type, gcry_ac_data_t data)

Creates a new key of type type, consisting of the MPI values contained in the data set data and stores it in key.

Function: gcry_error_t gcry_ac_key_pair_generate (gcry_ac_handle_t handle, unsigned int nbits, void *key_spec, gcry_ac_key_pair_t *key_pair, gcry_mpi_t **misc_data)

Generates a new key pair via the handle handle of NBITS bits and stores it in key_pair.

In case non-standard settings are wanted, a pointer to a structure of type gcry_ac_key_spec_<algorithm>_t, matching the selected algorithm, can be given as key_spec. misc_data is not used yet. Such a structure does only exist for RSA. A description of the members of the supported structures follows.

gcry_ac_key_spec_rsa_t
gcry_mpi_t e

Generate the key pair using a special e. The value of e has the following meanings:

= 0

Let Libgcrypt decide what exponent should be used.

= 1

Request the use of a "secure" exponent; this is required by some specification to be 65537.

> 2

Try starting at this value until a working exponent is found. Note that the current implementation leaks some information about the private key because the incrementation used is not randomized. Thus, this function will be changed in the future to return a random exponent of the given size.

Example code:

 
{
  gcry_ac_key_pair_t key_pair;
  gcry_ac_key_spec_rsa_t rsa_spec;

  rsa_spec.e = gcry_mpi_new (0);
  gcry_mpi_set_ui (rsa_spec.e, 1);

  err = gcry_ac_open  (&handle, GCRY_AC_RSA, 0);
  assert (! err);

  err = gcry_ac_key_pair_generate (handle, 1024, &rsa_spec,
                                   &key_pair, NULL);
  assert (! err);
}
Function: gcry_ac_key_t gcry_ac_key_pair_extract (gcry_ac_key_pair_t key_pair, gcry_ac_key_type_t which)

Returns the key of type which out of the key pair key_pair.

Function: void gcry_ac_key_destroy (gcry_ac_key_t key)

Destroys the key key.

Function: void gcry_ac_key_pair_destroy (gcry_ac_key_pair_t key_pair)

Destroys the key pair key_pair.

Function: gcry_ac_data_t gcry_ac_key_data_get (gcry_ac_key_t key)

Returns the data set contained in the key key.

Function: gcry_error_t gcry_ac_key_test (gcry_ac_handle_t handle, gcry_ac_key_t key)

Verifies that the private key key is sane via handle.

Function: gcry_error_t gcry_ac_key_get_nbits (gcry_ac_handle_t handle, gcry_ac_key_t key, unsigned int *nbits)

Stores the number of bits of the key key in nbits via handle.

Function: gcry_error_t gcry_ac_key_get_grip (gcry_ac_handle_t handle, gcry_ac_key_t key, unsigned char *key_grip)

Writes the 20 byte long key grip of the key key to key_grip via handle.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.6.6 Using cryptographic functions

The following flags might be relevant:

GCRY_AC_FLAG_NO_BLINDING

Disable any blinding, which might be supported by the chosen algorithm; blinding is the default.

There exist two kinds of cryptographic functions available through the ac interface: primitives, and high-level functions.

Primitives deal with MPIs (data sets) directly; what they provide is direct access to the cryptographic operations provided by an algorithm implementation.

High-level functions deal with octet strings, according to a specified "scheme". Schemes make use of "encoding methods", which are responsible for converting the provided octet strings into MPIs, which are then forwared to the cryptographic primitives. Since schemes are to be used for a special purpose in order to achieve a particular security goal, there exist "encryption schemes" and "signature schemes". Encoding methods can be used seperately or implicitly through schemes.

What follows is a description of the cryptographic primitives.

Function: gcry_error_t gcry_ac_data_encrypt (gcry_ac_handle_t handle, unsigned int flags, gcry_ac_key_t key, gcry_mpi_t data_plain, gcry_ac_data_t *data_encrypted)

Encrypts the plain text MPI value data_plain with the key public key under the control of the flags flags and stores the resulting data set into data_encrypted.

Function: gcry_error_t gcry_ac_data_decrypt (gcry_ac_handle_t handle, unsigned int flags, gcry_ac_key_t key, gcry_mpi_t *data_plain, gcry_ac_data_t data_encrypted)

Decrypts the encrypted data contained in the data set data_encrypted with the secret key KEY under the control of the flags flags and stores the resulting plain text MPI value in DATA_PLAIN.

Function: gcry_error_t gcry_ac_data_sign (gcry_ac_handle_t handle, gcry_ac_key_t key, gcry_mpi_t data, gcry_ac_data_t *data_signature)

Signs the data contained in data with the secret key key and stores the resulting signature in the data set data_signature.

Function: gcry_error_t gcry_ac_data_verify (gcry_ac_handle_t handle, gcry_ac_key_t key, gcry_mpi_t data, gcry_ac_data_t data_signature)

Verifies that the signature contained in the data set data_signature is indeed the result of signing the data contained in data with the secret key belonging to the public key key.

What follows is a description of the high-level functions.

The type "gcry_ac_em_t" is used for specifying encoding methods; the following methods are supported:

GCRY_AC_EME_PKCS_V1_5

PKCS-V1_5 Encoding Method for Encryption. Options must be provided through a pointer to a correctly initialized object of type gcry_ac_eme_pkcs_v1_5_t.

GCRY_AC_EMSA_PKCS_V1_5

PKCS-V1_5 Encoding Method for Signatures with Appendix. Options must be provided through a pointer to a correctly initialized object of type gcry_ac_emsa_pkcs_v1_5_t.

Option structure types:

gcry_ac_eme_pkcs_v1_5_t
gcry_ac_key_t key
gcry_ac_handle_t handle
gcry_ac_emsa_pkcs_v1_5_t
gcry_md_algo_t md
size_t em_n

Encoding methods can be used directly through the following functions:

Function: gcry_error_t gcry_ac_data_encode (gcry_ac_em_t method, unsigned int flags, void *options, unsigned char *m, size_t m_n, unsigned char **em, size_t *em_n)

Encodes the message contained in m of size m_n according to method, flags and options. The newly created encoded message is stored in em and em_n.

Function: gcry_error_t gcry_ac_data_decode (gcry_ac_em_t method, unsigned int flags, void *options, unsigned char *em, size_t em_n, unsigned char **m, size_t *m_n)

Decodes the message contained in em of size em_n according to method, flags and options. The newly created decoded message is stored in m and m_n.

The type "gcry_ac_scheme_t" is used for specifying schemes; the following schemes are supported:

GCRY_AC_ES_PKCS_V1_5

PKCS-V1_5 Encryption Scheme. No options can be provided.

GCRY_AC_SSA_PKCS_V1_5

PKCS-V1_5 Signature Scheme (with Appendix). Options can be provided through a pointer to a correctly initialized object of type gcry_ac_ssa_pkcs_v1_5_t.

Option structure types:

gcry_ac_ssa_pkcs_v1_5_t
gcry_md_algo_t md

The functions implementing schemes:

Function: gcry_error_t gcry_ac_data_encrypt_scheme (gcry_ac_handle_t handle, gcry_ac_scheme_t scheme, unsigned int flags, void *opts, gcry_ac_key_t key, gcry_ac_io_t *io_message, gcry_ac_io_t *io_cipher)

Encrypts the plain text readable from io_message through handle with the public key key according to scheme, flags and opts. If opts is not NULL, it has to be a pointer to a structure specific to the chosen scheme (gcry_ac_es_*_t). The encrypted message is written to io_cipher.

Function: gcry_error_t gcry_ac_data_decrypt_scheme (gcry_ac_handle_t handle, gcry_ac_scheme_t scheme, unsigned int flags, void *opts, gcry_ac_key_t key, gcry_ac_io_t *io_cipher, gcry_ac_io_t *io_message)

Decrypts the cipher text readable from io_cipher through handle with the secret key key according to scheme, flags and opts. If opts is not NULL, it has to be a pointer to a structure specific to the chosen scheme (gcry_ac_es_*_t). The decrypted message is written to io_message.

Function: gcry_error_t gcry_ac_data_sign_scheme (gcry_ac_handle_t handle, gcry_ac_scheme_t scheme, unsigned int flags, void *opts, gcry_ac_key_t key, gcry_ac_io_t *io_message, gcry_ac_io_t *io_signature)

Signs the message readable from io_message through handle with the secret key key according to scheme, flags and opts. If opts is not NULL, it has to be a pointer to a structure specific to the chosen scheme (gcry_ac_ssa_*_t). The signature is written to io_signature.

Function: gcry_error_t gcry_ac_data_verify_scheme (gcry_ac_handle_t handle, gcry_ac_scheme_t scheme, unsigned int flags, void *opts, gcry_ac_key_t key, gcry_ac_io_t *io_message, gcry_ac_io_t *io_signature)

Verifies through handle that the signature readable from io_signature is indeed the result of signing the message readable from io_message with the secret key belonging to the public key key according to scheme and opts. If opts is not NULL, it has to be an anonymous structure (gcry_ac_ssa_*_t) specific to the chosen scheme.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.6.7 Handle-independent functions

These two functions are deprecated; do not use them for new code.

Function: gcry_error_t gcry_ac_id_to_name (gcry_ac_id_t algorithm, const char **name)

Stores the textual representation of the algorithm whose id is given in algorithm in name. Deprecated; use gcry_pk_algo_name.

Function: gcry_error_t gcry_ac_name_to_id (const char *name, gcry_ac_id_t *algorithm)

Stores the numeric ID of the algorithm whose textual representation is contained in name in algorithm. Deprecated; use gcry_pk_map_name.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated on January, 20 2010 using texi2html 1.76.