Next: Dedicated ECC Functions, Previous: Used S-expressions, Up: Public Key cryptography [Contents][Index]
Some functions operating on S-expressions support ‘flags’ to influence the operation. These flags have to be listed in a sub-S-expression named ‘flags’. Flag names are case-sensitive. The following flags are known:
comp
nocomp
If supported by the algorithm and curve, the comp
flag requests
that points are returned in compact (compressed) representation. The
nocomp
flag requests that points are returned with full
coordinates. The default depends on the the algorithm and curve. The
compact representation requires a small overhead before a point can be
used but halves the size of a public key to be conveyed. If
comp
is used with the “EdDSA” algorithm, the key generation
prefixes the public key with a 0x40
byte.
pkcs1
Use PKCS#1 block type 2 padding for encryption, block type 1 padding for signing.
oaep
Use RSA-OAEP padding for encryption.
pss
Use RSA-PSS padding for signing.
eddsa
Use the EdDSA scheme signing instead of the default ECDSA algorithm. Note that the EdDSA uses a special form of the public key.
rfc6979
For DSA and ECDSA use a deterministic scheme for the k parameter.
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.
param
For ECC key generation also return the domain parameters. For ECC signing and verification override default parameters by provided domain parameters of the public or private key.
transient-key
This flag is only meaningful for RSA, DSA, and ECC key generation. If given, the 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 or per-message and do not require full cryptographic strength.
no-keytest
This flag skips internal failsafe tests to assert that a generated key is properly working. It currently has an effect only for standard ECC key generation. It is mostly useful along with transient-key to achieve fastest ECC key generation.
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 key
generation and usually not required. Note that this algorithm is
implicitly used if either derive-parms
is given.
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 slightly 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.
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 RSA based 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.
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)))
This function does not remove padding from the data by default. To let Libgcrypt remove padding, give a hint in ‘flags’ telling which padding method was used when encrypting:
(flags padding-method)
Currently padding-method is either pkcs1
for PKCS#1 block
type 2 padding, or oaep
for RSA-OAEP padding.
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 "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.
For DSA the input data is expected in this format:
(data (flags raw) (value mpi))
Here, the data to be signed is directly given as an MPI. It is expect that this MPI is the hash value. For the standard DSA, using a MPI is not a problem in regard to leading zeroes because the hash value is directly used as an MPI. For better standard conformance it would be better to explicitly use a memory string (like with pkcs1) but that is currently not supported. However, for deterministic DSA as specified in RFC6979 this can’t be used. Instead the following input is expected.
(data (flags rfc6979) (hash hash-algo block))
Note that the provided hash-algo is used for the internal HMAC; it should match the hash-algo used to create block.
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"; for ECDSA signing, the same format is used with "ecdsa" replacing "dsa".
For the EdDSA algorithm (cf. Ed25515) the required input parameters are:
(data (flags eddsa) (hash-algo sha512) (value message))
Note that the message may be of any length; hashing is part of
the algorithm. Using a large data block for message is in
general not suggested; in that case the used protocol should better
require that a hash of the message is used as input to the EdDSA
algorithm. Note that for X.509 certificates message is the
tbsCertificate
part and in CMS message is the
signedAttrs
part; see RFC-8410 and RFC-8419.
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 GCRY_ERR_BAD_SIGNATURE
to indicate that the signature does not match the provided data.
Additionally, libgcrypt provides three functions for digital signatures. Those functions are useful when hashing computation should be closely combined with signature computation.
This function is a variant of gcry_pk_sign
which takes as
additional parameter hd, handle for hash, and an optional
context ctx. skey is a private key in S-expression. The
hash algorithm used by the handle needs to be enabled and input needs
to be supplied beforehand. data-tmpl specifies a template to
compose an S-expression to be signed. A template should include
"(hash %s %b)"
or "(hash ALGONAME %b)"
. For the former
case, "%s" is substituted by the string of algorithm of
gcry_md_get_algo (
hd)
and when gcry_md_read
is called, ALGO=0
is used internally. For the latter case,
hash algorithm by ALGONAME
is used when gcry_md_read
is
called internally. The hash handle must not yet been finalized; the
function takes a copy of the state and does a finalize on the copy.
The last argument, ctx, may be used for supplying nonce
externally. If no need, ctx should be passed as NULL
.
This function is a variant of gcry_pk_verify
which takes as
additional parameter hd, handle for hash, and an optional
context ctx. pkey is a public key in S-expression. See
gcry_pk_hash_sign
, for the explanation of handle for hash,
data-tmpl and ctx.
This function is used to allocate a new context for nonce, by memory
area pointed to by p to len bytes. This context can be
used when calling gcry_pk_hash_sign
or
gcry_pk_hash_verify
to supply nonce externally, instead of
generating internally.
On success the function returns 0 and stores the new context object at
r_ctx; this object eventually needs to be released
(see gcry_ctx_release). On error the function stores NULL
at
r_ctx and returns an error code.
Next: Dedicated ECC Functions, Previous: Used S-expressions, Up: Public Key cryptography [Contents][Index]