The documentation for libgcrypt says:
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)))
...and...
p-mpi
RSA secret prime p.
q-mpi
RSA secret prime q with p < q.
u-mpi
Multiplicative inverse u = p^{-1} mod q.
...and...
Note that OpenSSL uses slighly different parameters: q < p and u = q^{-1} mod 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);
}
If in one p is the smaller prime and in the other q is the smaller prime, and given that the two equations are identical save for exchanging p and q, is it really necessary to have to recompute u? Is it not sufficient just to exchange p and q?
As a side question, I am curious why gcrypt doesn't use the same values as the PKCS#1 encoding:
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER, -- n
publicExponent INTEGER, -- e
privateExponent INTEGER, -- d
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER, -- (inverse of q) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}
o modulus is the RSA modulus n.
o publicExponent is the RSA public exponent e.
o privateExponent is the RSA private exponent d.
o prime1 is the prime factor p of n.
o prime2 is the prime factor q of n.
o exponent1 is d mod (p - 1).
o exponent2 is d mod (q - 1).
o coefficient is the CRT coefficient q^(-1) mod p.
The answer is that recalculating "u" is irrelevant. Simply swap the usage of "p" and "q" and it all works.
As a general comment on gcrypt, the asymmetric cryptography APIs are terrible. Truly abysmal.
There is no support for loading keys from file in ANY format.
There is no support to simply encrypt/decrypt a buffer. Instead you need to convert the buffer to an MPI before you can then convert it to an S-expression. After encryption you need to unwind the resulting S-expression to get the right piece and then call yet another function to get at the data itself. Decryption requires slightly more complexity in creating the S-expression to decrypt from a buffer, but retrieving the data is only one function call.
The parameters to the S-expression for the private key do not match the values in standard PKCS#1 format (although as covered by this question and answer, conversion is fairly easy). Why not?
During the course of my investigations I discovered that there is another GNU encryption library. Why they maintain two I have no idea. The other is called "nettle" and is much better:
*) It uses the GMP library for multi-precision integers, rather than having its own type as gcrypt does (mpi_t).
*) It supports loading keys from files in a variety of formats (I used it as the basis for my own code to load keys for use with gcrypt).
*) It supports conversion from various formats (PEM->DER, DER->Sexp).
*) It supports a variety of symmetric encryption algorithms and modes.
*) It supports asymmetric encryption/decryption/signing/verification.
I didn't actually use it so I cannot really comment on the APIs usability, but from what I saw it was generally much much better.
I don't really know the background on nettle, but I do wonder if it was created simply because gcrypt's API is so awful and they would rather start over than enhance gcrypt.