JkeyNet: Using ASN.1 encoded public keys in .NET


Understanding interoperability issues between different implementations of cryptography is important to the success of widespread deployment of crypto-enabled applications. While standards are evolving for communications protocols at the web-services layer, it is important to understand more basic interop. issues as well.

This note shows how to access and decode RSA public keys in various formats from .NET for digital signature and asymmetric public-key encryption use. Compatibility between .NET Framework 1.1 and Java 2 is discussed.

RSA PKCS#1 Digital Signature:
For the same RSA keypair, hash algorithm and byte content, digital signatures generated by java.security.Signature.Sign() with an RSA provider, are identical to those generated by .NET Framework 1.1 System.Security.Cryptography.RSAPKCS1SignatureFormatter.CreateSignature().
Both Java and .NET generate a PKCS #1 version 1.5 signature. By comparison, CryptoAPI CryptSignHash() generates the same PKCS #1 signature block, but in reversed (little-endian) order.

ASN.1 Encoded RSA Public Key formats:
There are two commonly used ASN.1 encoded "public key" formats.

SubjectPublicKeyInfo format is the encoding exported by Java 2 using java.security.PublicKey.getEncoded(). It is also the default format used by OpenSSL for exporting public key binary blobs. The RSAPublicKey format is in fact simply a sub-sequence of SubjectPublicKeyInfo. For a 1024 bit RSA keypair, SubjectPublicKeyInfo encoding is 162 bytes compared to 140 bytes for the RSAPublicKey encoding. RSAPublicKey format is used extensively in Windows and CryptoAPI in: The RSAPublicKey format corresponds to the encoded CERT_PUBLIC_KEY_INFO.Publickey.pbData member data, and is the identical byte sequence found in the corresponding X.509 v3 binary DER encoded certificate. The SubjectPublicKeyInfo format corresponds to an encoded version of the CERT_PUBLIC_KEY_INFO CryptoAPI encoded structure.
ASN.1 encoded public keys always use BIG-endian byte ordering for modulus and exponent data.

Sample hex-dumps of ASN.1 encoded SubjectPublicKeyInfo and RSAPublicKey blobs are shown below:

X.509 SubjectPublicKeyInfo public key format  [162 bytes]
30  81  9F  30  0D  06  09  2A  86  48  86  F7  0D  01  01  01  
05  00  03  81  8D  00  30  81  89  02  81  81  00  C2  AC  3D  
E3  D3  43  2C  88  4D  0C  7C  4C  3D  AC  14  95  20  A6  45  
11  B6  D3  BC  90  3F  74  DB  44  C8  BA  F9  E9  60  E2  CB  
48  59  4D  47  DF  2A  E3  08  14  2D  2E  52  56  B1  E5  5E  
A2  D4  13  CF  A5  B0  42  C3  35  5D  D8  97  9E  C8  95  8D  
8D  EC  C0  2F  1E  64  E1  C6  9E  96  E8  A9  AA  D1  A3  9A  
90  7B  F6  33  71  BB  B1  B5  D5  4D  05  3F  C5  67  F2  26  
74  C2  F6  69  78  67  B0  FC  0D  3C  8A  CC  B4  C6  B8  A1  
DD  76  72  31  45  2B  56  72  84  83  BF  8F  A1  02  03  01  
00  01  

RSAPublicKey PKCS #1 format  [140 bytes]
30  81  89  02  81  81  00  C2  AC  3D  E3  D3  43  2C  88  4D  
0C  7C  4C  3D  AC  14  95  20  A6  45  11  B6  D3  BC  90  3F  
74  DB  44  C8  BA  F9  E9  60  E2  CB  48  59  4D  47  DF  2A  
E3  08  14  2D  2E  52  56  B1  E5  5E  A2  D4  13  CF  A5  B0  
42  C3  35  5D  D8  97  9E  C8  95  8D  8D  EC  C0  2F  1E  64  
E1  C6  9E  96  E8  A9  AA  D1  A3  9A  90  7B  F6  33  71  BB  
B1  B5  D5  4D  05  3F  C5  67  F2  26  74  C2  F6  69  78  67  
B0  FC  0D  3C  8A  CC  B4  C6  B8  A1  DD  76  72  31  45  2B  
56  72  84  83  BF  8F  A1  02  03  01  00  01  


A partial ASN.1 dump of the certificate containing this public key is shown below. The entire displayed ASN.1 corresponds to the SubjectPublicKeyInfo data. The red sub-data is the RSAPublicKey encodeded data:

0235 30   9F:     SEQUENCE {
0238 30    D:       SEQUENCE {
023A 06    9:         OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
0245 05    0:         NULL
            :         }
0247 03   8D:       BIT STRING 0 unused bits, encapsulates {
024B 30   89:           SEQUENCE {
024E 02   81:             INTEGER
            :               00 C2 AC 3D E3 D3 43 2C 88 4D 0C 7C 4C 3D AC 14
            :               95 20 A6 45 11 B6 D3 BC 90 3F 74 DB 44 C8 BA F9
            :               E9 60 E2 CB 48 59 4D 47 DF 2A E3 08 14 2D 2E 52
            :               56 B1 E5 5E A2 D4 13 CF A5 B0 42 C3 35 5D D8 97
            :               9E C8 95 8D 8D EC C0 2F 1E 64 E1 C6 9E 96 E8 A9
            :               AA D1 A3 9A 90 7B F6 33 71 BB B1 B5 D5 4D 05 3F
            :               C5 67 F2 26 74 C2 F6 69 78 67 B0 FC 0D 3C 8A CC
            :               B4 C6 B8 A1 DD 76 72 31 45 2B 56 72 84 83 BF 8F
            :               A1
02D2 02    3:             INTEGER 65537
            :             }
            :           }
            :       }

Microsoft CryptoAPI Public Key formats:
CryptoAPI allows exporting keys in unencoded format. For public keys, the PUBLICKEYBLOB format can be easily parsed by any application to obtain the RSA public key parameters. The CryptoAPI PUBLICKEYBLOB can be obtained several ways. Here are a few:

.NET uses a slightly different "public key" structure as documented in StrongName.h. It is a thin wrapper around PUBLICKEYBLOB. The strong name "publickey" consists of 3 headers (12 bytes) followed by the usual CryptoAPI PUBLICKEYBLOB. This is the "publickey" field that is embedded in strong-named assembly metadata, and is the publickey returned by the .NET SDK tools sn.exe [-e | -p] and secutil.exe -s.

Note that CryptoAPI and .NET unencoded public key structures store the modulus and exponent in LITTLE-endian byte order.

Public key data sizes:
As a summary, here are the byte lengths for public key structures for 1024 bit RSA keys:

Using ASN.1 encoded or CryptoAPI PUBLICKEYBLOB public keys in .NET:
Public key parameters can be used to either verify RSA digital signatures, or to asymmetric-encrypt data using the recipients public key. To use various format public key files form .NET, the public key modulus and exponent parameters must be extracted from the keyblobs. One way to do this is:

At the certificate level, the same approach can be used to extract the public key parameters from:

RSAPubKeyData.cs is a utility class with methods to decode any of the public-key file blob formats discussed above:

Successful method invocation initializes the RSAPubKeyData properties: where the byte[] properties are in big-endian format. These properties can then be used to instantiate an RSACryptoServiceProvider and then used for signature verification or asymmetric public-key encryption.

The following utilities may also be useful:

DecodeBlob.exe is a native (C) console application which decodes a Java exported public key file, and writes a CryptoAPI PUBLICKEYBLOB file publickeyblobout to the current directory. Sample output

RSAKeyblob is a .NET console utility which reads and parses an RSA CryptoAPI PUBLICKEYBLOB file and displays public key details including RSA bit size, exponent and modulus value (in big-endian byte order). Sample output

DecodeCertKey is a .NET console utility which reads any local X.509 v3 certificate file, decodes the PUBLICKEYBLOB, displays the public key exponent and modulus in big-endian order and uses the public key data to instantiate an instance of .NET RSACryptoServiceProvider.


Michel I. Gallant
neutron@istar.ca