views:

117

answers:

1

Given a hash algorithm like SHA1 or SHA256 how would I go about obtaining the ASN.1 DER encoding for it as defined in RFC3447? (see page 42 - link) Below is the desired output.

MD5        30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 05 05 00 04 10
SHA-1      30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14
SHA-256    30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20
SHA-384    30 41 30 0d 06 09 60 86 48 01 65 03 04 02 02 05 00 04 30
SHA-512    30 51 30 0d 06 09 60 86 48 01 65 03 04 02 03 05 00 04 40

I'm hoping there is some intelligent way to do this in C# that doesn't require me to write an Oid to ASN.1 DER conversion routine (or hardcode them). Any ideas?

+3  A: 

This will get you part of the way:

string oidString = CryptoConfig.MapNameToOID(hashName); // f.x. "MD5"
byte[] encodedOid = CryptoConfig.EncodeOID(oidString); // Gives you f.x. 06 08 2a 86 48 86 f7 0d 02 05

Then you just need to insert it in the SEQUENCE-heading (30<length>30<length2><oid>050004<hashlength>).

Of course if you want to create an RSA PKCS#1 v1.5 signature, you would be better off just using RSAPKCS1SignatureFormatter.


EDIT: A few more details:

The ASN.1 you want to encode is this:

DigestInfo ::= SEQUENCE {
      digestAlgorithm AlgorithmIdentifier,
      digest OCTET STRING
}

where

AlgorithmIdentifier  ::=  SEQUENCE  {
      algorithm               OBJECT IDENTIFIER,
      parameters              ANY DEFINED BY algorithm OPTIONAL  
}

So to start from inside: the digest-AlgorithmIdentifier consist of a SEQUENCE-tag (30), a length (we will get back to that), an OID and some parameters. The OID for f.x. SHA-1 is 1.3.14.3.2.26, which is encoded as 06 05 2b 0e 03 02 1a (OID-tag 06, length 5 and the encoding of the OID). All the usual hash functions have NULL as parameters, which is encoded as 05 00. So the AlgorithmIdentifier contains 9 bytes - this is the above.

We can now continue with the rest of the DigestInfo: an OCTET STRING, which contains the value of the hash. SHA-1's 20 bytes hash will be encoded as 04 20 <HASH>.

The length of the contents of the DigestInfo is now 11+22 bytes (). We need to start the DigestInfo with the SEQUENCE-tag, so we end up with: 30 21 30 09 06 05 2b 0w 02 01 1a 05 00 04 20 <HASH>.

If you need to generate it yourself, you should now be able to see that length2 = encodedOid.Length + 2 and that length = length2 + 2 + 2 + hashlength.

If you need some more information about encoding ASN.1, I can recommend Burt Kaliski's A Layman's Guide to a Subset of ASN.1, BER, and DER.

Rasmus Faber
Where did you find the definition for the SEQUENCE heading? I'm trying to understand what length2 is and what 050004 represents?
Taylor Leese
@Taylor Leese: I added some more details.
Rasmus Faber
@Rasmus - thanks
Taylor Leese