rriggs
rriggs

Reputation: 21

How to Encrypt in C# .NET same as Java code

I need to send an encrypted string from a private key to a webserver for authentication. I have Java client code that generates the encrypted string correctly (such that the webserver can decrypt it with the public key). I am trying to write C# code to perform the exact same encryption - but have not succeeded.

First a keystore was generated in java using keytool similar to this:

keytool -genkey -dname "cn=Application Test, ou=XXX, o=YYY, c=US" -alias AppTest -keypass AppTest -keystore AppTest.jks -storepass AppTest -validity 1800 -keyalg RSA

Then this java code correctly reads the keystore and encrypts the data (privateKey.getAlgorithm() returns "RSA"):

KeyStore ks = KeyStore.getInstance("JKS");
InputStream is = new FileInputStream("AppTest.jks");
ks.load(is, "AppTest".toCharArray());
is.close();
PrivateKey privateKey = (PrivateKey) ks.getKey(user, password.toCharArray());

// Encrypt with the private key
String stamp = "123456";
byte[] bytesStampUtf8Unencrypted = stamp.getBytes(Charset.forName("UTF-8"));
Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] bytesTimestampUtf8Encrypted = cipher.doFinal(bytesStampUtf8Unencrypted);
String encrypted = new String((new Base64()).encode(bytesStampUtf8Unencrypted));

This all works great when passed to the web service. I then used keytool to convert from the java keystore to an PKCS12 certificate for use in my .NET application:

keytool -importkeystore -srckeystore AppTest.keystore -destkeystore KEYSTORE.p12  -srcstoretype JKS -deststoretype PKCS12 -srcstorepass AppTest -deststorepass AppTest-srcalias AppTest -destalias AppTest -srckeypass AppTest -destkeypass AppTest -noprompt

Using keytool I compared the finger prints of the keystore and P12 files - identical. I thought the following C# code should work:

X509Certificate2 myCertificate =
   new X509Certificate2(@"C:\Temp\KEYSTORE.p12", "AppTest");
RSACryptoServiceProvider privateKey =
   myCertificate.PrivateKey as RSACryptoServiceProvider;
String stamp = "123456";
byte[] buffer = Encoding.UTF8.GetBytes(stamp);
byte[] encryptedBytes = privateKey.Encrypt(buffer, false);
String encrypted = Convert.ToBase64String(encryptedBytes);

It reads the converted keystore file correctly, executes without problem, and generates what appears to be encrypted data, but the web service does NOT like the encrypted string (can't decrypt with the public key). When I replaced the C# encrypted string with the Java encrypted one (in the debugger) and sent that string through the C# program to the web service - it all worked as well - so I am confident the problem is in the encryption process, and not in the web service communication.

I have no control over the way the original key was generated (as a java keystore), nor what encryption method is expected by the web service. I can only control the .NET client that interacts with the Java based web service.

Am I missing some flag, setting, variable, what?

Upvotes: 2

Views: 8851

Answers (2)

Pankaj
Pankaj

Reputation: 1

This is a solution which is hard to find in working condition for Encrypt in Java and Decrypt in .Net and finally i was able to implement in one of my project,using this we can encrypt any string in java and decrypt that at .Net end using BouncyCastle API.

I have used Blowfish for Encryption/Decryption:

You can refer files etc for bouncycastle from : http://bouncycastle.org/latest_releases.html

Java code

  import org.bouncycastle.util.encoders.UrlBase64;
  import org.bouncycastle.crypto.engines.BlowfishEngine;
  import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
  import org.bouncycastle.crypto.params.KeyParameter;
  import org.bouncycastle.util.Strings;

  public class EncryptString
  {
public static void main(String[] args) throws Exception
{
String plain = "UserName=\'pgupta\'&Channel=\'1\'&LevelID=\'1\'&LevelName=\'Super Star colony\'";
     String key = "x-392kla%3$*1f";
//To getBytes in UTF8 Encoding
byte[] inBytes = plain.getBytes("UTF8");
byte[] keyByte = key.getBytes("UTF8"); 

PaddedBufferedBlockCipher _cipher = new PaddedBufferedBlockCipher(new BlowfishEngine());

try
{
_cipher.init(true, new KeyParameter(keyByte));

           // Determine the minimum output buffer size
byte[] outBytes = new byte[_cipher.getOutputSize(inBytes.length)];

        // 'len' is the actual size returned
     int len = _cipher.processBytes(inBytes, 0, inBytes.length, outBytes, 0);

_cipher.doFinal(outBytes,len);

         System.out.println("encrypted: " + new String(UrlBase64.encode(outBytes)));
}
catch(Exception e)
     {
         System.out.println("Exception: " + e.toString());
     }

}
  }

C# Code

using System;
using System.Collections.Generic;
using Org.BouncyCastle.Crypto.Paddings;
using System.Text;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Utilities.Encoders;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto;

public class Decrypt
{  

public string Decryption(string Request)
{
            String EncryptedS = Request;

            string convertHTML = string.Empty;
String key = ConfigurationSettings.AppSettings["EncDecKey"];//"123456789";

byte[] keyByte = Encoding.UTF8.GetBytes(key);   
try
{
byte[] result = BouncyCastleCrypto(false, UrlBase64.Decode(EncryptedS), key);
convertHTML = Encoding.UTF8.GetString(result);
}
catch (Org.BouncyCastle.Crypto.CryptoException ex)
{
convertHTML = "false";

}

return convertHTML;
}

private byte[] BouncyCastleCrypto(bool forEncrypt, byte[] input, string key)
{
try
{
byte[] keyByte = Encoding.UTF8.GetBytes(key);
_PaddedBufferedBlockCipherWithlowfish.Init(forEncrypt, new KeyParameter(keyByte));
byte[] outBytes = new byte[_PaddedBufferedBlockCipherWithlowfish.GetOutputSize(input.Length)];
int len = _PaddedBufferedBlockCipherWithlowfish.ProcessBytes(input, 0, input.Length, outBytes, 0);
_PaddedBufferedBlockCipherWithlowfish.DoFinal(outBytes, len);
return outBytes;

}
catch (Org.BouncyCastle.Crypto.CryptoException ex)
{
throw new CryptoException(ex.ToString());
}
}     
}

Note: Please make sure to use same key at both ends.

Upvotes: 0

Ta01
Ta01

Reputation: 31630

Are you certain that the encryption algorithm, the block cipher mode and padding mode are equivalent in your C# implementation when compared to your java implementation?

Edit: Actually for RSACryptoProvider you probably don't need cipher/padding mode - take a look at the example on MSDN, specifically the section on importing public key information via ImportParameters

Upvotes: 2

Related Questions