1

I need to parse a ASN.1 DER encoded RSA 2048 private key to get the different components like modulus, exponent etc. As I gone through the key, some of the components are found to have leading zeros. Are these zeros supposed to be skipped? If yes, how can I distinguish a zero which is part of the component from these leading zeros. For my specific case, the private exponent field has length 256 and the first byte is 0. Is this part of the exponent or supposed to be skipped. For RSA 2048 key, whether the private exponent will be of size 256 bytes always?

[UPDATE] It seems ASN.1 DER encoded values are ordered in big endian. So there is no point in asking leading zeros coming as part of the component and it is supposed to be skipped. So the question is limited to the size of private exponent. I have a RSA 2048 key and the private exponent size is 255 bytes. I have parsed the different private key components and populated on an object of 'RSAParameters'. Trying to import this using RSACryptoServiceProvider.ImportParameters() throws CryptographicException with error message 'Bad Data'. Whether the ImportParameters() expect the exponent size also to be 256 bytes? Is there any tool with which I can verify the different key components are correct?

hasmit
  • 115
  • 7
  • Have you read my answer? What is missing? – Maarten Bodewes Oct 13 '12 at 15:45
  • As an answer to the *additional* question in the update, you can use `openssl asn1parse -inform DER -dump -in ` to check the key. If there are any negative numbers in there, it is incorrect as RSA only works with positive numbers. – Maarten Bodewes Oct 13 '12 at 15:48

3 Answers3

1

In BER and DER, integers are encoded as 2s-complement numbers. This means that the first bit of a positive number must be zero. This sometimes requires an extra zero byte at the beginning. Note that it is invalid BER/DER to to have the first 9-bits of an integer value encoding all zero. The extra zero byte is added only to prevent a non-zero first bit from being interpreted as a negative number.

Paul Thorpe
  • 1,930
  • 17
  • 23
0

PKCS#1 key components are encoded as with ASN.1 signed integers (ASN.1 does not know unsigned integers as data type).

So if a positive number is key size in bytes, then the first bit needs to be 1 in unsigned notation. Thus the signed notation needs an extra byte set to 00h to make it a positive, signed number. Note that the private exponent is limited to value of the modulus but may sometimes be up to a few bytes smaller than the modulus.

As the modulus needs to be the exact key size, and since key sizes are almost always a multiple of 8, it will always need 00h padding.


If the number is key size in bits then by definition the first bit has to be switched on. E.g. if you have a eight bit number then you must represent it as 1XXX XXXX. This means that the number ranges from 2^7 to 2^8 (exclusive). Now remember that RSA key sizes are can commonly be divided by 8 (512, 1024, 2048, you know the score). This means that a number that has the same size as the key will always have its first bit set. As a signed number it will therefore need to have a padding byte.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Thanks for your reply. But I am not clear about your answer. My understanding is leading zero is inserted if the MSB of the first byte of the positive number is '1' and not while the number is key size in bytes. – hasmit Oct 15 '12 at 13:57
0

Microsoft implementation is less forgiving than most. There's already a few questions (and answers) here about this:

Community
  • 1
  • 1
poupou
  • 43,413
  • 6
  • 77
  • 174
  • So ImportParameters() expects a private exponent with size 256 bytes for a RSA 2048 key. Prefixing the exponent with a zero-byte (makes it 256 bytes) worked. Thanks... – hasmit Oct 15 '12 at 13:57