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

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.

Related

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

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();

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);

How to achieve Xamarin.Android Asymmetric Encryption of RSA key?

Here's the code that i have implemented. Click here for errors. Do i have to import any nuget? Help
public string EncryptRSA(string plainText, string publicKeyString)
{
byte[] cipherText = null;
String strEncryInfoData = "";
try
{
KeyFactory keyFac = KeyFactory.getInstance("RSA");
KeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publicKeyString.trim().getBytes(), Base64.DEFAULT));
Key publicKey = keyFac.generatePublic(keySpec);
// get an RSA cipher object and print the provider
final Cipher cipher = Cipher.getInstance("RSA");
// encrypt the plain text using the public key
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
cipherText = cipher.doFinal(text.getBytes());
strEncryInfoData = new String(Base64.encode(cipherText, Base64.DEFAULT));
}
catch (Exception e)
{
}
return strEncryInfoData.replaceAll("(\\r|\\n)", "");
}
Your codes is in java , however, Xamarin using c#
Please use C# way to do RSA encryption.
If you dont mind, use mine
public class RSA {
public RSA() => Provider = new RSACryptoServiceProvider(2048);
public RSA(string key) {
Provider = new RSACryptoServiceProvider(2048);
Provider.FromXmlString(Encoding.UTF8.GetString(Convert.FromBase64String(key)));
}
public RSACryptoServiceProvider Provider;
public string PublicKey() => Convert.ToBase64String(Encoding.UTF8.GetBytes(Provider.ToXmlString(false)));
public string PrivateKey() => Convert.ToBase64String(Encoding.UTF8.GetBytes(Provider.ToXmlString(true)));
public string Encrypt(string meta) => Convert.ToBase64String(Provider.Encrypt(Encoding.UTF8.GetBytes(meta), RSAEncryptionPadding.Pkcs1));
public string Decrypt(string meta) => Encoding.UTF8.GetString(Provider.Decrypt(Convert.FromBase64String(meta), RSAEncryptionPadding.Pkcs1));
}
Usage:
var rsa = new RSA();
var generatePrivateKey = rsa.PrivateKey();
var generatePublicKey = rsa.PublicKey();
var encryted = new RSA(yourKey).Encrypt(yourText);
var decrypted = new RSA(yourKey).Decrypt(yourText);
Note, this class use 2048 bits and Pkcs1 padding as default, you can change it according to your flavor.

Crypto-Js with c#

I am learning about encryption and using crypto-js I have made a Js & c# version.
What I am trying to accomplish is that the JS or c# version will be able to decode each other messages.
For testing I have kept the IV and KEY , paddding and mode the same in both the JS and C# instance.
I have them both decrypting and encrypting data respectivly but what I have yet to accomplish is providing an encrypted from JS be able to decode using c#.
JS
var key = CryptoJS.enc.Base64.parse('7061737323313233');
var iv = CryptoJS.enc.Base64.parse('7061737323313233');
var encrypted = CryptoJS.AES.encrypt("It works", key,
{ keySize: 128 / 8, iv: iv, mode: CryptoJS.mode.CBC,padding: CryptoJS.pad.Pkcs7 });
var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
keySize: 128 / 8, iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
document.write('Encrypted :' + encrypted + '<br>');
document.write('Key :' + encrypted.key + '<br>');
document.write('Salt :' + encrypted.salt + '<br>');
document.write('iv :' + encrypted.iv + '<br>');
document.write('Decrypted : ' + decrypted + '<br>');
document.write('utf8 = ' + decrypted.toString(CryptoJS.enc.Utf8) + '<br>');
C#
public void startEncryption(string original )
{
using (RijndaelManaged myRijndael = new RijndaelManaged())
{
//Settings
myRijndael.Mode = CipherMode.CBC;
myRijndael.Padding = PaddingMode.PKCS7;
myRijndael.FeedbackSize = 128;
keybytes = Encoding.UTF8.GetBytes("7061737323313233");
//Should be made unique for each message!. TODO
iv = Encoding.UTF8.GetBytes("7061737323313233");
// Encrypt the string to an array of bytes.
encrypted = EncryptStringToBytes(original, keybytes, iv);
//Show Encrypted data
txt_Output.Text = Convert.ToBase64String(encrypted);
// Decrypt the bytes to a string.
string roundtrip = DecryptStringFromBytes(encrypted, keybytes, iv);
//Display the original data and the decrypted data.
Console.WriteLine("Original: {0}", original);
Console.WriteLine("Round Trip: {0}", roundtrip);
}
}
Where the problem arises in decryption.
private void btn_Decrypt_Click(object sender, EventArgs e)
{
Console.WriteLine("Decrypting..");
using (RijndaelManaged myRijndael = new RijndaelManaged())
{
//Settings
myRijndael.Mode = CipherMode.CBC;
myRijndael.Padding = PaddingMode.PKCS7;
myRijndael.FeedbackSize = 128;
keybytes = Encoding.UTF8.GetBytes("7061737323313233");
//Should be made unique for each message!. TODO
iv = Encoding.UTF8.GetBytes("7061737323313233");
// Decrypt the bytes to a string.
string roundtrip = DecryptToString(txt_Output.Text);
txt_Output.Text = roundtrip;
//Display the original data and the decrypted data.
}
}
public string DecryptToString(string TextValue)
{
return DecryptStringFromBytes(Convert.FromBase64String(TextValue), keybytes, iv);
}
static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
rijAlg.Padding = PaddingMode.PKCS7;
rijAlg.Mode = CipherMode.CBC;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt =
new CryptoStream(msDecrypt,decryptor,CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
I am producing different encrypted size strings:
JS:MhAP11fHa+fUfRzSw2UHVQ==
C#:+Ijpt1GDVgM4MqMAQUwf0Q==
I get Padding is invalid and cannot be removed, when trying to decrypt the JS string in c#
Where have I got wrong?.
Basically you run into encoding issues. First of all, you parse your IV using Base64 decoding in one implementation and one using direct character encoding in the other. Your Base64 strings don't look like Base64 strings either.
Furthermore, many libraries (incorrectly) allow that incorrect key and IV sizes are used. This is however confusing as there is no generic way for key or IV expansion. So you should make sure that the binary representations of the key and IV are correct for the specific algorithm.
For AES you should use a key size of 128, 192 or 256 bits and an IV size identical to the block size, 128 bits. The IV should be randomly generated and communicated to the other side, e.g. by prefixing the IV to the ciphertext.

Encrypting and Decrypting Office 2007 documents

I am trying to encrypt and decrypt 2007 office documents. I am using System.Security.Cryptographic namespace
I am using the following code
using System;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
using System.Text;
namespace CSEncryptDecrypt
{
class Class1
{
static void Main()
{
// Must be 64 bits, 8 bytes.
// Distribute this key to the user who will decrypt this file.
string sSecretKey;
// Get the Key for the file to Encrypt.
sSecretKey = GenerateKey();
// Encrypt the file.
EncryptionHelper.EncryptFile(#"XCD - FTW Proposal.docx",
#"Encrypted.txt",
sSecretKey);
// Decrypt the file.
EncryptionHelper.DecryptFile(#"Encrypted.txt",
#"OUTPUT\XCD - FTW Proposal.docx",
sSecretKey);
}
// Function to Generate a 64 bits Key.
static string GenerateKey()
{
// Create an instance of Symetric Algorithm. Key and IV is generated automatically.
DESCryptoServiceProvider desCrypto = (DESCryptoServiceProvider)DESCryptoServiceProvider.Create();
// Use the Automatically generated key for Encryption.
return ASCIIEncoding.ASCII.GetString(desCrypto.Key);
}
}
public class EncryptionHelper
{
public static void EncryptFile(string sInputFilename, string sOutputFilename, string sKey)
{
//GCHandle gch = GCHandle.Alloc(sKey, GCHandleType.Pinned);
FileStream fsInput = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename,
FileMode.Create,
FileAccess.Write);
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
DES.Padding = PaddingMode.PKCS7;
//DES.Padding = PaddingMode.ANSIX923;
ICryptoTransform desencrypt = DES.CreateEncryptor();
CryptoStream cryptostream = new CryptoStream(fsEncrypted,
desencrypt,
CryptoStreamMode.Write);
byte[] bytearrayinput = new byte[fsInput.Length];
fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
cryptostream.Flush();
cryptostream.Close();
fsInput.Flush();
fsInput.Close();
fsEncrypted.Close();
}
public static void DecryptFile(string sInputFilename, string sOutputFilename, string sKey)
{
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
//A 64 bit key and IV is required for this provider.
//Set secret key For DES algorithm.
DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
//Set initialization vector.
DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
//Create a file stream to read the encrypted file back.
FileStream fsread = new FileStream(sInputFilename,
FileMode.Open,
FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename,
FileMode.Create,
FileAccess.Write);
//Create a DES decryptor from the DES instance.
ICryptoTransform desdecrypt = DES.CreateDecryptor();
//Create crypto stream set to read and do a
//DES decryption transform on incoming bytes.
CryptoStream cryptostreamDecr = new CryptoStream(fsread,
desdecrypt,
CryptoStreamMode.Read);
byte[] fileData = new byte[fsread.Length];
cryptostreamDecr.Read(fileData, 0, (int)fsread.Length);
fsEncrypted.Write(fileData, 0, fileData.Length);
fsread.Flush();
fsread.Close();
fsEncrypted.Flush();
fsEncrypted.Close();
cryptostreamDecr.Flush();
cryptostreamDecr.Close();
}
}
}
The above code works fine for doc,xls,ppt,txt files but it currupts .xlsx,pptx and docx files . When i try to open the file it prompts a repair window saying the file is currupted .. Any idea ?
I am facing the same problem however when I used a buffer of size 1 (useless) the problem disappeared, I believe there is a bunch of extra bytes added and Office suite software can detect such tampering =\

Resources