[sip-comm-dev] GSoC 09 - OTR - First term results (DSA Signature sign/verify using BC/libgcrypt)
Werner Dittmann
Werner.Dittmann at t-online.de
Tue Jul 14 20:27:47 CEST 2009
Goerge,
I'll take care of this. The author of libgcrypt is Werner Koch that I know
personally and I'm also subscribed to the libgcrypt list. To inform Werner
Koch I summarize your findings (you've done a great job here) and see what
he says to this issue.
As for the time being I agree with you to perform the sign/verify "manually"
and not using BC. I assume you have copied and modified the BC functions?
Can you upload the modifications to the otr4j source repository? Then I can
update mine here as well and we can work on the "modified very lightweigth
BC" library.
I'll keep you informed.
Regards,
Werner
Geekius Caesar schrieb:
> libgcrypt verifies the signature in cipher/dsa.c:verify.
>
> To test my hypothesis, if I modified BouncyCastle as to not use calculateE,
> and signature verification worked fine between SIP Communicator/otr4j/BC +
> Pidgin/libotr/libgcrypt.
>
> Still I would like a confirmation. Also if this is indeed the case we may
> have to generate/verify signatures without BouncyCastle, but within otr4j
> using the buggy process, at least until libgcrypt fixes the problem and the
> change has been incorporated in major linux distributions.
>
> On Tue, Jul 14, 2009 at 3:16 PM, Geekius Caesar <geekius.caesar at gmail.com>wrote:
>
>> Hello all,
>>
>> According to FIPS-186-3/p. DSA Signature Generation, (r,s) should be
>> generated as follows:
>>
>> *Let N be the bit length of q. Let min(N, outlen) denote the minimum of
>> the positive integers N and outlen, where outlen is the bit length of the
>> hash function output block. The signature of a message M consists of the
>> pair of numbers r and s that is computed according to the following
>> equations:
>>
>> r = (g^k mod p) mod q.
>> z = the leftmost min(N, outlen) bits of Hash(M).
>> s = (k^-1 (z + xr)) mod q.
>>
>> * BouncyCastle has method
>> org.bouncycastle.crypto.signers.DSASigner.class:calculateE that calculates z
>> and then calculates s.
>>
>> libgcrypt on the other hand seems to directly calculate s from M.
>>
>> If this is the case, I think this is a bug in libgcrypt, can anyone confirm
>> this?
>>
>> On Mon, Jul 13, 2009 at 4:27 AM, Geekius Caesar <geekius.caesar at gmail.com>wrote:
>>
>>> Hello Werner,
>>>
>>> Thank you for your reply, I have modified the code based on your
>>> suggestions. The problem now is that the calculated v is not equal with r
>>> (libgcrypt-1.4.1/cipher/dsa.c:380) so verification fails again.
>>>
>>> I use a custom build libgcrypt-1.4.1 and I have inserted the following
>>> calls in libgcrypt-1.4.1/cipher/dsa.c:verify
>>>
>>> log_mpidump (" r:", r);
>>> log_mpidump (" s:", s);
>>> log_mpidump (" hash:", hash);
>>> log_mpidump (" q:" , pkey->q);
>>> log_mpidump (" p:" , pkey->p);
>>> log_mpidump (" g:" , pkey->g);
>>> log_mpidump (" y:" , pkey->y);
>>>
>>> I do the same in otr4j (
>>> http://code.google.com/p/otr4j/source/browse/src/net/java/otr4j/StateMachine.java#787
>>> )
>>>
>>> This way I can verify r in otr4j/bc is the same as r in libotr/libgcrypt,
>>> s in otr4j/bc is the same as s in libotr/libgcrypt, e.t.c.
>>>
>>> I will insert more logging calls in libgcrypt/bouncycastle to see why
>>> exactly the resulting v is not equal with r.
>>>
>>> kind regards,
>>> George.
>>>
>>>
>>> On Sun, Jul 12, 2009 at 2:48 PM, Werner Dittmann <
>>> Werner.Dittmann at t-online.de> wrote:
>>>
>>>> Goerge,
>>>>
>>>>
>>>> Geekius Caesar schrieb:
>>>>
>>>> <SNIP --- SNAP>
>>>>
>>>>> I did not proceed into creating transformation sets for the rest of the
>>>>> protocols because there is an issue that the DSA signature does not
>>>> verify
>>>>> in Pidgin/libotr, this action is taken in the OTR Protocol Draft, High
>>>> Level
>>>>> Overview, Authenticated Key Exchange, Step 9. I tried to sign using
>>>>> BouncyCastle Leightweight API instead of the Standard JCE, but that
>>>> failed
>>>>> too.
>>>>>
>>>>> To make sure the signature I use is correct, I created a set of test
>>>> cases
>>>>> to verify signatures created with bouncycastle using the Sun JCE
>>>> provider
>>>>> and visa versa, but that failed too.
>>>> As per specification and an according cross-check of libotr
>>>> implementation
>>>> IMHO you cannot use the JCE DSA variant to sign. The JCE variant _always_
>>>> hashes the data, then signs it. The OTR specification reads like this:
>>>>
>>>> sigA(MA) (SIG)
>>>> This is the signature, using the private part of the key pubA, of the
>>>> 32-byte MA (which does not need to be hashed again to produce the
>>>> signature).
>>>>
>>>> IMHO "which does not need to be hashed" is a bit ambigous and should read
>>>> "must not be hased". The libotr implementation also reflects this (see
>>>> code
>>>> snippet below). Each signature value (r and s) is copied into a 20 byte
>>>> field,
>>>> padded with zero if r or s are shorter than 20 bytes. This padding is not
>>>> explictily stated in the spec (it should be stated however).
>>>>
>>>> IMHO you need to rebuild the specific DSA signature mode using the
>>>> appropriate BC functions (SHA256 HMAC, DSA) to be compliant to the spec
>>>> and
>>>> libotr. As said, the JCE methods cannot be used because of their
>>>> "embedded"
>>>> hash mechanism.
>>>>
>>>> Here the function from libotr that performs the signature (inline
>>>> comments
>>>> added by me):
>>>>
>>>>
>>>> /* Sign data using a private key. The data must be small enough to be
>>>> * signed (i.e. already hashed, if necessary). The signature will be
>>>> * returned in *sigp, which the caller must free(). Its length will be
>>>> * returned in *siglenp. */
>>>>
>>>> gcry_error_t otrl_privkey_sign(unsigned char **sigp, size_t *siglenp,
>>>> OtrlPrivKey *privkey, const unsigned char *data, size_t len)
>>>> {
>>>> gcry_mpi_t r,s, datampi;
>>>> gcry_sexp_t dsas, rs, ss, sigs, datas;
>>>> size_t nr, ns;
>>>> const enum gcry_mpi_format format = GCRYMPI_FMT_USG; //wd: raw int
>>>> format
>>>>
>>>> if (privkey->pubkey_type != OTRL_PUBKEY_TYPE_DSA)
>>>> return gcry_error(GPG_ERR_INV_VALUE);
>>>>
>>>> *sigp = malloc(40); //wd: get signature storage
>>>> if (sigp == NULL) return gcry_error(GPG_ERR_ENOMEM);
>>>> *siglenp = 40;
>>>>
>>>> if (len) { //wd: transform raw data into a gcrypt
>>>> multi-precision int
>>>> gcry_mpi_scan(&datampi, GCRYMPI_FMT_USG, data, len, NULL);
>>>> } else {
>>>> datampi = gcry_mpi_set_ui(NULL, 0);
>>>> }
>>>> gcry_sexp_build(&datas, NULL, "(%m)", datampi); //wd: build
>>>> s-expression that holds data now
>>>> gcry_mpi_release(datampi);
>>>> gcry_pk_sign(&sigs, datas, privkey->privkey); //wd: sign the
>>>> s-expr, return a s-expr in sigs
>>>> gcry_sexp_release(datas);
>>>> dsas = gcry_sexp_find_token(sigs, "dsa", 0); //wd: get "dsa" sub
>>>> s-expr (contains r and s)
>>>> gcry_sexp_release(sigs);
>>>> rs = gcry_sexp_find_token(dsas, "r", 0); //wd: get r s-expr
>>>> ss = gcry_sexp_find_token(dsas, "s", 0); //wd: get s s-expr
>>>> gcry_sexp_release(dsas);
>>>> r = gcry_sexp_nth_mpi(rs, 1, GCRYMPI_FMT_USG); //wd: get r MPI
>>>> gcry_sexp_release(rs);
>>>> s = gcry_sexp_nth_mpi(ss, 1, GCRYMPI_FMT_USG); //wd: get s MPI
>>>> gcry_sexp_release(ss);
>>>> gcry_mpi_print(format, NULL, 0, &nr, r); //wd: dummy print
>>>> just to get lentth in "nr"
>>>> gcry_mpi_print(format, NULL, 0, &ns, s); //wd: dummy print
>>>> just to get length in "ns"
>>>> memset(*sigp, 0, 40); //wd: fill with zero
>>>> to assure zero padding
>>>> gcry_mpi_print(format, (*sigp)+(20-nr), nr, NULL, r); //wd: extract
>>>> data from MPI into signature buffer
>>>> gcry_mpi_print(format, (*sigp)+20+(20-ns), ns, NULL, s); //wd: with
>>>> length as computed above
>>>> gcry_mpi_release(r);
>>>> gcry_mpi_release(s);
>>>>
>>>> return gcry_error(GPG_ERR_NO_ERROR);
>>>> }
>>>>
>>>> Verification is just the reversed way :-) .
>>>>
>>>> Regards,
>>>> Werner
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: dev-unsubscribe at sip-communicator.dev.java.net
>>>> For additional commands, e-mail: dev-help at sip-communicator.dev.java.net
>>>>
>>>>
>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe at sip-communicator.dev.java.net
For additional commands, e-mail: dev-help at sip-communicator.dev.java.net
More information about the dev
mailing list