Click here to Skip to main content
13,258,055 members (58,685 online)
Click here to Skip to main content
Add your own
alternative version


52 bookmarked
Posted 6 Apr 2004

Porting Java Public Key Hash to C# .NET

, 26 Oct 2004
Rate this:
Please Sign up or sign in to vote.
This tutorial is an effort to overcome problems faced by the developers who want to sign data using Java Key Store and want to verify it on .NET platform. The tutorial demonstrates how to export the Public Key using Java to .NET compatible Public Key (XML format).

Table of Contents


There is perhaps no software engineering topic of more timely importance than data security and integrity. Attacks are costly, whether the attack comes from inside or out, and some attacks can expose a software company to liability for damages. Staying on top of the most up-to-date techniques and tools is one key to application security and integrity. Developing cross platform applications to ensure security is a big problem which has been encountered by a number of developers.

This tutorial is an effort to overcome such problems faced by the developers who want to sign the data on one platform and want to verify it on another, using popular public-key digital signature known as RSA.

Starting with a Java program to illustrate how to generate the keys, sign and verify the data using the generated keys, both by breaking down the functions of the application and by viewing the final execution result. Next, the tutorial discusses how to export the public key, generated by Java, to be used later by .NET framework to verify the data in .NET applications. Finally, this tutorial discusses how to read the Public Key generated by Java program in .NET (using C#) and verify the data using this Public Key. In the end of the tutorial, different definitions of terms are also provided to equip the beginners as well.

Section 1: Introduction

Who should read?

The main ideas behind this tutorial revolve around signing a data in Java and then verifying it in .NET using C#. However, readers who are interested to start learning the signing & verifying of data using Java Cryptographic APIs and language can also use this tutorial. This tutorial assumes that reader knows how to read and write basic Java & C# .NET applications.

Before going through this tutorial, it is highly recommended that you should have basic knowledge of terms for Cryptography and Security packages defined in Java and .NET framework. For interested readers, the definitions of terms is provided in the Glossary at the end of the tutorial. Even if you know the terms, just go through them to re-memorize them.

Section 2: Signature generation in Java

The zip file includes the This Java class is responsible for signing the data and verifying the data using private and public keys respectively. It also generates the XML Public key for .NET framework. This class has the following responsibilities.

  • Initialize Signature Parameters
  • Generate Public and Private Keys
  • Store/Read generated Public and Private keys
  • Sign the input data
  • Verify the input data
  • Store the Public key in .NET compatible (XML) format

Although it is not fair to keep all the things in one class; but just to keep it simple, everything has been kept in one class. Reader may alter the code and may eliminate functions such as storing/reading the keys on/from HDD to some other class.

The code has been well documented with comments, and hopefully, the reader will not find it difficult to understand.

Public and Private Key Generation

Private Key is mandatory for digital signature generation. When you generate the Private Key, the corresponding Public key is automatically generated. For performance, Private / Public Keys are generated only once and stored at physical location of the HDD. The methodology adopted in the current code is to store the public key at some application path. However, for web applications, key may be streamed along with data. See figure.

The following function generates the Public and Private Keys and stores them at the specified location. This function also invokes functions to generate the compatible .NET Public Key. It takes the size of the hash algorithm as a parameter and generates the corresponding key.

Now, let's look at the corresponding code:

   * Generates the keys for given size.
   * @param size - Key Size [512|1024]
  public void generateKeys(int size) {
    try {
      System.out.println("Generating Keys");
      keyGen = KeyPairGenerator.getInstance("RSA");
      keypair = keyGen.genKeyPair();
      //Get the KeyPair for given algorithm and size.

      privateKey = keypair.getPrivate(); //Extract Private Key
      publicKey = keypair.getPublic();    // Extract Public Key

      // Get bytes of the public and private keys
      byte[] privateKeyBytes = privateKey.getEncoded(); //Get the key bytes
      byte[] publicKeyBytes = publicKey.getEncoded();  // Get the key bytes

      //write bytes to corresponding files after encoding
      //them to Base 64 using Base64Encoder Class.

      String encodedValue = new BASE64Encoder().encode(publicKeyBytes);
      writeKeyBytesToFile(encodedValue.getBytes(), PUBLIC_KEY_FILE);

      //Generate the Private Key, Public Key and Public Key in XML format.
      PrivateKey privateKey = 

      PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new

      //Create and Instance of RSAPublicKey class with X509 encoding
      RSAPublicKey rsaPublicKey =

      //Get the RSAPublicKey as XML store the public key in XML string
      //to make compatible .Net public key
      //file. See getRSAPublicKeyAsXMLString() for details
      String xml = getRSAPublicKeyAsXMLString(rsaPublicKey);

      //Store the XML (Generated .Net public key file) in file
      writeKeyBytesToFile(xml.getBytes(), DOT_NET_PUBLIC_KEY_FILE);
    catch ( e) {
          "No such algorithm. Please check the JDK version."+e.getCause());
    catch ( ik) {
          "Invalid Key Specs. Not valid Key files."+ ik.getCause());
    catch (UnsupportedEncodingException ex) {
    catch (ParserConfigurationException ex) {
    catch (TransformerException ex) {
    catch (IOException ioe) {
      System.out.println("Files not found on specified path. "+


Once the keys are generated, they can be stored at specific path in a simple file to avoid re-generation of Private and Public keys. It increases the performance. There may be a requirement to generate new keys each time for each request. If you want to generate the keys each time then invoke this function each time in main function or in your application before signing the data.

Public and Private Key initialization from stored files

Following two functions read the public and private keys. Whenever you have to sign the data, you only require a private key. Therefore, I have provided an additional function to initialize only the private key. The basic work flow of this function is described in the figure.

Let's look at the code now. As by name, it is clear the initializePrivateKey only initializes the private key, but if you wish to initialize both private and public keys, invoke the other function named as initializeKeys.

   * Initialize only the private key.
  private void initializePrivateKey() {
    try {
      //Read key files back and decode them from BASE64
      BASE64Decoder decoder = new BASE64Decoder();
      byte[] privateKeyBytes = decoder.decodeBuffer(new
      // Convert back to public and private key objects
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      EncodedKeySpec privateKeySpec = new
      privateKey = keyFactory.generatePrivate(privateKeySpec);

    catch (IOException io) {
      System.out.println("Private Key File Not found."+
    catch (InvalidKeySpecException e) {
      System.out.println("Invalid Key Specs. Not valid Key files."
      + e.getCause());
    catch (NoSuchAlgorithmException e) {
      System.out.println("There is no such algorithm." +
      " Please check the JDK ver."+ e.getCause());


   * Initializes the public and private keys.
  private void initializeKeys() {
    try {
      //Read key files back and decode them from BASE64
      BASE64Decoder decoder = new BASE64Decoder();
      byte[] privateKeyBytes = decoder.decodeBuffer(new
      byte[] publicKeyBytes = decoder.decodeBuffer(new

      // Convert back to public and private key objects
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      EncodedKeySpec privateKeySpec =
                     new PKCS8EncodedKeySpec(privateKeyBytes);
      privateKey = keyFactory.generatePrivate(privateKeySpec);

      EncodedKeySpec publicKeySpec =
                    new X509EncodedKeySpec(publicKeyBytes);
      publicKey = keyFactory.generatePublic(publicKeySpec);

    catch (IOException io) {
      System.out.println("Public/ Private Key File Not found."
      + io.getCause());
    catch (InvalidKeySpecException e) {
      System.out.println("Invalid Key Specs. Not valid Key files."
      + e.getCause());
    catch (NoSuchAlgorithmException e) {
      System.out.println("There is no such algorithm." +
      " Please check the JDK ver."+ e.getCause());

Signing the Data

As it is evident from the function name, that function is responsible for signing the data sent as bytes. Prior to this function invocation, the private key initialization is must. Either read the existing private key or generate a new private key. See figure.

   * Signs the data and return the signature for a given data.
   * @param toBeSigned Data to be signed
   * @return byte[] Signature
  public byte[] signData(byte[] toBeSigned) {
    if (privateKey == null) {
    try {
      Signature rsa = Signature.getInstance("SHA1withRSA");
      rsa.initSign(privateKey); //initialize the signature with provided key
      rsa.update(toBeSigned); //sign the data
      return rsa.sign(); //return the signature in bytes
    catch (NoSuchAlgorithmException ex) {
    catch (InvalidKeyException in) {
      System.out.println("Invalid Key file." +
      "Please chekc the key file path"+ in.getCause());
    catch (SignatureException se) {
    return null;

Verify data and Signature

Verifying the data is fairly simple. The following function is responsible for verifying the signature for corresponding data, sent as bytes. The signature is verified with the Public Key. See figure.

   * Verifies the signature for the given bytes using the public key.
   * @param signature Signature
   * @param data Data that was signed
   * @return boolean True if valid signature else false
  public boolean verifySignature(byte[] signature, byte[] data) {
    try {
      // Initialize the keys before verifying the signature
      //Initialize the signature engine instance with public key
      // load the data to be verified
      // verify the data loaded in previous step
      // with given signature and return the
      return sign.verify(signature);
    catch (SignatureException e) {
    catch (InvalidKeyException e) {

    return false;

Section 3: Generating .NET compatible Public Key

.NET RSA Public Key XML

.NET RSA Public Key contains Modulus and Exponent which can be extracted from the Java Public key. Before we look into the Java code details, let's look at the XML which can be transformed into the RSAParameters structure. The Modulus represents the Modulus parameter for the RSA algorithm while Exponent represents the Exponent parameter for the RSA Algorithm. The RSA algorithm class in .NET is available under the namespace System.Security.Cryptography.RSA.

The .NET RSA Public XML key structure is given below.

<?xml version="1.0" encoding="UTF-8"?>



Generating .NET XML Public Key from Java

In this section, we will discuss the methodology adopted to export the Java public key class as .NET compatible public key. The exported XML key will be later loaded in our .NET application and we will verify the signature by using this key.

Let's look at the code.

Recall from our Key Generation process that we invoked some functions to generate the Public key in XML format.

      //Create and 
Instance of RSAPublicKey class with X509 encoding key specs
      RSAPublicKey rsaPublicKey = (RSAPublicKey) 
          generatePublic(new X509EncodedKeySpec(publicKeyBytes));

      //Get the RSAPublicKey as XML store the public key
      //in XML string to make compatible .Net public key
      //file. See getRSAPublicKeyAsXMLString() for details
      String xml = getRSAPublicKeyAsXMLString(rsaPublicKey);

      //Store the XML (Generated .Net public key file) in file
      writeKeyBytesToFile(xml.getBytes(), DOT_NET_PUBLIC_KEY_FILE);

If you see the first line, X509EncodedKeySpec has been used. This class represents the ASN.1 encoding of a public key, encoded according to the ASN.1 type SubjectPublicKeyInfo. The SubjectPublicKeyInfo syntax is defined in the X.509 standard as follows:

SubjectPublicKeyInfo ::= SEQUENCE {
   algorithm AlgorithmIdentifier,
   subjectPublicKey BIT STRING }

Now, look at the function named as getRSAPublicKeyAsXMLString:

   * Gets the RSA Public key as XML string.
   * @param key RSAPublicKey
   * @return String XML representation of RSA Public Key.
   * @throws UnsupportedEncodingException
   * @throws ParserConfigurationException
   * @throws TransformerException
  private String getRSAPublicKeyAsXMLString(RSAPublicKey key) throws
      TransformerException {
    Document xml = getRSAPublicKeyAsXML(key);
    Transformer transformer =
    StringWriter sw = new StringWriter();
    transformer.transform(new DOMSource(xml), new StreamResult(sw));
    return sw.getBuffer().toString();

   * Gets the RSA Public Key as XML. The idea is to make the key readable 
   * .Net platform. The generated key is compatible with .Net key structure.
   * @param key RSAPublicKey
   * @return Document XML document.
   * @throws ParserConfigurationException
   * @throws UnsupportedEncodingException
  private Document getRSAPublicKeyAsXML(RSAPublicKey key) throws
      UnsupportedEncodingException {
    Document result =
    Element rsaKeyValue = result.createElement("RSAKeyValue");
    Element modulus = result.createElement("Modulus");

    byte[] modulusBytes = key.getModulus().toByteArray();
    modulusBytes = stripLeadingZeros(modulusBytes);
//  KeyManager.write("c:\\mod.c",
//    new sun.misc.BASE64Encoder().encode(modulusBytes));
//    //Stored it for testing purposes
        new String(new sun.misc.BASE64Encoder().encode(modulusBytes))));

    Element exponent = result.createElement("Exponent");

    byte[] exponentBytes = key.getPublicExponent().toByteArray();
//  KeyManager.write("C:\\exponenet.c",
//   new sun.misc.BASE64Encoder().encode(exponentBytes));
//      //stored it for testing purposes
        new String(new sun.misc.BASE64Encoder().encode(exponentBytes))));

    return result;

The above mentioned functions allow us to generate the XML file which contains the Public Key Information. We store this file on the hard disk or stream it over the network.

Section 4: Reading Public Key and verifying the Data in .NET

In this section, we will read the Public key which was generated in the previous section by the Java program.


In the constructor, initialize RSAParameters class and RSACryptoServiceProvider.

PUBLIC_KEY="c:\\netpublic.key"; //Generated by Java Program
RSAKeyInfo = new RSAParameters();
RSA = new RSACryptoServiceProvider();

Reading Public Key in .NET

Following function reads the file from the specific path on HDD. One may use network stream to read the XML file. Parse the modulus data and exponent data and assign them to variables. Convert the strings from Base64 and assign them to RSAParameters.Modulus and RSAParameters.Exponent. ImportParameters function of RSACryptoServiceProvider is used to load the parameters for RSA algorithm.

private void readKey()
   // read the XML formated public key

    XmlTextReader reader = new XmlTextReader(PUBLIC_KEY);
     if (reader.NodeType == XmlNodeType.Element)
       modStr= reader.Value;
      else if(reader.Name=="Exponent")
       expStr= reader.Value;
    if(modStr.Equals("") ||expStr.Equals(""))
     //throw exception
     throw new Exception("Invalid public key");
    RSAKeyInfo.Modulus = Convert.FromBase64String(modStr);
    RSAKeyInfo.Exponent = Convert.FromBase64String(expStr);
   catch(Exception e)
    throw new Exception("Invalid Public Key.");

Verifying the Signature in .NET

The signature can be verified once the Modulus and Exponent have been parsed from the XML and loaded in RSACryptoServiceProvider. verifySignature method is invoked to verify the signature for given data. It verifies the specified signature data by comparing it to the signature computed for the specified data. See figure.

public bool verifySignature(byte[] 
signature , string signedData)
   byte[] hash = Convert.FromBase64String(signedData);
     //Console.WriteLine("The signature is valid.");
     return true;
     //Console.WriteLine("The signature is not valid.");
     return false;
   catch(Exception e)
    return false;



Special thanks to:

  • Dr. Iman Gholampur
  • Philip Ross
  • Mitch Gallant


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Shaheryar Ch.
Software Developer (Senior)
United Arab Emirates United Arab Emirates
Shaheryar specializes in architecture, design, development and deployment of J2EE and .Net enterprise applications. He got hooked with enterprise application development during his Masters and has been devoted to it ever since.

He was born in Lahore-Pakistan and holds a Bachelors degree in Computer Science (Major in Software Engg.) from Mohammed Ali Jinnah University, Islamabad-Pakistan.

Presently he is working as GIS Software Engineer for Client / Server J2EE (Web/Desktop) Applications in Middle East.

His skill set includes Java, JSP, Servlet, Massive EJB component development, J2EE essential design patterns, JDBC, JAAS, JMS, Java Help System, Java XML Parsers, web design, symmetric & asymmetric encryption (AES, DES, RSA), JavaScript, PDF417 2D Barcodes, ASP.Net, C#, Visual C++, AWT/Swing, UML, ArcIMS, ArcXML, ESRI Map Objects Java, Coldfusion, JBoss AS, Oracle 10g AS, Tomcat, IIS and JRun. He has successfully developed and deployed cross platform applications on IRIX, Linux and Windows platforms.

He usually works late hours with some heavy music and prefers to test and prove everything to his own satisfaction before committing himself and likes to finish what he starts without interruptions.

He loves playing guitar, bowling, snooker and cricket.

You may also be interested in...


Comments and Discussions

QuestionDear Sir? I cannot download your souce code? Pin
Member 133389811-Aug-17 17:24
memberMember 133389811-Aug-17 17:24 
GeneralMy vote of 5 Pin
purplepangolin24-Nov-10 0:04
memberpurplepangolin24-Nov-10 0:04 
QuestionHow about the reverse process? Pin
AnDong197818-Mar-10 0:23
memberAnDong197818-Mar-10 0:23 
noothersam22-Feb-10 23:52
membernoothersam22-Feb-10 23:52 
QuestionHow to decipher data in .NET using "RSA/ECB/PKCS1Padding"? Pin
Jadhav Ajay21-Apr-09 7:53
groupJadhav Ajay21-Apr-09 7:53 
GeneralPKCS#8 and X.509 Pin
Jeffrey Walton27-Apr-08 2:31
mvpJeffrey Walton27-Apr-08 2:31 
GeneralExcellent kick start for me Pin
pulavas10-Aug-06 5:08
memberpulavas10-Aug-06 5:08 
GeneralRe: Excellent kick start for me Pin
tyrone152813-Mar-08 18:57
membertyrone152813-Mar-08 18:57 
GeneralRe: Excellent kick start for me Pin
Jeffrey Walton30-Apr-08 3:22
mvpJeffrey Walton30-Apr-08 3:22 
GeneralEncrypt &amp; Decrypt From JAVA to NET to JAVA Pin
srinivas_temp01@sirigina.com3-Feb-05 7:42
membersrinivas_temp01@sirigina.com3-Feb-05 7:42 
GeneralRe: Encrypt &amp; Decrypt From JAVA to NET to JAVA Pin
ashokt823-Sep-06 2:24
memberashokt823-Sep-06 2:24 
GeneralUsage of PEM format open SSL key to encrypt data in .NET Pin
Colorado20048-Nov-04 9:38
memberColorado20048-Nov-04 9:38 
Hello all,

I have an existing PEM format public/private key pair that I generated using the libeay32.lib in openssl. Is it possible for me to use the same key with the .NET crypto library to encrypt and decrypt data?

I am able to read the modulus and exponent members from the old public key and set them in the RSAParameters struct. I then use the Encrypt function of RSACryptoServiceProvider to encrypt data. However i am unable to decrypt the same data. Whenever i try to set the private exponent members in RSAParameters, i get bad data and decryption fails
THis is how i am reading the data members from the openssl RSA struct.

unsigned char* tempChar=new unsigned char[256];
unsigned char* tempChar1=new unsigned char[256];
int iTemp=BN_bn2bin(m_RSAKey->p, tempChar);//this is how i read all the members like p,q,n,e,d etc

Base64Coder b64;
DWORD decodeLen = 0;
b64.Encode((PBYTE)tempChar, iTemp, (PBYTE&) tempChar1, decodeLen);

I then take this base64 encoded string , decode it and set it in the relevant member in the RSAParameters struct. For instance in the above case i would set it in the P member of the RSAParameters struct.

Is there any other way to approach this problem
I would appreciate any help, thoughts or insights on the above problem.

GeneralRe: Usage of PEM format open SSL key to encrypt data in .NET Pin
Shaheryar Ch.10-Nov-04 2:02
memberShaheryar Ch.10-Nov-04 2:02 
GeneralGoing the other way Pin
Kerry Sanders26-Oct-04 19:34
memberKerry Sanders26-Oct-04 19:34 
GeneralRe: Going the other way Pin
Shaheryar Ch.10-Nov-04 1:31
memberShaheryar Ch.10-Nov-04 1:31 
GeneralRe: Going the other way Pin
hieu.nguyez@gmail.com24-Mar-05 9:14
susshieu.nguyez@gmail.com24-Mar-05 9:14 
GeneralRe: Going the other way Pin
no_aol27-Apr-07 9:14
memberno_aol27-Apr-07 9:14 
GeneralRe: Going the other way Pin
Abyshai30-Nov-09 9:31
memberAbyshai30-Nov-09 9:31 
GeneralPorting DSA Keys Pin
Dirk Theune15-Oct-04 0:40
sussDirk Theune15-Oct-04 0:40 
GeneralRe: Porting DSA Keys Pin
Shaheryar Ch.20-Oct-04 8:08
memberShaheryar Ch.20-Oct-04 8:08 
GeneralRe: Porting DSA Keys Pin
Shaheryar Ch.20-Oct-04 8:59
memberShaheryar Ch.20-Oct-04 8:59 
GeneralRe: Porting DSA Keys Pin
dirk.theune22-Oct-04 3:52
memberdirk.theune22-Oct-04 3:52 
GeneralRe: Porting DSA Keys Pin
Saud AKhter23-Aug-12 5:46
memberSaud AKhter23-Aug-12 5:46 
QuestionWhat about certificates creation? Pin
DaberElay16-Jun-04 1:18
memberDaberElay16-Jun-04 1:18 
AnswerRe: What about certificates creation? Pin
Shaheryar Ch.8-Aug-04 0:13
memberShaheryar Ch.8-Aug-04 0:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.171114.1 | Last Updated 26 Oct 2004
Article Copyright 2004 by Shaheryar Ch.
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid