Using Base64 encoded Public Key to verify RSA signature

26,014

Solution 1

Your string is the base64 encoding of a SubjectPublicKeyInfo. You can use Bouncycastle.net to decode it like this:

byte[] publicKeyBytes = Convert.FromBase64String(publicKeyString);
AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(publicKeyBytes);
RsaKeyParameters rsaKeyParameters = (RsaKeyParameters) asymmetricKeyParameter;
RSAParameters rsaParameters = new RSAParameters();
rsaParameters.Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned();
rsaParameters.Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned();
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParameters);

Solution 2

First base64 is only an encoding of some binary data. There's more than one way to encode, in binary, an RSA public key. However if you got this from OpenSSL it's likely a DER-encoded RSAPublicKey structure.

 RSAPublicKey ::= SEQUENCE {
     modulus            INTEGER,    -- n
     publicExponent     INTEGER  }  -- e

In general you would need a ASN.1 decoder, Mono.Security.dll provides one, but for such a simple structure you might want to do it by hand since ASN.1 is basically a Tag, Length and a Value.

Share:
26,014
jscheppers
Author by

jscheppers

Updated on January 05, 2020

Comments

  • jscheppers
    jscheppers over 4 years

    In a nutshell, this is my problem:

    private string publicKeyString = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVGUzbydMZS+fnkGTsUkDKEyFOGwghR234d5GjPnMIC0RFtXtw2tdcNM8I9Qk+h6fnPHiA7r27iHBfdxTP3oegQJWpbY2RMwSmOs02eQqpKx4QtIjWqkKk2Gmck5cll9GCoI8AUAA5e0D02T0ZgINDmo5yGPhGAAmqYrm8YiupwQIDAQAB";
    
    /* Some transformation required, using publicKeyString to initiate a new RSACryptoServiceProvider object
    */
    
    //for now:
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
    
    byte[] selfComputedHash = new byte[]; //left out of the example
    byte[] signature = new byte[];
    
    bool result = rsa.VerifyHash(selfComputedHash, CryptoConfig.MapNameToOID("SHA1"), signature);
    

    As you can see, the problem is initiating a new RSACryptoServiceProvider with the given Base64 encoded public key string. I've been able to do the instantiation using an object RSAParameters, loaded with the byte[]'s for Modulus and Exponent derived from this public key string using an OpenSSL shell command. But since this public key may change in the future I want to be able to store it in its original form in a database. There must be a more straightforward way of dealing with this.

    A lot of the examples I've read so far avoid this problem by exporting and importing the generated private and public keys to and from a key-container object and use it in the same piece of code and thus not 'transferring' the key in some string form out of memory. Some people have expressed the same problem, both here on StackOverflow and on other sites, but I have not been able to find a satisfying answer yet.

    Any idea's are more than welcome.

    Background info: My communication partner computes a 20-byte SHA1-hash from an input string of variable length, composed of the information contained in several fields of an ASCII encoded message. This hash is then RSA-signed with my partner's private key and sent along with the ASCII message to me. Upon arrival, I compute the SHA1 hash myself, using the same fields from the ASCII message and then try to verify if these fields were not altered by calling VerifyHash.

    The key is provided in 2 forms: regular and 'noNL'. The noNL version is included in the code above, the regular version is this:

    -----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDVGUzbydMZS+fnkGTsUkDKEyFO
    GwghR234d5GjPnMIC0RFtXtw2tdcNM8I9Qk+h6fnPHiA7r27iHBfdxTP3oegQJWp
    bY2RMwSmOs02eQqpKx4QtIjWqkKk2Gmck5cll9GCoI8AUAA5e0D02T0ZgINDmo5y
    GPhGAAmqYrm8YiupwQIDAQAB
    -----END PUBLIC KEY-----
    
  • jscheppers
    jscheppers about 12 years
    That would be a good possibility, but I have no control over the way the keys are generated. The keys are provided as-is, no certificate is available where this key is present in.
  • jscheppers
    jscheppers about 12 years
    The organisation that provides the public keys does not mention the format of the key, but since I'm able to 'read' them with OpenSSL and since the key contains both the -----BEGIN PUBLIC KEY----- and -----END PUBLIC KEY----- tags (I'll add this to my original post) I'm fairly certain it's a DER encodes key. How would you go about converting this string into an ASN.1 structure by hand? When bytes come into play, I'm not that sure of myself :)
  • jscheppers
    jscheppers about 12 years
    Thank you, that's pretty easy. I'll look into the BouncyCastle library, but are you sure there is no way to accomplish this using only the Cryptography library in .NET itself?
  • Rasmus Faber
    Rasmus Faber about 12 years
    @jscheppers: You can do it manually as poupou suggests, but there is no direct support for the format in .NET. A quick search reveals this example for decoding manually: jensign.com/JavaScience/dotnet/pempublic/pempublic.cs , but that one looks a bit messy.
  • Rasmus Faber
    Rasmus Faber about 12 years
    Note that it is actually a SubjectPublicKeyInfo containing an RSAPublicKey.
  • jscheppers
    jscheppers about 12 years
    I think I prefer your BouncyCastle-solution then ;) I've already tried it in my current implementation and it works. I'll mark your post as the answer!