Reputation: 1125
I'm looking at an RSA private key in PEM format. When I decode the base64 string and review the components of the key, some of them have an extra byte, specifically the modulus, P, DP, and IQ. They all have a leading 0x00 byte. I'm handling this by just trimming the byte[] down to the expected lengths of 256 or 128 so I can use them with .NET RSAParameters and RSACryptoServiceProvider, but wondering why some of these INTEGER structures have the extra byte while others don't. It would appear that online and other libraries that decode the PEM to XML, etc handle this gracefully, so is this part of the RFC, just something that you have to protect against, or only a concern because I'm using the .NET libraries after decoding? Here's an example of the modulus with 257 bytes:
00 B7 55 AA 3F 14 89 BC CE ED AF 80 1C 54 2A DF
AB 3C 6A 44 B4 55 58 90 0E 0D 32 96 E6 EF 35 2D
AD B7 44 A7 AB CE 6F D3 BB 9D B4 4B FD 0A DE 87
96 03 55 23 81 49 FE 1B 3E CE 62 B6 2F B1 4C 33
E4 F8 C2 09 5F 0E 10 78 22 D0 F3 C9 BF B9 AC AC
11 00 17 28 09 23 10 D5 8A C9 2B E2 86 96 A7 E2
57 68 D7 3B 63 BE 74 ED B8 02 E2 63 EF F5 40 85
0C A6 9F D0 B6 88 36 8B 4E 6B 35 27 BE 11 CC C8
C3 0A 66 25 E0 AB B6 DD 6D E6 2B AF 9E 1C D7 11
CE 5F E7 C8 1F EB 3D 79 B3 B2 E1 FF D8 20 6D 76
A2 43 9E 20 67 58 97 39 46 D8 73 F6 F0 76 01 E0
61 8E 4A EE C4 03 A6 44 C7 D3 50 E3 C8 62 CF 33
D1 37 6B 85 F5 D4 3C 6D 1F 1A 14 B3 30 B5 E0 82
A5 94 83 4F 7A 17 DA 86 2B F7 2A 47 A3 5F D2 D5
7B 96 32 86 27 5E 2A 6A 85 6E C6 24 15 A9 09 65
BB 04 8C 0D 39 F7 15 D4 F0 F8 5F 0F B0 1D A7 2F
D7
Here's an example of the "D" parameter that is not padded with a leading 0x00:
04 07 EF 8A 5D 88 3D C7 8B 00 5D DF C1 96 03 BE
FF 20 1D 0C A8 07 BF 7B 1F 9D 2A 26 3F C2 3A 93
E4 40 B5 33 18 E1 EA 94 E8 7D C0 61 EF F8 3E A0
F4 C7 CD 75 0D 4C 72 0A EA 7C CF 26 B3 4E 4A A1
D1 3A 6A FA 55 11 D5 A2 66 57 C5 EA DA 49 4A AB
41 06 41 52 1A 1C 47 A5 BA 90 A5 75 72 20 94 E0
79 24 AA 60 A2 12 6E 1B AA AC 91 A7 F8 0B 88 21
64 14 85 81 4D F3 6D 12 B7 56 BE DD F6 04 3B B1
CC 95 A6 8C 9D A6 8D BF 05 C1 72 A4 0B 03 75 F6
40 B6 8E 25 91 3D 87 84 CD 23 EF 2C 29 13 DD A7
75 6E 48 F4 DE 49 98 4F B7 09 CF 5A A3 F5 39 05
37 C8 2B 79 64 F0 B8 AD 11 EF 79 FD 78 C0 6B 2B
50 7F DE BC 59 3D D1 A1 90 59 B7 7E 57 B4 2C A0
D2 20 D2 D6 7C 4A B3 3C 63 5D FA E6 67 18 58 AC
F3 EF 0E E1 C0 C9 B6 D9 8C D1 8E 3D CE 8A FF F0
12 BF C2 FE 72 DC 07 E4 3C 00 5B BE 05 D9 5A 61
And the DP parameter without leading 0:
3E 50 B2 28 A3 B1 71 F3 D5 31 B1 2D FD B3 60 4B
57 F8 C1 46 C7 89 B7 95 F4 7D AE 54 F2 EA 11 98
F7 61 93 30 50 D9 24 19 BF 7F 06 19 DB 97 01 06
8B 20 D7 7A 5E 1A FA 76 9A 0E 27 46 AB FF 25 3C
74 61 E2 9B 3E CE A5 F9 58 40 70 15 94 F2 58 3E
DB E4 90 91 3C 50 B0 24 8F C7 A7 55 EB E3 59 A7
5D 01 19 29 4F F9 F9 E6 EB 78 D1 93 14 61 E4 5C
36 D7 E7 82 58 E7 C5 60 21 F3 1E 5A D4 49 C6 D1
Upvotes: 0
Views: 1161
Reputation: 13974
These values are encoded as INTEGER
ASN type which uses two-complement notation. That is if most significant bit is set to 1, then the number is negative. However, all numbers (modulus, exponents, primes) in key are positive numbers and prepended with extra leading zero octet to denote positive integer. If the most significant bit is already set to 0, then no extra bytes are added.
Upvotes: 3
Reputation: 33238
The RSA modulus is a positive number, and ASN.1 integers are all signed.
So if the leading 0x00 wasn't there, this byte encoding would represent a negative number because the first byte would have the high bit set (0xB7 >= 0x80). As a consequence, the 0x00 gets inserted into the DER data stream.
.NET's representation is based on the Windows CAPI representation. CAPI uses domain knowledge to know that the values are all unsigned integers, and then omits the leading 0x00 bytes. So it's up to whoever translates between the DER data and the .NET/CAPI data to add or remove the bytes as needed.
Upvotes: 3