# OpenSSL - extract hash algorithm from signature data (PKCS#1 v 1.5)

PKCS#1 v 1.5 stores hash algorithm identifier that was used to digest the original message. I would like to know if and how to extract this information.

I am working on a buffer containing the signature bytes and a buffer with public key.

I know it can be done (e.g. openssl rsautl does it with -verify and -asn1parse), but there is no sensible documentation for asn1 functions in openssl.

The hash identifier of a given RSASSA-PKCS1-v1_5 signature can only be obtained using the signature's public key¹. It's revealed by performing the signature verification steps 1 and 2/a/b/c (which basically gets the signature as an integer, raises it to the power $$e$$ modulo $$N$$ extracted from the public key, and converts back to bytes), then parsing the Encoded Message, which should be as per section 9.2 step 5, that is $$\text{EM}=\mathtt{00}\mathbin\|\mathtt{01}\mathbin\|\mathtt{FF}\mathbin\|\ldots\|\mathtt{FF}\mathbin\|\mathtt{00}\mathbin\|T$$ where

• the left two bytes $$\mathtt{00}\mathbin\|\mathtt{01}$$ are fixed, and followed by $$f\ge8$$ bytes at $$\mathtt{FF}$$ then a $$\mathtt{00}$$ ($$f$$ is maximal, that is for a $$b$$-bit public modulus $$N$$ the length of $$T$$ is $$\left\lfloor(b-17)/8\right\rfloor-f$$ bytes).
• $$T$$ is ASN.1 DER encoded, containing the hash identifier and hash value.

The pragmatic approach to decode $$T$$ is to look at note 1 (or the table below, which comes from that).

MD2:         30 20 30 0C 06 08 2A 86 48 86 F7 0D 02 02 05 00 04 10 ∥ H
MD5:         30 20 30 0C 06 08 2A 86 48 86 F7 0D 02 05 05 00 04 10 ∥ H
SHA-1:       30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 ∥ H
SHA-224:     30 2D 30 0D 06 09 60 86 48 01 65 03 04 02 04 05 00 04 1C ∥ H
SHA-256:     30 31 30 0D 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ∥ H
SHA-384:     30 41 30 0D 06 09 60 86 48 01 65 03 04 02 02 05 00 04 30 ∥ H
SHA-512:     30 51 30 0D 06 09 60 86 48 01 65 03 04 02 03 05 00 04 40 ∥ H
SHA-512/224: 30 2D 30 0D 06 09 60 86 48 01 65 03 04 02 05 05 00 04 1C ∥ H
SHA-512/256: 30 31 30 0D 06 09 60 86 48 01 65 03 04 02 06 05 00 04 20 ∥ H


If we dive into the fine print, this is a DigestInfoValue. For example, the last entry decodes as

• 30 31   Sequence of 49 bytes
• 30 0D   Sequence of 13 bytes
• 06 09   OID of 9 bytes
• 60 86 48 01 65 03 04 02 06
OID 2.16.840.1.101.3.4.2.6 meaning "SHA512-256 algorithm"
• 05 00   NULL for the Parameters field²
• 04 20   Octet string of 32 bytes
• (the hash H follows as 32 bytes).

See this for how OIDs are encoded, and links to the ASN.1 DER specification. Examples can be thrown at Lapo Luchini's useful ASN.1 decoder.

¹ Given a signature, it's possible to make a new public/private key pair that makes this signature valid with any desired hash identifier and matching any desired known message (not only the the original) when checked with this new public key.

² This field must be present and NULL when encoding and checking $$T$$ in the context of RSASSA-PKCS1-v1_5. In other contexts a parser must accept that it is missing for the SHA algorithms, see the Exception in appendix B.1 and the two paragraphs above.