Decrypt RSA encrypted value generated from .net in Android [duplicate] - encryption

I have gone through many posts here but did not find the right solution. I want to decrypt a value encrypted in c# .net from Android.
I have successfully decrypted in .net platform using the following code snippet
public static void Main()
{
string _privateKey = Base64Decode("myprivatekey");
var rsa = new RSACryptoServiceProvider();
string data = "198,47,144,175,154,47,194,175,242,41,212,150,220,177,198,161,236,36,197,62,18,111,21,244,232,245,90,234,195,169,141,195,139,199,131,163,26,124,246,50,102,229,73,148,18,110,170,145,112,237,23,123,226,135,158,206,71,116,9,219,56,96,140,19,180,192,80,29,63,160,43,127,204,135,155,67,46,160,225,12,85,161,107,214,104,218,6,220,252,73,252,92,152,235,214,126,245,126,129,150,49,68,162,120,237,246,27,25,45,225,106,201,251,128,243,213,250,172,26,28,176,219,198,194,7,202,34,210";
var dataArray = data.Split(new char[] { ',' });
byte[] dataByte = new byte[dataArray.Length];
for (int i = 0; i < dataArray.Length; i++)
{
dataByte[i] = Convert.ToByte(dataArray[i]);
}
rsa.FromXmlString(_privateKey);
var decryptedByte = rsa.Decrypt(dataByte, false);
Console.WriteLine(_encoder.GetString(decryptedByte));
}
Now I want to do the same process in Android app. Please can somebody guide me through this?
I have tried the following code but its throwing javax.crypto.IllegalBlockSizeException: input must be under 128 bytes exception
String modulusString = "hm2oRCtP6usJKYpq7o1K20uUuL11j5xRrbV4FCQhn/JeXLT21laKK9901P69YUS3bLo64x8G1PkCfRtjbbZCIaa1Ci/BCQX8nF2kZVfrPyzcmeAkq4wsDthuZ+jPInknzUI3TQPAzdj6gim97E731i6WP0MHFqW6ODeQ6Dsp8pc=";
String publicExponentString = "AQAB";
byte[] modulusBytes = Base64.decode(modulusString, DEFAULT);
byte[] exponentBytes = Base64.decode(publicExponentString, DEFAULT);
BigInteger modulus = new BigInteger(1, modulusBytes);
BigInteger publicExponent = new BigInteger(1, exponentBytes);
RSAPrivateKeySpec rsaPubKey = new RSAPrivateKeySpec(modulus, publicExponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey pubKey = fact.generatePrivate(rsaPubKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] plainBytes = result.getBytes("UTF-16LE");
byte[] cipherData = cipher.doFinal(plainBytes);
String encryptedStringBase64 = Base64.decode(cipherData, DEFAULT).toString();

Related

DATA ENCRYPTION 2048 RSA Algorithm using public key in mvc

i want to encrypt a json data
{
"urc": "7718313198",
"umc": "101871",
"ak": "asdfgh123456",
"fname": "Biswajit",
"lname": "Dolui",
"email": "retailer001#giblvirtualmail.com",
"phno": "7718313198",
"pin": "712410"
}
i could not encrypt long string in asp.net using rsa algorithm 2048
var csp = new RSACryptoServiceProvider(2048);
//how to get the private key
var privKey = csp.ExportParameters(true);
//and the public key ...
var pubKey = csp.ExportParameters(false);
//converting the public key into a string representation
string pubKeyString;
{
//we need some buffer
var sw = new System.IO.StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, pubKey);
//get the string from the stream
pubKeyString = sw.ToString();
}
//converting it back
{
//get a stream from the string
var sr = new System.IO.StringReader(pubKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
pubKey = (RSAParameters)xs.Deserialize(sr);
}
//conversion for the private key is no black magic either ... omitted
//we have a public key ... let's get a new csp and load that key
csp = new RSACryptoServiceProvider();
csp.ImportParameters(pubKey);
//we need some data to encrypt
var plainTextData = "{urc: 7718313198,umc: 101871,ak: asdfgh123456,fname: Biswajit,lname: Dolui,email: biswajitdoluicse#gmail.com,phno: 7718313198}";
//for encryption, always handle bytes...
var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(plainTextData);
//apply pkcs#1.5 padding and encrypt our data
var bytesCypherText = csp.Encrypt(bytesPlainTextData, false);
//we might want a string representation of our cypher text... base64 will do
var cypherText = Convert.ToBase64String(bytesCypherText);

Java TripleDES PKCS5Padding decryption to C# - bad data / padding error

I'm trying to write the C# equivalent for the following Java code:
protected static final String DES_ECB_PKCS5PADDING = "DESede/ECB/PKCS5Padding";
public static String decryptValueDirect(String value, String key)
throws NoSuchAlgorithmException, NoSuchPaddingException,
GeneralSecurityException, IllegalBlockSizeException,
BadPaddingException {
byte[] bytes = Base64.decodeBase64(value);
Cipher cipher = Cipher.getInstance(DES_ECB_PKCS5PADDING);
cipher.init(Cipher.DECRYPT_MODE, convertSecretKey(key.getBytes()));
byte[] decryptedValue = cipher.doFinal(bytes);
String nstr = new String(decryptedValue);
return nstr;
}
protected static SecretKey convertSecretKey(byte[] encryptionKey) throws GeneralSecurityException {
if (encryptionKey == null || encryptionKey.length == 0)
throw new IllegalArgumentException("Encryption key must be specified");
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(TRIPLEDES);
KeySpec keySpec = new DESedeKeySpec(encryptionKey);
return keyFactory.generateSecret(keySpec);
}
The source text is a base64 encoded, then encrypted and then base64 encoded for transport on a rabbit queue. Our vendor who handles the encryption provided the above for decryption in Java, but has no idea about C#.
The only input on the encryption side is a key, a random string. We use the same string for encryption/decryption 012345678901234567890123456789 in our dev env. That is the only input, no salt, hashing (that i see) or pw iterations. The only requirement is that it is at least 24 chars long.
My C# code is below and a fiddle of my attempt is here.
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
public class Program
{
public static void Main()
{
//Message Data value
//We are using encrypted multibyte.
string myData = #"ROE8oYeV7B6faUsvfIx0Xe55vSs9IR5DlWGRbSM+lmKmLcaJsA13VudwWlAEYtLUD8+nMXShky0grSxsk0Z9cQe5V45XnAIfUhnyzI9a0jtMFC8XnIZ5dbclPO/V73QnieIZDkbNV5cPo3BM+l79ai96KB/gkF3xuerFPxvWejtPyWbOyO+FfNyFps4gAYDITsYIAEH39VP4eipmQ5zc18BA39lajQ3UaVewSxz7H+x3Ooe2SzJT/TQWRkioJSEFwexqzkHiLOQ0MOCIVD9xTWpLYnsL3LMwyF6H8f0PY4Fc57LVGhvUZ7dsB9NWUAnmG3uqbsonNFVhuXyvJTWNyFOHwFzOMx6XDLJJFHGZhaHg2VrescfnpUtonQY08RgojBngyJNRqK8URAvI3bqKq8Y7F/9HmEtMIIQe6KuuTmU=";
string myKey = "012345678901234567890123456789";//Development Env Key.
Console.WriteLine("Decrypt1:");
string s = Decrypt1(myData, myKey);
Console.ReadLine();
}
public static string Decrypt1(string value, string decryptionKey)
{
string decryptString = "";
TripleDESCryptoServiceProvider tDESalg = new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider hashMD5Provider = new MD5CryptoServiceProvider();
try
{
byte[] decodedData = Convert.FromBase64String(value);
tDESalg.Mode = CipherMode.ECB;
tDESalg.Padding = PaddingMode.PKCS7;//According to MS, same as PKCS5PADDING
byte[] Key = hashMD5Provider.ComputeHash(Encoding.UTF8.GetBytes(decryptionKey));
//byte[] IV = tDESalg.IV;
byte[] IV = new byte[tDESalg.BlockSize / 8]; //The size of the IV property must be the same as the BlockSize property divided by 8
var memoryStream = new MemoryStream(decodedData);
var cryptoStream = new CryptoStream(memoryStream, tDESalg.CreateDecryptor(Key, IV), CryptoStreamMode.Read);
var reader = new StreamReader(cryptoStream);
decryptString = reader.ReadToEnd();
byte[] decryptData = Convert.FromBase64String(decryptString);
}
catch (Exception e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message + e.StackTrace);
return null;
}
return decryptString;
}
}
Searching seems to point to the same answer, the key, encoding, ... all must be the same. I just don't know what that would be the equivalent for the Java source provided. :) Any suggestions will be helpful.
MD5 has a 16-byte output, Triple DES (3DES) requires a 24-byte key. There is a key size mis-match.
The C# and Java key derivations are substantially different:
C#:
byte[] Key = hashMD5Provider.ComputeHash(Encoding.UTF8.GetBytes(decryptionKey));
returns 16-bytes.
Java:
SecretKeyFactory.getInstance(TRIPLEDES)
returns 24-bytes.
There is a key option (2TDEA) where a 16-byte key is used and the first 8-bytes will be duplicated to create the last 8-bytes. NIST has deprecated this option.
Some implementations will accept a 16-byte key and extend the key to 24-bytes and some will not. You should provide all 24-bytes to 3DES, do not rely on an implementation to create the 24-byte key.
Note: The question was updated so it is not clear that the the actual encrytpion key is derived.

encrypt in .net core with TripleDES

public static string Encrypt(string toEncrypt, string secretKey)
{
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
var md5Serv = System.Security.Cryptography.MD5.Create();
keyArray = md5Serv.ComputeHash(UTF8Encoding.UTF8.GetBytes(secretKey));
md5Serv.Dispose();
var tdes = System.Security.Cryptography.TripleDES.Create();
//set the secret key for the tripleDES algorithm
tdes.Key = keyArray;
//mode of operation. there are other 4 modes.
//We choose ECB(Electronic code Book)
tdes.Mode = CipherMode.ECB;
//padding mode(if any extra byte added)
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateEncryptor();
//transform the specified region of bytes array to resultArray
byte[] resultArray =
cTransform.TransformFinalBlock(toEncryptArray, 0,
toEncryptArray.Length);
//Release resources held by TripleDes Encryptor
tdes.Dispose();
//Return the encrypted data into unreadable string format
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
secretkey = 16 character of string
in this line :
tdes.Key = keyArray;
i get this error:
Message = "Specified key is not a valid size for this algorithm."
error Message screen shot
how to solved this problem in asp.net core 1.1.0?
how to convert byte[16] to byte[24]?
Updated Post
thanks For Help :) but!
I use this code in .Net Framework 4.6.2 for encrypt:
public static string Encrypt(string toEncrypt, string secretKey)
{
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
System.Configuration.AppSettingsReader settingsReader = new AppSettingsReader();
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(secretKey));
hashmd5.Clear();
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
//set the secret key for the tripleDES algorithm
tdes.Key = keyArray;
//mode of operation. there are other 4 modes.
//We choose ECB(Electronic code Book)
tdes.Mode = CipherMode.ECB;
//padding mode(if any extra byte added)
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateEncryptor();
//transform the specified region of bytes array to resultArray
byte[] resultArray =
cTransform.TransformFinalBlock(toEncryptArray, 0,
toEncryptArray.Length);
//Release resources held by TripleDes Encryptor
tdes.Clear();
//Return the encrypted data into unreadable string format
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
and Use this in .Net Core 1.1 :
public static string Encrypt(string toEncrypt, string secretKey)
{
byte[] keyArray;
byte[] resultArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
using (var md5Serv = System.Security.Cryptography.MD5.Create())
{
keyArray = md5Serv.ComputeHash(UTF8Encoding.Unicode.GetBytes(secretKey));
if(keyArray.Length==16)
{
byte[] tmp = new byte[24];
Buffer.BlockCopy(keyArray, 0, tmp, 0, keyArray.Length);
Buffer.BlockCopy(keyArray, 0, tmp, keyArray.Length, 8);
keyArray = tmp;
}
}
using (var tdes = System.Security.Cryptography.TripleDES.Create())
{
//set the secret key for the tripleDES algorithm
tdes.Key = keyArray;
//mode of operation. there are other 4 modes.
//We choose ECB(Electronic code Book)
tdes.Mode = CipherMode.ECB;
//padding mode(if any extra byte added)
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateEncryptor();
//transform the specified region of bytes array to resultArray
resultArray =
cTransform.TransformFinalBlock(toEncryptArray, 0,
toEncryptArray.Length);
}
//Return the encrypted data into unreadable string format
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
but i don't know why this methods give me different result?!
if (key.Length == 16)
{
byte[] tmp = new byte[24];
Buffer.BlockCopy(key, 0, tmp, 0, key.Length);
Buffer.BlockCopy(key, 0, tmp, key.Length, 8);
key = tmp;
}
That will turn your 2DES key (k1, k2) into the 3DES key (k1, k2, k1). FWIW, this has been fixed for .NET Core 2.0 (https://github.com/dotnet/corefx/issues/9966).
So, now your code will work again. Though, as others have pointed out in comments, there's a lot going on in your code which is not considered cryptologically sound by modern standards. You should strongly consider taking this as an opportunity to enhance your encryption. (If you can't "because then it can't work with already existing data" then you should take this opportunity to add crypto-agility to your data, to permit you to move to different key schemes and/or algorithms over time.)

java.io.IOException: Error while finalizing cipher while decrypting sub-strings

I am running into an issue that I am not sure the proper fix. I used this thread as reference:
java.lang.IllegalArgumentException: bad base-64 when decrypting string
Basically I split a string into chunks and encrypt each chunk. But when it is time to decrypt the same way it never works. It always gives me this annoying exception:
"java.io.IOException: Error while finalizing cipher"
basically I split the string as below:
static public class RSAString {
private ArrayList<String> mChunkList = new ArrayList<String>();
RSAString() {
mChunkList.clear();
}
public ArrayList<String> getChunkList() {
return mChunkList;
}
RSAString(String stringSrc) {
if (stringSrc.length() < CHUNK_SIZE) {
mChunkList.add(stringSrc);
} else {
int j = 0;
for (int i = 0; i < stringSrc.length() / CHUNK_SIZE; i++) {
String subString = stringSrc.substring(j, j + CHUNK_SIZE);
mChunkList.add(subString);
j += CHUNK_SIZE;
}
int leftOver = stringSrc.length() % CHUNK_SIZE;
if (leftOver > 0) {
String subString = stringSrc.substring(j, j + leftOver);
mChunkList.add(subString);
}
}
}
}
Then I decrypt with this code:
// This **DOES NOT** work
final String AndroidOpenSSLString = "AndroidOpenSSL";
final String AndroidKeyStoreBCWorkaroundString = "AndroidKeyStoreBCWorkaround";
mProvider = Build.VERSION.SDK_INT < Build.VERSION_CODES.M ? AndroidOpenSSLString : AndroidKeyStoreBCWorkaroundString;
Cipher outCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", mProvider);
outCipher.init(Cipher.DECRYPT_MODE, mPrivateKey);
for (String chunkEncrypted : rsaEcryptedText.getChunkList()) {
byte[] cipherText = chunkEncrypted.getBytes("UTF-8");
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(Base64.decode(cipherText, Base64.NO_WRAP)), outCipher);
ArrayList<Byte> values = new ArrayList<>();
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
values.add((byte) nextByte);
}
byte[] bytes = new byte[values.size()];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = values.get(i);
}
decryptedString += new String(bytes, 0, bytes.length, "UTF-8");
cipherInputStream.close();
cipherInputStream.reset();
}
The only work around I found was to re-initialize the cypher every new sub-string. Like the hack below:
for (String chunkEncrypted : rsaEcryptedText.getChunkList()) {
// This works, but I am re-initializing the out cypher every time!
// super slow!!! WHY DO I HAVE TO DO THIS?
Cipher outCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", mProvider);
outCipher.init(Cipher.DECRYPT_MODE, mPrivateKey);
byte[] cipherText = chunkEncrypted.getBytes("UTF-8");
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(Base64.decode(cipherText, Base64.NO_WRAP)), outCipher);
ArrayList<Byte> values = new ArrayList<>();
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
values.add((byte) nextByte);
}
byte[] bytes = new byte[values.size()];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = values.get(i);
}
decryptedString += new String(bytes, 0, bytes.length, "UTF-8");
cipherInputStream.close();
cipherInputStream.reset();
}
The problem with my fix is that it makes the decryption much slower. Also, even with my sub-strings at small sizes (sub-string int CHUNK_SIZE = 64) I keep getting the same exception.
Anyway, I wonder if anyone can point me out the correct way to decrypt a long string with RSA encryption.
and here is the encryption code--not sure if it matters in this case--but it always works:
Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", mProvider);
inCipher.init(Cipher.ENCRYPT_MODE, mPublicKey);
RSAString rsaStringPlainText = new RSAString(plainText);
for (String chunkPlain : rsaStringPlainText.getChunkList()) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(
outputStream, inCipher);
cipherOutputStream.write(chunkPlain.getBytes("UTF-8"));
cipherOutputStream.flush();
cipherOutputStream.close();
byte[] ecryptedText = Base64.encode(outputStream.toByteArray(), Base64.NO_WRAP);
encryptedStringOut.mChunkList.add(new String(ecryptedText));
}
RSA is not suited for bulk encryption as it's quite slow (more than a factor 1000 when compared to AES). Instead use a symmetric encryption algorithm like AES if you can. If you need the two key's of RSA, use Hybrid encryption where you encrypt the data with a random symmetric key, and then encrypt that key with the RSA key.
Another benefit of symmetric encryption is that libraries automatically supports bulk encryption, where you don't need to handle chopping your data up into small blocks before encryption.

Implementing PHP AES Function in .NET (C#)

I have given a task in which I need to encrypt an user's ID using AES encryption, what they want is I need to pass in a parameter in a website just like this.
URL : http://www.site.com/event/sample.jce
Parameter : ?param= encrypted text
aside from that there was an attched php sample that they want me to follow to encrypt but I don't have an idea on how to convert this one in .NET
function getEncrypt($sStr, $sKey, $sIV){
$sCipher = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $sKey, $sStr, MCRYPT_MODE_CFB, $sIV);
return bin2hex($sCipher);
}
$sStr = "13410##13";
$sKey = "mediaservice1234";
$sKey = "kjcemsdev3jangho"; // Do not change
$sIV = "fs0tjwkdgh0akstp"; // Do not change
$tmp= getEncrypt($sStr, $sKey, $sIV);
Could somebody help me to understand this codes? or better if they could help me to convert this one on .NEt code? Thanks. :)
Try this, you need to set the FeedbackSize and Padding:
public static string Encrypt(string plaintext)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
//RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.FeedbackSize = 8;
rijndaelCipher.Mode = CipherMode.CFB;
rijndaelCipher.KeySize = 128;
// rijndaelCipher.BlockSize = 128;
rijndaelCipher.BlockSize = 128;
rijndaelCipher.Padding = PaddingMode.Zeros;
byte[] plaintextByte = System.Text.Encoding.ASCII.GetBytes(plaintext);
//Rfc2898DeriveBytes
ASCIIEncoding textConverter = new ASCIIEncoding();
rijndaelCipher.Key = textConverter.GetBytes(PRIVATEKEY); ;
rijndaelCipher.IV = Convert.FromBase64String(PRIVATEIV);
ICryptoTransform encryptor = rijndaelCipher.CreateEncryptor();
//http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(VS.80).aspx
//Encrypt the data.
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
//Convert the data to a byte array.
byte[] toEncrypt = textConverter.GetBytes(plaintext);
//Write all data to the crypto stream and flush it.
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
byte[] encrypted = new byte[16];
//Get encrypted array of bytes.
encrypted = msEncrypt.ToArray();
return Convert.ToBase64String(encrypted);
}
Here you can find some more information about using the AES encryption in .net:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged%28VS.80%29.aspx
The code is pretty straight forward.

Resources