Equivalent code for System.Security.Cryptography in Java - java

I'm trying to convert the following C# code to Java, the code is using .NET library (System.Security.Cryptography), I want a work around to get the same results using Java:
internal static class CryptoHelper
{
// keys must be 16 characters long (and ASCII)
public const string DefaultKey = "2$8Kba19z23asd!#";
public const string IV = "0000000000000000";
enum CryptoTransformType
{
Encryptor,
Decryptor
}
public static byte[] Encrypt(bool FIPScompatible, string key, byte[] data)
{
if(key == null) throw new ArgumentNullException("key");
if(data == null) return null;
// Create the crypto
ICryptoTransform transform = CreateCryptoTransform(FIPScompatible,CryptoTransformType.Encryptor, key, IV);
// Encrypt the data
using(MemoryStream ms = new MemoryStream())
{
using(CryptoStream cs = new CryptoStream(ms, transform, CryptoStreamMode.Write))
{
cs.Write(data, 0, data.Length);
cs.FlushFinalBlock();
}
byte[] encryptedData = ms.GetBuffer();
return encryptedData;
}
}
public static byte[] Decrypt(bool FIPScompatible, string key, byte[] data)
{
if(key == null) throw new ArgumentNullException("key");
if(data == null) return null;
// Create the crypto
ICryptoTransform transform = CreateCryptoTransform(FIPScompatible,CryptoTransformType.Decryptor, key, IV);
// Decrypt the data
using(MemoryStream ms = new MemoryStream(data))
{
using(CryptoStream cs = new CryptoStream(ms, transform, CryptoStreamMode.Read))
{
byte[] decryptedData = new byte[data.Length];
cs.Read(decryptedData, 0, decryptedData.Length);
return decryptedData;
}
}
}
private static ICryptoTransform CreateCryptoTransform(bool FIPScompatible,CryptoTransformType transformType, string key, string iv)
{
if (!FIPScompatible)
{
RijndaelManaged rijndael = new RijndaelManaged();
rijndael.Mode = CipherMode.CBC;
rijndael.Padding = PaddingMode.Zeros;
rijndael.BlockSize = 128;
byte[] bykey = Encoding.ASCII.GetBytes(key);
byte[] byiv = Encoding.ASCII.GetBytes(iv);
ICryptoTransform transform = null;
if (transformType == CryptoTransformType.Encryptor)
transform = rijndael.CreateEncryptor(bykey, byiv);
else
transform = rijndael.CreateDecryptor(bykey, byiv);
return transform;
}
else
{
AesCryptoServiceProvider provider = new AesCryptoServiceProvider();
provider.Padding = PaddingMode.Zeros;
provider.BlockSize = 128;
byte[] bykey = Encoding.ASCII.GetBytes(key);
byte[] byiv = Encoding.ASCII.GetBytes(iv);
ICryptoTransform transform = null;
if (transformType == CryptoTransformType.Encryptor)
transform = provider.CreateEncryptor(bykey, byiv);
else
transform = provider.CreateDecryptor(bykey, byiv);
return transform;
}
}
}
I tried a method but I couldn't get the same results that comes out from the .NET code, the method I tried will be added in the comments.

Related

AES/GCM/NoPadding JAVA encryption doesn't match C# encryption

I'm using some encryption functions in C# and Java whose output doesn't seem to match. I've been fighting with this for a few days and thought I'd finally turn here for help.
Input string: "a"
Here is a snippet of the java implementation:
CryptoAesGcmService.getInstance().encryptData("a", aes_key)
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class CryptoAesGcmService {
private static CryptoAesGcmService instance;
private static final int GCM_TAG_LENGTH = 16;
private static final int GCM_IV_LENGTH = 12;
public static CryptoAesGcmService getInstance() {
if (instance == null) {
instance = new CryptoAesGcmService();
}
return instance;
}
public String encryptData(String plaintext, String key) throws Exception {
return encrypt2(plaintext, key, createGCMParameter());
}
private static String encrypt(String plaintext, String key, GCMParameterSpec gcmParameterSpec) throws Exception {
// return plaintext;
try {
byte[] plainTextByte = plaintext.getBytes(StandardCharsets.UTF_8);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, createSecretKeySpec(key), gcmParameterSpec);
byte[] cipherText = cipher.doFinal(plainTextByte);
return Base64.getEncoder().encodeToString(cipherText);
} catch (Exception e) {
throw new Exception("Unexpected exception occur.", e);
}
}
private static SecretKeySpec createSecretKeySpec(String secretKey) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(secretKey.getBytes(StandardCharsets.UTF_8));
return new SecretKeySpec(md.digest(), "AES");
}
private static GCMParameterSpec createGCMParameter() {
return new GCMParameterSpec(GCM_TAG_LENGTH * 8, new byte[GCM_IV_LENGTH]);
}
}
Output: fix 3UhjsGLxeoCyP/cd7c7p++I=
Here is a snippet of the .Net implementation:
aes.Encrypt("a", aes_key);
using System;
using System.Buffers.Binary;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
namespace api.Class
{
public class AESGCM
{
private const int KEY_BIT_SIZE = 256;
private const int MAC_BIT_SIZE = 128;
private const int NONCE_BIT_SIZE = 128;
private readonly SecureRandom random;
private static AESGCM instance;
public static AESGCM Instance //property of this class. Create an instance if it is not created yet
{
get
{
if (instance == null)
instance = new AESGCM();
return instance;
}
}
public AESGCM()
{
random = new SecureRandom();
}
//encrypt with strings
public string Encrypt(string text, string key, byte[] nonSecretPayload = null)
{
if (string.IsNullOrEmpty(text))
throw new ArgumentException("Text required!", "text");
//var decodedKey = Convert.FromBase64String(key);
var decodedKey = Encoding.UTF8.GetBytes(key);
var plainText = Encoding.UTF8.GetBytes(text);
var cipherText = EncryptWithKey(plainText, decodedKey, nonSecretPayload);
return Convert.ToBase64String(cipherText);
}
//encrypt with byte array
private byte[] EncryptWithKey(byte[] text, byte[] key, byte[] nonSecretPayload = null)
{
if (key == null || key.Length != KEY_BIT_SIZE / 8)
throw new ArgumentException(String.Format("Key needs to be {0} bit!", KEY_BIT_SIZE), "key");
nonSecretPayload = nonSecretPayload ?? new byte[] { };
var nonce = new byte[NONCE_BIT_SIZE / 8];
random.NextBytes(nonce, 0, nonce.Length);
var cipher = new GcmBlockCipher(new AesEngine());
var parameters = new AeadParameters(new KeyParameter(key), MAC_BIT_SIZE, nonce, nonSecretPayload);
cipher.Init(true, parameters);
var cipherText = new byte[cipher.GetOutputSize(text.Length)];
var len = cipher.ProcessBytes(text, 0, text.Length, cipherText, 0);
cipher.DoFinal(cipherText, len);
using (var combinedStream = new MemoryStream())
{
using (var binaryWriter = new BinaryWriter(combinedStream))
{
binaryWriter.Write(nonSecretPayload);
binaryWriter.Write(nonce);
binaryWriter.Write(cipherText);
}
return combinedStream.ToArray();
}
}
}
}
Output: always changing
example 1
4BNEStJ12YZIQsaFhOcufy1rgXW2/H5kBmPyBSVdf2qP
example 2
z4xNJgr6YLg+lsCA2jUn0HKorN8UXrVm0QtKl10w/Yba
example 3
0IxfAp2vIOmj3fvsJ25VVINHpnaxtZ5KNl89Qk7MNFcn
I want output .net same java. I don't know enough about encryption nor Java to know where to turn next. Any guidance would be greatly appreciated
UPDATE
I try to follow the advice but not working.
using System;
using System.Text;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
namespace api.Class
{
public class AESGCM
{
private const int KEY_BIT_SIZE = 256;
private const int MAC_BIT_SIZE = 128;
//encrypt with strings
public string Encrypt(string text, string key)
{
if (string.IsNullOrEmpty(text))
throw new ArgumentException("Text required!", "text");
var decodedKey = Encoding.UTF8.GetBytes(key);
var plainText = Encoding.UTF8.GetBytes(text);
var cipherText = EncryptWithKey(plainText, decodedKey);
return Convert.ToBase64String(cipherText);
}
//encrypt with byte array
private byte[] EncryptWithKey(byte[] text, byte[] key)
{
if (key == null || key.Length != KEY_BIT_SIZE / 8)
throw new ArgumentException(String.Format("Key needs to be {0} bit!", KEY_BIT_SIZE), "key");
var nonce = new byte[12];
var cipher = new GcmBlockCipher(new AesEngine());
var parameters = new AeadParameters(new KeyParameter(key), MAC_BIT_SIZE, nonce);
cipher.Init(true, parameters);
var cipherText = new byte[cipher.GetOutputSize(text.Length)];
var len = cipher.ProcessBytes(text, 0, text.Length, cipherText, 0);
cipher.DoFinal(cipherText, len);
return cipherText;
}
}
}
Output: fix 7szCRlNpTMM+93eTi332Gdw=
FINAL CODE
using System;
using System.Security.Cryptography;
using System.Text;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Modes;
using Org.BouncyCastle.Crypto.Parameters;
namespace api.Class
{
public class AESGCM
{
private const int KEY_BIT_SIZE = 256;
private const int MAC_BIT_SIZE = 128;
//encrypt with strings
public string Encrypt(string text, string key)
{
if (string.IsNullOrEmpty(text))
throw new ArgumentException("Text required!", "text");
var decodedKey = sha256_hash(key);
var plainText = Encoding.UTF8.GetBytes(text);
var cipherText = EncryptWithKey(plainText, decodedKey);
return Convert.ToBase64String(cipherText);
}
//encrypt with byte array
private byte[] EncryptWithKey(byte[] text, byte[] key)
{
if (key == null || key.Length != KEY_BIT_SIZE / 8)
throw new ArgumentException(String.Format("Key needs to be {0} bit!", KEY_BIT_SIZE), "key");
var nonce = new byte[12];
var cipher = new GcmBlockCipher(new AesEngine());
var parameters = new AeadParameters(new KeyParameter(key), MAC_BIT_SIZE, nonce);
cipher.Init(true, parameters);
var cipherText = new byte[cipher.GetOutputSize(text.Length)];
var len = cipher.ProcessBytes(text, 0, text.Length, cipherText, 0);
cipher.DoFinal(cipherText, len);
return cipherText;
}
private byte[] sha256_hash(string value)
{
Byte[] result;
using (var hash = SHA256.Create())
{
Encoding enc = Encoding.UTF8;
result = hash.ComputeHash(enc.GetBytes(value));
}
return result;
}
}
}
Output: same the java
Thank you very much, #user9014097

how can i do code conversion from PHP function to Java function

This is the Java code for the function which create a keyed hash digest, and I want to do the same but in PHP code.
Java code:
private String generateHash(final InputStream is, final int iteration,final String key) throws IOException,NoSuchAlgorithmException,InvalidKeyException {
Mac sha256_HMAC;
sha256_HMAC = Mac.getInstance(ALGORITHM);
final SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), ALGORITHM);
sha256_HMAC.init(secret_key);
byte[] bytesBuffer = new byte[2048];
int bytesRead = -1;
while ((bytesRead = is.read(bytesBuffer)) != -1) {
sha256_HMAC.update(bytesBuffer, 0, bytesRead);
}
byte[] digestValue = sha256_HMAC.doFinal();
for (int i = 0; i < iteration; i++) {
sha256_HMAC.reset();
digestValue = sha256_HMAC.doFinal(digestValue);
}
return Base64.encodeBase64String(digestValue);
}
This the PHP code I have tried, but the output of both code are not same.
And also that I think I'm missing something somewhere because I don't know alternative for each code statement of Java in PHP:
function generateHash($file, $iteration, $key){
//$hash = hash_hmac('sha256', 'hello, world!', 'mykey');
$inithash=hash_init('SHA256',1,$key);
//mb_strlen($string, '8bit')
while ($buffer=fread($file,"2048")) {
hash_update($inithash, $buffer);
}
$hash = hash_final($inithash);
$hashbyte = unpack('C*',$hash);
for($i=0;$i<$iteration;$i++)
{
//unset($hashbyte);
$inithash=hash_init('SHA256');
$inithash = hash_final($inithash);
}
return base64_encode($inithash);
}

Triple DES Encrypt C# - Decrypt in Java

I'm getting a Triple DES decrypted string from the clients server, which has been coded in c# (see below):
using System.IO;
using System;
using System.Security.Cryptography;
using System.Collections;
using System.Text;
class Program
{
static void Main()
{
Console.WriteLine("Hello, World!");
var encryption = TripleDESEncrypt("12345678901234", "C9AF269DF8A78A06D1216BFFF8F0536A");
Console.WriteLine(encryption);
}
public static string TripleDESEncrypt(string strClearText, string strKey)
{
byte[] bytClearText;
byte[] bytClearTextChunk = new byte[8];
byte[] bytEncryptedChunk = new byte[8];
int BytesCount = 0;
int nArrayPosition = 0;
string strEncryptedChar;
string strEncryptedText = "";
ArrayList Input = new ArrayList();
ArrayList Output = new ArrayList();
TripleDESCryptoServiceProvider tdes = (TripleDESCryptoServiceProvider)TripleDESCryptoServiceProvider.Create();
tdes.Key = HexToByteArray(strKey);
tdes.Mode = CipherMode.ECB;
ICryptoTransform tdesEncrypt = tdes.CreateEncryptor();
bytClearText = ASCIIEncoding.ASCII.GetBytes(strClearText);
BytesCount = bytClearText.Length;
for (int i = 0; i < BytesCount; i++)
{
if (nArrayPosition == 8)
{
Input.Add(bytClearTextChunk);
bytClearTextChunk = new byte[8];
nArrayPosition = 0;
}
bytClearTextChunk[nArrayPosition] = bytClearText[i];
nArrayPosition++;
}
if (nArrayPosition != 0)
Input.Add(bytClearTextChunk);
foreach (byte[] Cbyte in Input)
{
tdesEncrypt.TransformBlock(Cbyte, 0, 8, bytEncryptedChunk, 0);
Output.Add(bytEncryptedChunk);
bytEncryptedChunk = null;
bytEncryptedChunk = new byte[8];
}
foreach (byte[] Cbyte in Output)
{
foreach (byte BByte in Cbyte)
{
strEncryptedChar = BByte.ToString("X");
strEncryptedChar = strEncryptedChar.PadLeft(2, Convert.ToChar("0"));
strEncryptedText += strEncryptedChar;
}
}
return strEncryptedText;
}
private static byte[] HexToByteArray(string strHex)
{
byte[] bytArray = new byte[strHex.Length / 2];
int positionCount = 0;
for (int i = 0; i < strHex.Length; i += 2)
{
bytArray[positionCount] = byte.Parse(strHex.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);
positionCount++;
}
return bytArray;
}
}
I am then trying to Triple DES decrypt it in Java using this key: C9AF269DF8A78A06D1216BFFF8F0536A
Here is my code to decrypt:
public String DesDecryptPin(String pin, String encryptKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
String UNICODE_FORMAT = "UTF8";
String decryptedPinText = null;
byte[] hexConvert = hexStringtoByteArray(encryptKey);
SecretKey desKey = null;
byte[] tdesKey = new byte[24];
System.arraycopy(hexConvert, 0, tdesKey, 0,16);
System.arraycopy(hexConvert, 0, tdesKey, 0,8);
byte[] encryptKeyBytes = encryptKey.getBytes(UNICODE_FORMAT);
KeySpec desKeySpec = new DESedeKeySpec(tdesKey);
Cipher desCipher;
SecretKeyFactory skf = SecretKeyFactory.getInstance("DESede");
desCipher = Cipher.getInstance("DESede/ECB/NoPadding");
try {
desKey = skf.generateSecret(desKeySpec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
desCipher.init(Cipher.DECRYPT_MODE, desKey);
byte[] decryptPin = desCipher.doFinal(pin.getBytes());
decryptedPinText = new String(decryptPin, "UTF-8");
return decryptedPinText;
}
The sample out put would be input/output would be "12345678901234" however, I'm getting jumbled nonsense returned e.g ��0�8��/0��
So something is getting lost between c# and java...
This is a follow on from a previous question I asked here
I'd appreciate help on this
changes to code
public String DesDecryptPin(String pin, String encryptKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
String UNICODE_FORMAT = "UTF8";
String decryptedPinText = null;
SecretKey desKey = null;
byte[] encryptKeyBytes = EncodingUtils.getAsciiBytes(encryptKey);
byte[] tdesKey = new byte[24];
System.arraycopy(encryptKeyBytes, 8, tdesKey, 0, 8);
System.arraycopy(encryptKeyBytes, 0, tdesKey, 8, 16);
KeySpec desKeySpec = new DESedeKeySpec(tdesKey);
Cipher desCipher;
SecretKeyFactory skf = SecretKeyFactory.getInstance("DESede");
desCipher = Cipher.getInstance("DESede/ECB/NoPadding");
try {
desKey = skf.generateSecret(desKeySpec);
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
desCipher.init(Cipher.DECRYPT_MODE, desKey);
byte[] decryptPin = desCipher.doFinal(EncodingUtils.getAsciiBytes(pin));
decryptedPinText = new String(decryptPin, "ASCII");
return decryptedPinText;
}
c# decrypt code
using System.IO;
using System;
using System.Security.Cryptography;
using System.Collections;
using System.Text;
class Program
{
static void Main()
{
Console.WriteLine("Hello, World!");
var encryption = TripleDESDecrypt("1D30CC3DE1641D7F5E821D13FC1200C3", "C9AF269DF8A78A06D1216BFFF8F0536A");
Console.WriteLine(encryption);
}
public static string TripleDESDecrypt(string strEncryptedText, string strKey)
{
string errorMessage = "";
int errorCode = 0;
string strDecryptedText = "";
try
{
byte[] bytEncryptedChunk = new byte[8];
byte[] bytClearTextChunk = new byte[8];
byte[] _bytesEmpty = new byte[8];
int BytesCount = 0;
int positionCount = 0;
ArrayList Input = new ArrayList();
ArrayList Output = new ArrayList();
TripleDESCryptoServiceProvider tdes = (TripleDESCryptoServiceProvider)TripleDESCryptoServiceProvider.Create();
tdes.Key = HexToByteArray(strKey);
tdes.Mode = CipherMode.ECB;
ICryptoTransform tdesDecrypt = tdes.CreateDecryptor();
BytesCount = strEncryptedText.Length;
for (int i = 0; i < BytesCount; i += 2)
{
if (positionCount == 8)
{
positionCount = 0;
Input.Add(bytEncryptedChunk);
bytEncryptedChunk = new byte[8];
}
bytEncryptedChunk[positionCount] = byte.Parse(strEncryptedText.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);
positionCount++;
}
if (positionCount != 0)
{
Input.Add(bytEncryptedChunk);
}
foreach (byte[] Cbyte in Input)
{
tdesDecrypt.TransformBlock(Cbyte, 0, 8, _bytesEmpty, 0);
tdesDecrypt.TransformBlock(Cbyte, 0, 8, bytClearTextChunk, 0);
Output.Add(bytClearTextChunk);
bytClearTextChunk = null;
bytClearTextChunk = new byte[8];
}
foreach (byte[] Cbyte in Output)
{
strDecryptedText += ASCIIEncoding.ASCII.GetString(Cbyte);
}
}
catch (Exception ex)
{
errorCode = 1;
errorMessage = ex.Message;
}
Console.WriteLine(strDecryptedText);
return strDecryptedText;
}
private static byte[] HexToByteArray(string strHex)
{
byte[] bytArray = new byte[strHex.Length / 2];
int positionCount = 0;
for (int i = 0; i < strHex.Length; i += 2)
{
bytArray[positionCount] = byte.Parse(strHex.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);
positionCount++;
}
return bytArray;
}
}
This returns what is inputting into the encrypt 12345678901234
In your C# code, you use ASCII:
bytClearText = ASCIIEncoding.ASCII.GetBytes(strClearText);
While in Java you use UNICODE:
byte[] encryptKeyBytes = encryptKey.getBytes(UNICODE_FORMAT);
Try to change your C# to use UNICODE or your java code to use ASCII.
Also, since the C# is padding the output :
strEncryptedChar = strEncryptedChar.PadLeft(2, Convert.ToChar("0"));
You probably must check to remove all the '00' in the crypted string, so 1D30CC3DE1641D7F5E821D13FC1200C3 will become 1D30CC3DE1641D7F5E821D13FC12C3
(you must check if it's in the boundaries of an hex expression: 1C01A1 should probably be modified since it got a padding on the second Hexa 1C 01 A1: 1C1A1
acording https://stackoverflow.com/a/33768305/1140304 you can use
unicode instead of UTF-8 in java code
encrypt in c# :
public static string Encrypt2(string clearText,string key)
{
try
{
string encryptedText = "";
MD5 md5 = new MD5CryptoServiceProvider();
TripleDES des = new TripleDESCryptoServiceProvider();
des.KeySize = 128;
des.Mode = CipherMode.CBC;
des.Padding = PaddingMode.PKCS7;
byte[] md5Bytes = md5.ComputeHash(Encoding.Unicode.GetBytes(key));
byte[] ivBytes = new byte[8];
des.Key = md5Bytes;
des.IV = ivBytes;
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
ICryptoTransform ct = des.CreateEncryptor();
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
encryptedText = Convert.ToBase64String(ms.ToArray());
}
return encryptedText;
}
catch (Exception exception)
{
return "";
}
}
for decode in c# you can use:
public static string Decrypt2(string cipher,string key)
{
try
{
byte[] clearBytes = Convert.FromBase64String(cipher);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] md5Bytes = md5.ComputeHash(Encoding.Unicode.GetBytes(key));
string encryptedText = "";
TripleDES des = new TripleDESCryptoServiceProvider();
des.KeySize = 128;
des.Mode = CipherMode.CBC;
des.Padding = PaddingMode.PKCS7;
byte[] ivBytes = new byte[8];
des.Key = md5Bytes;
des.IV = ivBytes;
ICryptoTransform ct = des.CreateDecryptor();
byte[] resultArray = ct.TransformFinalBlock(clearBytes, 0, clearBytes.Length);
encryptedText = Encoding.Unicode.GetString(resultArray);
return encryptedText;
}
catch (Exception exception)
{
return "";
}
}
now, for encrypt in java you can use :
private String _encrypt2(String clearText,String key )
{
try
{
/**
* create md5
*/
MessageDigest md = MessageDigest.getInstance("md5");
byte[] digestOfPassword = md.digest(key.getBytes("UTF-16LE"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8; )
{
keyBytes[k++] = keyBytes[j++];
}
SecretKey secretKey = new SecretKeySpec(keyBytes, 0, 24, "DESede");
IvParameterSpec iv = new IvParameterSpec(new byte[8]);
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
byte[] plainTextBytes = clearText.getBytes("UTF-16LE");
byte[] cipherText = cipher.doFinal(plainTextBytes);
String output = Base64.encodeToString(cipherText,Base64.DEFAULT);
return output;
}
catch (Exception ex) {}
return "";
}
and for decrypt in java :
private String _decrypt2(String encryptText,String key)
{
MessageDigest md = null;
byte[] digestOfPassword = null;
try
{
byte[] message = Base64.decode(encryptText.getBytes("UTF-16LE"), Base64.DEFAULT);
/**
* make md5
*/
md = MessageDigest.getInstance("md5");
digestOfPassword = md.digest(key.getBytes("UTF-16LE"));
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8; )
{
keyBytes[k++] = keyBytes[j++];
}
SecretKey secretKey = new SecretKeySpec(keyBytes, 0, 24, "DESede");
IvParameterSpec iv = new IvParameterSpec(new byte[8]);
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
byte[] cipherText = cipher.doFinal(message);
return new String(cipherText, "UTF-16LE");
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
catch (InvalidKeyException e)
{
e.printStackTrace();
}
catch (InvalidAlgorithmParameterException e)
{
e.printStackTrace();
}
catch (NoSuchPaddingException e)
{
e.printStackTrace();
}
catch (BadPaddingException e)
{
e.printStackTrace();
}
catch (IllegalBlockSizeException e)
{
e.printStackTrace();
}
return "";
}
If someone find himself/herself in the same problem like I did, here is a java implementation (android) of the same .NET decrypt function:
public static byte[] byteArrayConcat(byte[] array1, byte[] array2) {
byte[] result = new byte[array1.length + array2.length];
System.arraycopy(array1, 0, result, 0, array1.length);
System.arraycopy(array2, 0, result, array1.length, array2.length);
return result;
}
private byte[] fGPKeyTo3DESKey(byte[] GPKey) {
byte[] _3DESKey = new byte[24];
byte[] tmp = new byte[8];
arraycopy(GPKey, 0, tmp, 0, 8);
_3DESKey = DaPlugUtils.byteArrayConcat(GPKey, tmp);
return _3DESKey;
}
private static byte[] hexStringtoByteArray(String hex) {
int len = hex.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16));
}
return data;
}
public String desDecryptPin(String pin, String encryptKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidKeySpecException {
int bytesCount = 0;
int positionCount = 0;
byte[] bytEncryptedChunk = new byte[8];
ArrayList<byte[]> Input = new ArrayList();
bytesCount = pin.length();
for (int i = 0; i < bytesCount; i += 2) {
if (positionCount == 8) {
positionCount = 0;
Input.add(bytEncryptedChunk);
bytEncryptedChunk = new byte[8];
}
bytEncryptedChunk[positionCount] = (byte) (Integer.parseInt(pin.substring(i, i + 2), 16));
positionCount++;
}
if (positionCount != 0) {
Input.add(bytEncryptedChunk);
}
byte[] _3DESKey = fGPKeyTo3DESKey(hexStringtoByteArray(encryptKey));
DESedeKeySpec keySpec = new DESedeKeySpec(_3DESKey);
SecretKey k = SecretKeyFactory.getInstance("DESede").generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, k);
String res = "";
for (byte[] bs : Input) {
byte[] decryptPin = cipher.doFinal(bs);
String a = new String(decryptPin, StandardCharsets.US_ASCII);
res += a;
}
return res.trim();
}

Java Encryption done is not matching with .Net Encryption both encryption are different

Code is running without any error but not getting encrpted correctly as same as from Java code.
.Net Code :
public static string Encrypt(string stringToEncrypt, string key)
{
using (RijndaelManaged myRijndael = new RijndaelManaged())
{
myRijndael.Key = Encoding.Default.GetBytes(key);
myRijndael.IV = new byte[16];
return EncryptStringToBytes(stringToEncrypt, myRijndael.Key, myRijndael.IV);
}
}
public static string EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
{
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
byte[] encrypted;
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;
rijAlg.Padding = PaddingMode.None;
rijAlg.Mode = CipherMode.ECB;
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write(plainText);
if (plainText.Length < 16)
{
for (int i = plainText.Length; i < 16; i++)
{
swEncrypt.Write((byte)0x0);
}
}
}
encrypted = msEncrypt.ToArray();
Enc = Convert.ToBase64String(encrypted);
//encrypted = Convert.ToBase64String(msEncrypt.ToArray());
}
}
}
return Enc;
}

using java to encrypt/decrypt files return wrong number of bytes when using padding

I'm trying to make an application that encrypts / decrypt and it is working fine when I use a cipher mode without padding. With padding, the number of blocks is unpredictable and I cant find the source of the problem.
I am using the following code to test:
private static final int KEY_LEN = 16;
private static final String ENCRYPTION_ALGO = "AES";
private static final String HASHING_ALGO = "SHA-256";
private static final String CIPHER_MODE = "AES/CFB/PKCS5Padding";
private static final String ENCODING = "UTF-8";
static private byte[] initVector;
static private SecretKey key;
static Cipher cipher;
private static SecretKey generateKey(byte[] password) {
MessageDigest md = MessageDigest.getInstance(HASHING_ALGO);
byte[] hashedKey = md.digest(password);
return new SecretKeySpec(hashedKey, 0, KEY_LEN, ENCRYPTION_ALGO);
}
public static byte[] getIV() {
return initVector;
}
public static void setup(String password)
{
key = generateKey(password.getBytes(ENCODING));
cipher = Cipher.getInstance (CIPHER_MODE);
cipher.init (Cipher.ENCRYPT_MODE, key);
AlgorithmParameters params = cipher.getParameters ();
initVector = params.getParameterSpec (IvParameterSpec.class).getIV();
}
public static void setup(String password, byte[] iv)
{
key = generateKey(password.getBytes(ENCODING));
cipher = Cipher.getInstance (CIPHER_MODE);
// define init vector that was used for encryption
cipher.init (Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
}
private static byte[] crypt(byte[] plaintext, boolean hasNext)
if (hasNext) {
return cipher.update(plaintext);
}else {
return cipher.doFinal(plaintext);
}
}
public static void main(String [] args)
{
try {
File input = new File ("input.txt");
File eoutput = new File ("output.enc");
File doutput = new File ("decrypted.txt");
FileInputStream fin = new FileInputStream(input);
FileOutputStream fout = new FileOutputStream (eoutput);
byte [] buffer = new byte [32];
int nBytes;
//encrypt
setup("password");
while ((nBytes = fin.read(buffer))!=-1) {
byte[] cyphertext;
if (nBytes < buffer.length) {
byte[] trimbuffer = new byte [nBytes];
System.arraycopy(buffer, 0, trimbuffer, 0, nBytes);
cyphertext = crypt(trimbuffer, false);
}else {
cyphertext = crypt(buffer, true);
}
fout.write(cyphertext);
}
fin.close();
fout.close();
FileInputStream fin2 = new FileInputStream(eoutput);
FileOutputStream fout2 = new FileOutputStream (doutput);
byte[] iv = getIV();
// decrypt
setup("password",iv);
while ((nBytes = fin2.read(buffer))!=-1) {
byte[] plaintext;
if (nBytes < buffer.length) {
byte[] trimbuffer = new byte [nBytes];
System.arraycopy(buffer, 0, trimbuffer, 0, nBytes);
plaintext = crypt(trimbuffer, false);
}else {
plaintext = crypt(buffer, true);
}
fout2.write(plaintext);
}
fin2.close();
fout2.close();
}
I forgot to mention that the problem seems to be in decryption side.
I just found the problem after lots of testing. The problem is that when I read files and the last block had the exact same size of the buffer, I was always calling crypt(buffer, true) that does a cipher.update() insted of cipher.doFinal()

Categories