Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert signature from P1363 to ASN.1/DER format using Crypto++?

I have a signature created this way:

size_t siglenth = _signer.MaxSignatureLength();
QByteArray signature(siglenth, 0x00);
signature.reserve(siglenth);
siglenth = _signer.SignMessage(_prng,
        (const CryptoPP::byte*) (message.constData()),
        message.length(), (CryptoPP::byte*) signature.data());

My signature have a size of 64 and contains:

ECCD530E5F232B7C566CA5322F990B3D55ED91156DF3845C4B9105BFE57606DDD68F332A0A5BF7CAB673E4970D10109B72F114571E7474F93ED7C89CD1B89AD4

From what I have read in dsa.h file this signature is currently in DSA_P1363 format. I need to convert it to DSA_DER format.

To perform this action I try :

QByteArray derSign(70, 0xFF);
size_t converted_size = CryptoPP::DSAConvertSignatureFormat(
        (CryptoPP::byte*) (derSign.data()), sizeof(derSign.data()), CryptoPP::DSA_DER,
        (CryptoPP::byte*) (signature.data()), sizeof(signature.data()), CryptoPP::DSA_P1363);

The output of this conversion is shown below. It seems to be only the first part of the signature. It has a size of 8 and contains:

300D020500ECCD53

What is wrong?

Thanks.

like image 488
pipou Avatar asked Sep 25 '19 12:09

pipou


1 Answers

The output of this convertion is curious, it seems to be only the first part of the signature. It have a size of 8 and contains :

300D020500ECCD53

What is wrong ?

Instead of:

size_t converted_size = DSAConvertSignatureFormat(
    (byte*) (derSign.data()), sizeof(derSign.data()), DSA_DER,
    (byte*) (signature.data()), sizeof(signature.data()), DSA_P1363);

You should use something like:

size_t converted_size = DSAConvertSignatureFormat(
    (byte*) (derSign.data()), derSign.size(), DSA_DER,
    (const byte*) (signature.data()), signature.size(), DSA_P1363);

sizeof(derSign.data()) yields the sizeof a size_t, which is different then the size of the string data.

Also, since derSign is being written to, you need a non-const pointer. The way to get that with nearly all versions of C++ is using the address of the first element:

size_t converted_size = DSAConvertSignatureFormat(
    (byte*) (&derSign[0]), derSign.size(), DSA_DER,
    (const byte*) (signature.data()), signature.size(), DSA_P1363);

Nearly finally, this is what you have in P1363, where r and s are a concatenation and each is based on the size of a field element and subgroup order:

[ r ] [ s ]

This is what you need in ASN.1/DER. There are 3 ASN.1 objects - one sequence and two integers. Each object needs one octet for the ASN.1 type, and at most two octets for the length. r and s are the size of the field element. Each ASN.1 integer may need a leading 0, so add two additional bytes for both r and s.

SEQUENCE = {
    INTEGER r;
    INTEGER s;
}

So, for the ASN.1/DER buffer, you need 3+3+3+COUNTOF(r)+1+COUNTOF(s)+1.

Finally, the snippet may look like:

using namespace CryptoPP;
// ... Other gyrations

std::string derSign, signature;
// ...Calculate signature

// Make room for the ASN.1/DER encoding
derSign.resize(3+3+3+2+signature.size())

size_t converted_size = DSAConvertSignatureFormat(
    (byte*) (&derSign[0]), derSign.size(), DSA_DER,
    (const byte*) (signature.data()), signature.size(), DSA_P1363);

ASSERT(converted_size <= derSign.size());
derSign.resize(converted_size);

Crypto++ now has a page on the wiki at DSAConvertSignatureFormat. There is an example of using DSAConvertSignatureFormat at ECDSA | OpenSSL and Java, but the conversion is going the other way.

(Your question and lack of documentation effectively triggered a bug, and we closed the gap).


I just noticed this...

size_t siglenth = _signer.SignatureLength();
QByteArray signature(siglenth, 0x00);
signature.reserve(siglenth);
siglenth = _signer.SignMessage(_prng, (const CryptoPP::byte*) (message.constData()),
                               message.length(), (CryptoPP::byte*) signature.data());

Instead use this:

QByteArray signature;
size_t siglenth = _signer.SignatureLength();

signature.resize(siglenth);
siglenth = _signer.SignMessage(_prng,
             (const byte*) (message.constData()), message.length(),
             (byte*) (&signature[0]));
signature.resize(siglenth);
like image 146
jww Avatar answered Nov 08 '22 11:11

jww