DSAConvertSignatureFormat
Documentation |
#include <cryptopp/dsa.h>
|
DSAConvertSignatureFormat allows you to convert between different DSA and ECDSA signature formats. Signature formats and how to use them with Crypto++ comes up on occasion, like Convert DSA_P1363 to DSA_DER, ECDSA sign with OpenSSL, verify with Crypto++ and ECDSA sign with BouncyCastle and verify with Crypto++ on Stack Overflow.
Crypto++ supports three types of DSA and ECDSA signature formats. The first is the library's native format and it is IEEE's P1363. P1363 is a simple concatenation of [math]\displaystyle{ r }[/math] and [math]\displaystyle{ s }[/math]. The second format is ASN.1/DER format, and it is used by OpenSSL, Java and .Net. ASN.1/DER is a SEQUENCE
of two INTEGER
, [math]\displaystyle{ r }[/math] and [math]\displaystyle{ s }[/math]. The final format is OpenPGP format.
A full sample that uses DSAConvertSignatureFormat
is available at OpenSSL and Java on the wiki. DSAConvertSignatureFormat
is only a small part of the code.
Function Signature
DSAConvertSignatureFormat
is declared in dsa.h and defined in dsa.cpp. The signature of the function is shown below.
size_t DSAConvertSignatureFormat( byte *buffer, size_t bufferSize, DSASignatureFormat toFormat, const byte *signature, size_t signatureLen, DSASignatureFormat fromFormat);
buffer
is the destination buffer.
bufferSize
is the destination buffer size.
toFormat
is the new encoding format.
signature
is the source buffer.
signatureLen
is the source buffer size.
fromFormat
is the existing encoding format.
DSASignatureFormat
is an enumeration and is one of DSA_P1363
, DSA_DER
or DSA_OPENPGP
.
Crypto++ and P1363
Crypto++ uses P1363 format by default for signatures. The signature is a concatenation of r
and s
, where both r
and s
are based on the size of a field element and the subgroup order. Sometimes the signature is denoted r || s
because it is a simple concatenation.
The table below shows different element and signature sizes for different fields. DSA uses the field of integers, and ECDSA uses a field over elliptic curves. NIST random curves are shown, and Koblitz curves are similar.
Algorithm | Element Size | Signature Size |
---|---|---|
DSA-1024 | 16 | 40 |
DSA-2048 | 32 | 56 |
DSA-3072 | 48 | 64 |
secp112r1 | 14 | 28 |
secp128r1 | 16 | 32 |
secp224r1 | 28 | 56 |
secp256r1 | 32 | 64 |
secp192r1 | 40 | 80 |
secp384r1 | 48 | 96 |
secp521r1 | 66 | 132 |
P1363 to ASN.1/DER
Crypto++ uses P1363 formatted signatures, and OpenSSL, Java and .Net use ASN.1/DER formatted signatures. The code below converts from P1363 to ASN.1/DER. The tricky part in the code is determining the ASN.1/DER buffer size.
The code below assumes you have a Crypto++ signature in p1363Signature
produced by a function like SignMessage
. The signature is r || s
.
std::string p1363Signature, derSignature; // ...Calculate signature p1363Signature = SignMessage(signer, message); // Make room for the ASN.1/DER encoding derSignature.resize(3+3+3+2+p1363Signature.size()) size_t encodedSize = DSAConvertSignatureFormat( (byte*) (&derSignature[0]), derSignature.size(), DSA_DER, (const byte*) (p1363Signature.data()), p1363Signature.size(), DSA_P1363); ASSERT(encodedSize <= derSignature.size()); derSignature.resize(encodedSize );
The derSignature
buffer size is calculated as follows. The maximum size of the ASN.1/DER objects are shown below. The final ASN.1/DER object may be smaller.
Each ASN.1 object needs a tag that takes one octet, and a length that takes up to 2 octets. An ASN.1 INTEGER
may need a leading 0 prepended to r
or s
. COUNTOF
is the count of the bytes in r
or s
. The number of bytes in r
or s
is determined by the size of an element in the underlying field and subgroup order.
SEQUENCE := { // 1+2 INTEGER r; // 1+2+COUNTOF(r)+1 INTEGER s; // 1+2+COUNTOF(s)+1 }
ASN.1/DER to P1363
Crypto++ uses P1363 formatted signatures, and OpenSSL, Java and .Net use ASN.1/DER formatted signatures. The code below converts from ASN.1/DER to P1363. The code is easier because the P1363 buffer is smaller than the ASN.1/DER buffer.
The one caveat during conversion is, the P1363 buffer must be correctly sized. The buffer cannot be oversized and then trimmed later. "Correctly sized" means the buffer is exactly SignatureLength()
in size. The requirement is because the integers r
and s
must be padded to a particular size so the concatenation is r || s
is the correct size.
The code below assumes you have a OpenSSL, Java or .Net signature in derSignature
, and loaded by a function like LoadSignatureOnMessage
. The inbound signature format is SEQUENCE := { INTEGER r; INTEGER s; }
, and it needs to be converted to P1363 so Crypto++ can use it.
std::string derSignature, p1363Signature; // ...From OpenSSL, Java or .Net derSignature = LoadSignatureOnMessage(...); // Need the verifier object to size the P1363 buffer ECDSA<ECP, SHA256>::Verifier verifier(publicKey); // Make room for the P1363 encoding p1363Signature.resize(verifier.SignatureLength()); size_t encodedSize = DSAConvertSignatureFormat( (byte*) (&p1363Signature[0]), p1363Signature.size(), DSA_P1363, (const byte*) (derSignature.data()), derSignature.size(), DSA_DER); ASSERT(encodedSize <= p1363Signature.size()); p1363Signature.resize(encodedSize);
P1363 to OpenPGP
Crypto++ uses P1363 formatted signatures, and OpenPGP uses a custom formatted signatures. The code below converts from P1363 to OpenPGP. The tricky part in the code is determining the OpenPGP buffer size.
The code below assumes you have a Crypto++ signature in p1363Signature
produced by a function like SignMessage
. The signature is r || s
.
std::string p1363Signature, openpgpSignature; // ...Calculate signature p1363Signature = SignMessage(signer, message); // Make room for the ASN.1/DER encoding openpgpSignature.resize(2+2+p1363Signature.size()) size_t encodedSize = DSAConvertSignatureFormat( (byte*) (&openpgpSignature[0]), openpgpSignature.size(), DSA_OPENPGP, (const byte*) (p1363Signature.data()), p1363Signature.size(), DSA_P1363); ASSERT(encodedSize <= openpgpSignature.size()); openpgpSignature.resize(encodedSize );
The openpgpSignature
buffer size is calculated as follows. OpenPGP uses a length prefixed value, which is a 16-bit length prefix. The maximum size of the OpenPGP objects are 2 plus the byte size of r
and 2 plus the byte size of s
.