HMAC in C++ that outputs the same value in Java - java

I am unable to get the same output from HMAC in C++ like the one i wrote in java, they have different output.
Java:
private static byte[] hmac_sha(String crypto, byte[] keyBytes, byte[] text) {
try {
Mac hmac;
hmac = Mac.getInstance(crypto);
SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW");
hmac.init(macKey);
return hmac.doFinal(text);
} catch (GeneralSecurityException gse) {
throw new UndeclaredThrowableException(gse);
}
}
C++:
BYTE *key = (BYTE *)encodedSeed.data();
BYTE digest[20];
const char *message = encodedTime.data();
CHMAC_SHA1 HMAC;
HMAC.HMAC_SHA1((BYTE *)message, strlen(message), key, sizeof(key), digest);
wstring finalDigest;
for (int i = 0; i < 20; i++){
finalDigest.push_back(std::btowc(digest[i]));
}
return finalDigest;

Related

decrypted result 128- aes-CBC difference between mbedtls in C and Java Cipher

I want to encrypt data from a client and send it to a server over a socket. The client is written in Java and the server is written in C. However, the result is not the same as my expected.
The C program as follows:
#define MAX_BUFF 1024
#define MAX_LENGTH_DATA 1024
static void decrypt128(unsigned char intput[], unsigned char output[]) {
mbedtls_aes_context context_out;
unsigned char key1[] = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P'};
unsigned char iv1[16] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P' };
unsigned char decrypt[128];
mbedtls_aes_init(&context_out);
mbedtls_aes_setkey_dec(&context_out, key1, 128);
mbedtls_aes_crypt_cbc(&context_out, MBEDTLS_AES_DECRYPT, 16, iv1, intput,decrypt);
printf("\nInside of decrypt128 function:\n");
for (unsigned index = 0; index < 128; ++index)
printf("%c", (char) decrypt[index]);
strcpy(output, decrypt);
}
int main(int argc, char * argv[]){
int socket_desc, client_sock, c, read_size, rc, option = 1, ret,
encrypt_size, counter_data_receive;
struct sockaddr_in server, client;
int opt = 1;
struct timeval timeout_receive;
unsigned char encrypt_bufferr[MAX_LENGTH_DATA] = { 0 };
unsigned char decrypt_bufferr[MAX_LENGTH_DATA] = { 0 };
// Creating socket file descriptor
printf("Creating socket...!!!!!\n");
if ((socket_desc = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port 4434
if (setsockopt(socket_desc, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt,
sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(4434);
// Forcefully attaching socket to the port 4434
if (bind(socket_desc, (struct sockaddr *) &server, sizeof(server)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
c = sizeof(struct sockaddr_in);
printf("Start waiting for incoming connections!\n");
listen(socket_desc, 1);
client_sock = accept(socket_desc, (struct sockaddr*) &client,
(socklen_t*) &c);
if (client_sock < 0) {
printf("Failed: accept connection");
exit(EXIT_FAILURE);
}
printf("Connection accepted\n");
timeout_receive.tv_sec = 5;
timeout_receive.tv_usec = 0;
setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO,
(const void*) &timeout_receive, sizeof(struct timeval));
memset(encrypt_bufferr, 0x00, sizeof(encrypt_bufferr));
memset(decrypt_bufferr, 0x00, sizeof(decrypt_bufferr));
ret = recv(client_sock, encrypt_bufferr, sizeof(encrypt_bufferr), 0);
printf("\n+++++++++++++byte receive: %d\n", ret);
printf("\n+++++++++++++received buff: %s\n", encrypt_bufferr);
decrypt128(encrypt_bufferr, decrypt_bufferr);
printf("\nFinal decrypted data = %s", decrypt_bufferr);
}
output
Creating socket...!!!!!
Start waiting for incoming connections!
Connection accepted
+++++++++++++byte receive: 24
+++++++++++++received buff: 8+4c4xcMC1FPhdJabnl/4w==
Inside of decrypt128 function:
R�V͵2�Q���˵��
For the client-side, I wrote it using Java:
public class EncryptDecryptString {
private static final String cipherTransformation = "AES/CBC/PKCS5PADDING";
private static final String aesEncryptionAlgorithem = "AES";
public static String encrypt(String plainText) {
String encryptedText = "";
byte iv1[] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P' };
try {
Cipher cipher = Cipher.getInstance(cipherTransformation);
byte[] key = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P' };
SecretKeySpec secretKey = new SecretKeySpec(key, aesEncryptionAlgorithem);
IvParameterSpec ivparameterspec = new IvParameterSpec(iv1);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivparameterspec);
byte[] cipherText = cipher.doFinal(plainText.getBytes("UTF-8"));
Base64.Encoder encoder = Base64.getEncoder();
encryptedText = encoder.encodeToString(cipherText);
} catch (Exception E) {
System.err.println("Encrypt Exception : "+E.getMessage());
}
return encryptedText;
}
public static String decrypt(String encryptedText) {
String decryptedText = "";
byte iv1[] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P' };
try {
Cipher cipher = Cipher.getInstance(cipherTransformation);
byte[] key = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P' };//encryptionKey.getBytes(characterEncoding);
SecretKeySpec secretKey = new SecretKeySpec(key, aesEncryptionAlgorithem);
IvParameterSpec ivparameterspec = new IvParameterSpec(iv1);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivparameterspec);
Base64.Decoder decoder = Base64.getDecoder();
byte[] cipherText = decoder.decode(encryptedText.getBytes("UTF8"));
decryptedText = new String(cipher.doFinal(cipherText), "UTF-8");
} catch (Exception E) {
System.err.println("decrypt Exception : "+E.getMessage());
}
return decryptedText;
}
public static void main(String[] args) {
//System.out.println("Enter String : ");
System.out.println("Running.... ");
String plainString = "Hello world!";//sc.nextLine();
String encyptStr = encrypt(plainString);
String decryptStr = decrypt(encyptStr);
Socket socketOfClient;
try {
socketOfClient = new Socket("127.0.0.1", 4434);
BufferedWriter os = new BufferedWriter(new OutputStreamWriter(socketOfClient.getOutputStream()));
BufferedReader is = new BufferedReader(new InputStreamReader(socketOfClient.getInputStream()));
os.write(encyptStr);
os.flush();
System.out.printf("\nSent data to server....\n");
//os.flush();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Plain String : "+plainString);
System.out.println("Encrypt String : "+encyptStr);
System.out.println("Decrypt String : "+decryptStr);
}
}
Output
Running....
Sent data to server....
Plain String : Hello world!
Encrypt String : 8+4c4xcMC1FPhdJabnl/4w==
Decrypt String : Hello world!
The received encrypted data is the same between the two sides, but when I used mbedtl to decrypt this data in the server-side, the result is not the same. Please help me to resolve the problem. Thank you!!!!

Android AES decryption returning rare characters V2.0

Recently i've post a question about this topic but the thing turns a little weird when i tried to decrypt an AES String that was encoded on UTF8
In the following lines i read the String AES encrypted wich returns the following String: RnLObq9hdUDGp9S2pxC1qjQXekuf9g6i/5bQfKilYn4=
public static final String AesKey256 ="ZzRtNDNuY3J5cHRrM3kuLi4=";
//This reads the String and stores on res.getContents()
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
IntentResult res= IntentIntegrator.parseActivityResult(requestCode, resultCode,data);
if(res!=null){
if (res.getContents() == null) {
Toast.makeText(this,"Captura cancelada",Toast.LENGTH_SHORT).show();
}else{
try {
String cadena= decrypt(res.getContents());
out.setText(cadena);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//provide the res.getContents() to decrypt method, wich its the String i've recently read
private String decrypt(String cadena)throws Exception{
SecretKeySpec keySpec= generateKey(AesKey256); //HERE
Cipher c= Cipher.getInstance(AES_MODE);
c.init(Cipher.DECRYPT_MODE,keySpec);
byte[] decodedValue= Base64.decode(cadena, Base64.DEFAULT);
byte[] decValue= c.doFinal(decodedValue);/* c.doFinal(decodedValue);*/
String decryptedValue= new String((decValue), "UTF-8");
return decryptedValue;
}
private SecretKeySpec generateKey(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
final MessageDigest digest= MessageDigest.getInstance("SHA-256");
byte[] bytes= password.getBytes("UTF-8");
digest.update(bytes,0,bytes.length);
byte[] key= digest.digest();
SecretKeySpec secretKeySpec= new SecretKeySpec(key, "AES");
return secretKeySpec;
}
I am only using the decryption method but it still returning this characters:
i've spent hours looking for a solution, but nothing works for now... hope someone can give me a hand!
Best Regards!
EDIT
THIS IS HOW IT WAS ENCRYPTED IN C#
private const string AesIV256 = "IVFBWjJXU1gjRURDNFJGVg==";
private const string AesKey256 = "ZzRtNDNuY3J5cHRrM3kuLi4=";
public static string Encrypt(string text)
{
var sToEncrypt = text;
var rj = new RijndaelManaged()
{
Padding = PaddingMode.Zeros,
Mode = CipherMode.ECB,
KeySize = 256,
BlockSize = 256,
};
var key = Convert.FromBase64String(AesKey256);
var IV = Convert.FromBase64String(AesIV256);
var encryptor = rj.CreateEncryptor(key, IV);
var msEncrypt = new MemoryStream();
var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
var toEncrypt = Encoding.UTF8.GetBytes(sToEncrypt);
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
var encrypted = msEncrypt.ToArray();
return (Convert.ToBase64String(encrypted));
}
Made it!
After a long time of searching thanks to all you guys who answered this post i used the bouncy castle library and i've decrypt the desired String by doing the following:
public static String decrypt(String valueToDecrypt) throws Exception {
AESCrypt enc = new AESCrypt();
return new String(enc.decryptInternal(valueToDecrypt)).trim();
}
private byte[] decryptInternal(String code) throws Exception {
if (code == null || code.length() == 0) {
throw new Exception("Empty string");
}
byte[] decrypted = null;
try {
byte[] key= SecretKey.getBytes("UTF-8");
PaddedBufferedBlockCipher c = new PaddedBufferedBlockCipher(new RijndaelEngine(256), new ZeroBytePadding());
CipherParameters params= new KeyParameter(key);`
// false because its going to decrypt
c.init(false,params);
decrypted= GetData(c,(Base64.decode(code,Base64.DEFAULT));
} catch (Exception e) {
throw new Exception("[decrypt] " + e.getMessage());
}
return decrypted;
}
private static byte[] GetData(PaddedBufferedBlockCipher cipher, byte[] data) throws InvalidCipherTextException
{
int minSize = cipher.getOutputSize(data.length);
byte[] outBuf = new byte[minSize];
int length1 = cipher.processBytes(data, 0, data.length, outBuf, 0);
int length2 = cipher.doFinal(outBuf, length1);
int actualLength = length1 + length2;
byte[] cipherArray = new byte[actualLength];
for (int x = 0; x < actualLength; x++) {
cipherArray[x] = outBuf[x];
}
return cipherArray;
}

C# equivalent encryption decryption for Java

C# Code
namespace MWS.DAL
{
public class StringHelpers
{
#region Constants
private const char QUERY_STRING_DELIMITER = '&';
#endregion Constants
#region Members
private static RijndaelManaged _cryptoProvider;
//128 bit encyption: DO NOT CHANGE
private static readonly byte[] Key = { some byte value };
private static readonly byte[] IV = { some byte value };
#endregion Members
#region Constructor
static StringHelpers()
{
_cryptoProvider = new RijndaelManaged();
_cryptoProvider.Mode = CipherMode.CBC;
_cryptoProvider.Padding = PaddingMode.PKCS7;
}
#endregion Constructor
#region Methods
/// <summary>
/// Encrypts a given string.
/// </summary>
/// <param name="unencryptedString">Unencrypted string</param>
/// <returns>Returns an encrypted string</returns>
public static string Encrypt(string unencryptedString)
{
byte[] bytIn = ASCIIEncoding.ASCII.GetBytes(unencryptedString);
// Create a MemoryStream
MemoryStream ms = new MemoryStream();
// Create Crypto Stream that encrypts a stream
CryptoStream cs = new CryptoStream(ms,
_cryptoProvider.CreateEncryptor(Key, IV),
CryptoStreamMode.Write);
// Write content into MemoryStream
cs.Write(bytIn, 0, bytIn.Length);
cs.FlushFinalBlock();
byte[] bytOut = ms.ToArray();
return Convert.ToBase64String(bytOut);
}
/// <summary>
/// Decrypts a given string.
/// </summary>
/// <param name="encryptedString">Encrypted string</param>
/// <returns>Returns a decrypted string</returns>
public static string Decrypt(string encryptedString)
{
if (encryptedString.Trim().Length != 0)
{
// Convert from Base64 to binary
byte[] bytIn = Convert.FromBase64String(encryptedString);
// Create a MemoryStream
MemoryStream ms = new MemoryStream(bytIn, 0, bytIn.Length);
// Create a CryptoStream that decrypts the data
CryptoStream cs = new CryptoStream(ms,
_cryptoProvider.CreateDecryptor(Key, IV),
CryptoStreamMode.Read);
// Read the Crypto Stream
StreamReader sr = new StreamReader(cs);
return sr.ReadToEnd();
}
else
{
return "";
}
}
public static NameValueCollection DecryptQueryString(string queryString)
{
if (queryString.Length != 0)
{
//Decode the string
string decodedQueryString = HttpUtility.UrlDecode(queryString);
//Decrypt the string
string decryptedQueryString = StringHelpers.Decrypt(decodedQueryString);
//Now split the string based on each parameter
string[] actionQueryString = decryptedQueryString.Split(new char[] { QUERY_STRING_DELIMITER });
NameValueCollection newQueryString = new NameValueCollection();
//loop around for each name value pair.
for (int index = 0; index < actionQueryString.Length; index++)
{
string[] queryStringItem = actionQueryString[index].Split(new char[] { '=' });
newQueryString.Add(queryStringItem[0], queryStringItem[1]);
}
return newQueryString;
}
else
{
//No query string was passed in.
return null;
}
}
public static string EncryptQueryString(NameValueCollection queryString)
{
//create a string for each value in the query string passed in.
string tempQueryString = "";
for (int index = 0; index < queryString.Count; index++)
{
tempQueryString += queryString.GetKey(index) + "=" + queryString[index];
if (index != queryString.Count - 1)
{
tempQueryString += QUERY_STRING_DELIMITER;
}
}
return EncryptQueryString(tempQueryString);
}
/// <summary>
/// You must pass in a string that uses the QueryStringHelper.DELIMITER as the delimiter.
/// This will also append the "?" to the beginning of the query string.
/// </summary>
/// <param name="queryString"></param>
/// <returns></returns>
public static string EncryptQueryString(string queryString)
{
return "?" + HttpUtility.UrlEncode(StringHelpers.Encrypt(queryString));
}
#endregion Methods
}
}
Java Code
public String decrypt(String text) throws Exception{
// byte[] keyBytess={some byte values};
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes= new byte[16];
byte[] b= { some byte values };
byte[] iv = { some byte values };
int len= b.length;
if (len > keyBytes.length) len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE,keySpec,ivSpec);
BASE64Decoder decoder = new BASE64Decoder();
byte [] results = cipher.doFinal(decoder.decodeBuffer(text));
return new String(results,"UTF-8");
}
public String encrypt(String text)
throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes= new byte[16];
byte[] b= { some byte values };
byte[] iv = { some byte values };
int len= b.length;
if (len > keyBytes.length) len = keyBytes.length;
System.arraycopy(b, 0, keyBytes, 0, len);
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivSpec);
byte[] results = cipher.doFinal(text.getBytes("UTF-8"));
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(results);
}
In Case of C#
value= just4fun
and
ecncrypted value= j/Rph4d/Op6sugBxZ/kJbA==
In Case of Java
value= just4fun
and
encrypted value= 8BfD/Jr0Hk35qn8DXwFHmA==
and when I am trying to decrypt C# encrypted value in java it giving javax.crypto.BadPaddingException: Given final block not properly padded
I have some restriction, I can't update C# code it is in use
When you encrypt/decrypt you are using using UTF-8 Encoding in Java
byte[] results = cipher.doFinal(text.getBytes("UTF-8"));
and ASCII in C#
byte[] bytIn = ASCIIEncoding.ASCII.GetBytes(unencryptedString);
You should get the same results when using UFT-8 encoding, like for C#:
byte[] bytIn = UTF8Encoding.UTF8.GetBytes(unencryptedString);
or for Java:
byte[] bytIn = text.getBytes("US_ASCII");
As Fildor mentioned the different PaddingModes see the comment below by James K Polk
I added a quote from msdn.microsoft.com forums for additional information
PKCS7 padding in .Net vs PKCS5 padding in Java
The difference between the PKCS#5 and PKCS#7 padding mechanisms is the block size; PKCS#5 padding is defined for 8-byte block sizes, PKCS#7 padding would work for any block size from 1 to 255 bytes. So fundamentally PKCS#5 padding is a subset of PKCS#7 padding for 8 byte block sizes.
! so, data encrypted with PKCS#5 is able to decrypt with PKCS#7, but data encrypted with PKCS#7 may not be able to decrypt with PKCS#5.
Also found a possible duplicate for your problem here.

encrypt using BouncyCastle (java) and Gcrypt (C) gives different result

I wrote this simple Java program which encrypt a string and output the hex value of the iv, salt, derived key and cipher text.
public class tmp{
static Cipher encryptionCipher;
static String RANDOM_ALGORITHM = "SHA1PRNG";
static String PBE_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC";
static String CIPHER_ALGORITHM = "AES/CBC/PKCS7Padding";
static String SECRET_KEY_ALGORITHM = "AES";
static int PBE_ITERATION_COUNT = 2048;
static String PROVIDER = "BC";
public static byte[] generateIv() {
try{
SecureRandom random;
random = SecureRandom.getInstance(RANDOM_ALGORITHM);
byte[] iv = new byte[16];
random.nextBytes(iv);
return iv;
} catch(Exception e){
return null; // Always must return something
}
}
public static byte[] generateSalt() {
try {SecureRandom random;
random = SecureRandom.getInstance(RANDOM_ALGORITHM);
byte[] salt = new byte[32];
random.nextBytes(salt);
return salt;
} catch(Exception e){
return null; // Always must return something
}
}
public static SecretKey getSecretKey(String password, byte[] salt){
try {
PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), salt, PBE_ITERATION_COUNT, 256);
SecretKeyFactory factory = SecretKeyFactory.getInstance(PBE_ALGORITHM, PROVIDER);
SecretKey tmp = factory.generateSecret(pbeKeySpec);
return new SecretKeySpec(tmp.getEncoded(), SECRET_KEY_ALGORITHM);
} catch(Exception e){
System.out.println(e); // Always must return something
return null;
}
}
public static String encrypt(String plaintext, Key key, byte[] iv) {
try {
AlgorithmParameterSpec ivParamSpec = new IvParameterSpec(iv);
encryptionCipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
encryptionCipher.init(Cipher.ENCRYPT_MODE, key, ivParamSpec);
byte[] ciphertext = encryptionCipher.doFinal(plaintext.getBytes("UTF-8"));
String cipherHexString = DatatypeConverter.printHexBinary(ciphertext);
return cipherHexString;
}
catch (Exception e) {
System.out.println(e);
return null;
}
}
public static void main (String[] Args){
SecretKey key;
//sha512(ciao)
String encami = "This is a test pharse. Thanks!!";
String password = "a0c299b71a9e59d5ebb07917e70601a3570aa103e99a7bb65a58e780ec9077b1902d1dedb31b1457beda595fe4d71d779b6ca9cad476266cc07590e31d84b206";
byte[] iv = new byte[16];
byte[] salt = new byte[32];
iv = generateIv();
salt = generateSalt();
String ll = DatatypeConverter.printHexBinary(iv);
String lp = DatatypeConverter.printHexBinary(salt);
System.out.println(ll);
System.out.println(lp);
key = getSecretKey(password, salt);
byte tt[] = new byte[32];
tt = key.getEncoded();
String lo = DatatypeConverter.printHexBinary(tt);
System.out.println(lo);
String outenc = encrypt(encami, key, iv);
System.out.println(outenc);
}
}
In the following C program iv and salt are initialized with the values given by the above Java program. No padding needed since the length of the text is 32 bytes.
#include <stdio.h>
#include <gcrypt.h>
#include <stdlib.h>
#include <string.h>
int
main (void)
{
int i;
char *encami = "This is a test pharse. Thanks!!";
char *pwd = "a0c299b71a9e59d5ebb07917e70601a3570aa103e99a7bb65a58e780ec9077b1902d1dedb31b1457beda595fe4d71d779b6ca9cad476266cc07590e31d84b206";
unsigned char iv[] = {};
unsigned char salt[] = {};
int algo = gcry_cipher_map_name("aes256");
unsigned char *devkey = NULL;
unsigned char *enc_buf = NULL;
enc_buf = gcry_malloc(32);
devkey = gcry_malloc_secure (32);
gcry_cipher_hd_t hd;
gcry_cipher_open(&hd, algo, GCRY_CIPHER_MODE_CBC, 0);
gcry_kdf_derive (pwd, strlen(pwd)+1, GCRY_KDF_PBKDF2, GCRY_MD_SHA256, salt, 32, 2048, 32, devkey);
for (i=0; i<32; i++)
printf ("%02x", devkey[i]);
printf("\n");
gcry_cipher_setkey(hd, devkey, 32);
gcry_cipher_setiv(hd, iv, 16);
gcry_cipher_encrypt(hd, enc_buf, strlen(encami)+1, encami, strlen(encami)+1);
for (i=0; i<32; i++)
printf("%02x", enc_buf[i]);
printf("\n");
gcry_cipher_close(hd);
gcry_free(enc_buf);
gcry_free (devkey);
return 0;
}
My problem is that the derived key is not the same in those two programs. Why?
Is the bouncy castle deriving function not working in the same way as gcry_kdf_derive?
Thanks!
I've now looked into the PBEWithSHA256And256BitAES-CBC-BC algorithm in the BC provider, and found that it is not compatible with GCRY_KDF_PBKDF2. The gcrypt algorithm is PKCS#5 2.0 Scheme 2, whereas the BC one is actually implementing PKCS#12.
Actually, I've so far not found a named algorithm in the provider that matches the gcrypt one, however I was able to use the BC API directly to get matching results b/w them, as follows.
Bouncy Castle:
byte[] salt = new byte[8];
Arrays.fill(salt, (byte)1);
PBEParametersGenerator pGen = new PKCS5S2ParametersGenerator(new SHA256Digest());
pGen.init(Strings.toByteArray("password"), salt, 2048);
KeyParameter key = (KeyParameter)pGen.generateDerivedParameters(256);
System.out.println(Hex.toHexString(key.getKey()));
gcrypt:
unsigned char salt[8];
memset(salt, 1, 8);
unsigned char key[32];
gcry_kdf_derive("password", 8, GCRY_KDF_PBKDF2, GCRY_MD_SHA256, salt, 8, 2048, 32, key);
for (int i = 0; i < 32; ++i)
printf("%02x", key[i]);
printf("\n");
which both output:
4182537a153b1f0da1ccb57971787a42537e38dbf2b4aa3692baebb106fc02e8
You appear to be including a terminating NULL character in your count of 32 bytes (encami), which explains the differing outputs. The java version sees a 31-character input and provides a single PKCS#7-padded output block (PKCS#7 will pad the input with a single '1' byte). The C version is passed 32 bytes, including the final '0' byte. So the inputs are different.
I recommend you stop treating the NULL terminator as part of the input; instead apply PKCS#7 padding, as the Java version is doing. I'm not familiar with gcrypt, so I don't know what the typical method is for doing this, but PKCS#7 padding is a quite simple concept in any case.

Cipher / 3DES / CFB / Java and PHP

I have a PHP servor which decrypt data in 3DES with the CFB Mode
I encrypt in PHP :
$montant = "500";
$message_crypte = mcrypt_encrypt(MCRYPT_3DES, "N4y1FRDRJ7wn7eJNnWaahCIS", $montant, ,CRYPT_MODE_CFB, "NCNPJDcR");
$montant = base64_encode($message_crypte);
This script in PHP is OK with other system.
And I want to encrypt in Java :
public class CryptData {
private KeySpec keySpec;
private SecretKey key;
private IvParameterSpec iv;
public CryptData(String keyString, String ivString) {
try {
final MessageDigest md = MessageDigest.getInstance("md5");
final byte[] digestOfPassword = md.digest(Base64
.decodeBase64(keyString.getBytes("ISO-8859-1")));
final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
//keySpec = new DESedeKeySpec(keyBytes);
keySpec = new DESedeKeySpec(keyString.getBytes());
key = SecretKeyFactory.getInstance("DESede")
.generateSecret(keySpec);
iv = new IvParameterSpec(ivString.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
public String encrypt(String value) {
try {
Cipher ecipher = Cipher.getInstance("DESede/CFB/NoPadding");
//"SunJCE");
ecipher.init(Cipher.ENCRYPT_MODE, key, iv);
if (value == null)
return null;
// Encode the string into bytes using utf-8
byte[] valeur = value.getBytes("ISO-8859-1");
//byte[] utf8 = value.getBytes();
// Encrypt
byte[] enc = ecipher.doFinal(valeur);
// Encode bytes to base64 to get a string
return new String(Base64.encodeBase64(enc), "ISO-8859-1");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
I have not the same result in PHP and in Java
How modify Java treatment to obtain the same result as PHP?
The answer is:
Cipher ecipher = Cipher.getInstance("DESede/CFB8/NoPadding");
I need to use "CFB8"

Categories

Resources