After 2 weeks of trying every code I found on internet I ask for help...
I have to convert a java script into php
I need your help to guide me to the solution
Here the code of the class
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.log4j.Logger;
public class DirectLinkCryption {
private static final String ALGORITHM = "AES";
private static final String UTF_8 = "UTF-8";
/**
* AES encryption of the data with Cipher Block Chaining (CBC) and padding to fill up the empty bytes.
*/
private static final String AES_CBC_PKCS5PADDING = "AES/CBC/PKCS5PADDING";
private IvParameterSpec ivParameterSpec;
public DirectLinkCryption() {
initIvParameterSpec();
}
public String getEncryptedParameter(String parameter, String password) {
try {
Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5PADDING);
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(password), this.ivParameterSpec);
return Base64.getUrlEncoder().encodeToString(cipher.doFinal(parameter.getBytes()));
} catch (Exception e) {
Logger.getRootLogger().error(String.format("Could not encrypt parameter '%s'!", parameter));
Logger.getRootLogger().error(e, e);
return "";
}
}
public static String getDecryptedParameter(String url, String password, String initializationVector) {
try {
Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5PADDING);
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(password), new IvParameterSpec(Base64.getUrlDecoder().decode(initializationVector)));
return new String(cipher.doFinal(Base64.getUrlDecoder().decode(url)));
} catch (Exception e) {
Logger.getRootLogger().error(String.format("Could not decrypt url '%s' with AES 128", url));
Logger.getRootLogger().error(e, e);
return "";
}
}
private void initIvParameterSpec() {
byte[] ivBytes = new byte[16];
(new SecureRandom()).nextBytes(ivBytes);
this.ivParameterSpec = new IvParameterSpec(ivBytes);
}
public String getInitializationVector() {
return Base64.getUrlEncoder().encodeToString(this.ivParameterSpec.getIV());
}
private static SecretKeySpec getSecretKey(String password) {
try {
return new SecretKeySpec(password.getBytes(UTF_8), ALGORITHM);
} catch (UnsupportedEncodingException e) {
Logger.getRootLogger().error("Unsupported encoding algorithm! ", e);
return null;
}
}
}
I tried a lot of thing, it doesn't give the same result as the java class but the most common solution is :
$iv = base64_encode(openssl_random_pseudo_bytes(openssl_cipher_iv_length('AES-128-CBC')));
$encodedEncryptedData = base64_encode(openssl_encrypt($string, "AES-128-CBC", $key, OPENSSL_RAW_DATA, base64_decode($iv)));
I also tried with the same IV (fixed) but it doesn't work either...
I miss something but I don't know what.
Thx in advance
Thx to #Michael
I use these functions :
function base64url_encode( $data ){
return rtrim( strtr( base64_encode( $data ), '+/', '-_'), '=');
}
function base64url_decode( $data ){
return base64_decode( strtr( $data, '-_', '+/') . str_repeat('=', 3 - ( 3 + strlen( $data )) % 4 ));
}
Instead of base64_encode and base64_decode
Related
I want to exactly build a function which produces a HMAC with a secret key like this site provides:
http://www.freeformatter.com/hmac-generator.html
The Java 8 lib only provides MessageDigest and KeyGenerator which both only support up to SH256.
Also, Google doesn't give me any result for an implementation to generate a HMAC.
Does someone know a implementation?
I have this code to generate an ordinary SH256 but I guess this doesn't help me much:
public static String get_SHA_512_SecurePassword(String passwordToHash) throws Exception {
String generatedPassword = null;
MessageDigest md = MessageDigest.getInstance("SHA-512");
byte[] bytes = md.digest(passwordToHash.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
generatedPassword = sb.toString();
System.out.println(generatedPassword);
return generatedPassword;
}
The simplest way can be -
private static final String HMAC_SHA512 = "HmacSHA512";
private static String toHexString(byte[] bytes) {
Formatter formatter = new Formatter();
for (byte b : bytes) {
formatter.format("%02x", b);
}
return formatter.toString();
}
public static String calculateHMAC(String data, String key)
throws SignatureException, NoSuchAlgorithmException, InvalidKeyException
{
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), HMAC_SHA512);
Mac mac = Mac.getInstance(HMAC_SHA512);
mac.init(secretKeySpec);
return toHexString(mac.doFinal(data.getBytes()));
}
public static void main(String[] args) throws Exception {
String hmac = calculateHMAC("data", "key");
System.out.println(hmac);
}
You can change the HMAC_SHA512 variable to any of the Mac algorithm and the code will work the same way.
Hope this helps:
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Test1 {
private static final String HMAC_SHA512 = "HmacSHA512";
public static void main(String[] args) {
Mac sha512Hmac;
String result;
final String key = "Welcome1";
try {
final byte[] byteKey = key.getBytes(StandardCharsets.UTF_8);
sha512Hmac = Mac.getInstance(HMAC_SHA512);
SecretKeySpec keySpec = new SecretKeySpec(byteKey, HMAC_SHA512);
sha512Hmac.init(keySpec);
byte[] macData = sha512Hmac.doFinal("My message".getBytes(StandardCharsets.UTF_8));
// Can either base64 encode or put it right into hex
result = Base64.getEncoder().encodeToString(macData);
//result = bytesToHex(macData);
} catch (UnsupportedEncodingException | InvalidKeyException | NoSuchAlgorithmException e) {
e.printStackTrace();
} finally {
// Put any cleanup here
System.out.println("Done");
}
}
}
For converting from byte array to hex refer this stackoverflow answer : here
Also you can use a little wrapper by Apache Commons codec:
import static org.apache.commons.codec.digest.HmacAlgorithms.HMAC_SHA_512;
import org.apache.commons.codec.digest.HmacUtils;
public class HmacService {
private String sharedSecret;
public HmacService(String sharedSecret) {
this.sharedSecret = sharedSecret;
}
public String calculateHmac(String data) {
return new HmacUtils(HMAC_SHA_512, sharedSecret).hmacHex(data);
}
public boolean checkHmac(String data, String hmacHex) {
return calculateHmac(data).equals(hmacHex);
}
}
You could use Caesar (version 0.6.0 or later):
int blockSize = 128;
String secretKey = "My secret key";
String message = "Message to hash";
System.out.println(
new Hmac(
new ImmutableMessageDigest(
MessageDigest.getInstance("SHA-512")
),
blockSize,
new PlainText(secretKey),
new PlainText(message)
).asHexString()
);
I am connecting a third party interface and they only gave me a Java code demo, I need to connect it with my PHP system.But I can't handle the encryption, my encryption proccess in PHP always gets different result with the third party Java code.
I install phpseclib/phpseclib package via composer in order to perform AES encryption.
Java Encryption Code:
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
private static final String KEY_ALGORITHM = "AES";
private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
public static String encrypt(String content, String encryptKey) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(encryptKey));
byte[] result = cipher.doFinal(byteContent);
return toHexString(result);
} catch (Exception ex) {
}
return null;
}
private static SecretKeySpec getSecretKey(final String encryptKey) {
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance(KEY_ALGORITHM);
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(encryptKey.getBytes());
kg.init(128, secureRandom);
SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);
} catch (NoSuchAlgorithmException ex) {
}
return null;
}
public static String toHexString(byte b[]) {
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < b.length; i++) {
String plainText = Integer.toHexString(0xff & b[i]);
if (plainText.length() < 2)
plainText = "0" + plainText;
hexString.append(plainText);
}
return hexString.toString();
}
PHP encryption code:
//composer require phpseclib/phpseclib
use phpseclib\Crypt\AES;
function aesEncrypt($message, $key)
{
$cipher = new AES(AES::MODE_ECB);
$cipher->setKeyLength(128);
$cipher->setKey(hex2bin($key));
$cryptText = $cipher->encrypt($message);
return bin2hex($cryptText);
}
Java Result:
before:testStringtestString
key:acccd6fa0caf52a0e5e5fda8bd3ff55a
after:2bbd3011eb084c9494228fe913e6e033aaffb1aa04ef9d0f14614c21fd16af9a
PHP Result:
before:testStringtestString
key:acccd6fa0caf52a0e5e5fda8bd3ff55a
after:d9a683511cdeb174bf51a285140071a8b38b57c6c6133d1b9425846ae0ec333b
Error : javax.crypto.IllegalBlockSizeException: Input length must be
multiple of 16 when decrypting with padded cipher
Tried Solutions: I've tried to to change the padding to "AES/ECB/NoPadding", "AES/ECB/PKCS5", "AES/CBC/NoPadding", "AES/CBC/PKCS5Padding" and still received the same error or an error stating only AES or Rijndael required. Then I tried making the key use "AES" parameter and ALGO set to "AES/CBC/PKCS5Padding", but I recieved a missing parameter error which I tried to fix my adding new IvParameterSpec(new byte[16]) to cipher.init. It still resulted into the 16 bit issue. So I'm stuck now.
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.security.Key;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.*;
import java.io.PrintWriter;
import java.io.FileWriter;
import java.util.*;
import java.io.*;
// Don't forget to import any supporting classes you plan to use.
public class Crypto
{
private Scanner fileText;
private PrintWriter fileEncrypt;
private Scanner inputFile;
private PrintWriter outputFile;
private static final String ALGO = "AES/CBC/PKCS5Padding";
private byte[] keyValue;
public Crypto(String key)
{
keyValue = key.getBytes();
}
public String encrypt(String Data) throws Exception
{
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.ENCRYPT_MODE, key);
byte[] encVal = c.doFinal(Data.getBytes());
String encryptedValue = new BASE64Encoder().encode(encVal);
return encryptedValue;
}
public String decrypt(String encryptedData) throws Exception
{
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decodedValue = new BASE64Decoder().decodeBuffer(encryptedData);
byte[] decValue = c.doFinal(decodedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
public Key generateKey() throws Exception
{
Key key = new SecretKeySpec(keyValue, "AES");
return key;
}
// encrypt_decrypt("ENCRYPT", "CryptoPlaintext.txt", "CryptoCiphertext.txt" )
// encrypt_decrypt("DECRYPT", "CryptoCiphertext.txt", "CryptoDeciphered.txt")
public void encrypt_decrypt(String function_type , String source_file , String
target_file)
{
String lineValue = "";
String convertedValue = "";
try
{
inputFile = new Scanner(new File(source_file));
}
catch(Exception e)
{
System.out.println("( " + source_file + ") - File Opening Error");
}
try
{
outputFile = new PrintWriter(new FileWriter(target_file));
}
catch(Exception e)
{
System.out.println("( " + target_file + ") - File Opening Error");
}
while(inputFile.hasNext())
{
lineValue = inputFile.nextLine();
System.out.println("Source Line: " + lineValue);
try
{
if (function_type == "ENCRYPT")
{
convertedValue = encrypt(lineValue);
}
else if (function_type == "DECRYPT")
{
convertedValue = decrypt(lineValue);
}
}
catch(Exception e)
{
System.out.println(e);
}
System.out.println("Converted Line : " + convertedValue);
outputFile.write(convertedValue);
}
inputFile.close();
outputFile.close();
}
public static void main( String args[] ) throws IOException
{
// Write your code here...
// You will read from CryptoPlaintext.txt and write to
CryptoCiphertext.txt.
Crypto c = new Crypto("dk201anckse29sns");
c.encrypt_decrypt("ENCRYPT", "CryptoPlaintext.txt", "CryptoCiphertext.txt"
);
c.encrypt_decrypt("DECRYPT", "CryptoCiphertext.txt",
"CryptoDeciphered.txt");
//
// And then read from CryptoCiphertext.txt and write to
CryptoDeciphered.txt.
//
// DON'T forget your comments!
// =============================== DO NOT MODIFY ANY CODE BELOW HERE
==============================
// Compare the files
System.out.println(compareFiles() ? "The files are identical!" : "The
files are NOT identical.");
}
/**
* Compares the Plaintext file with the Deciphered file.
*
* #return true if files match, false if they do not
*/
public static boolean compareFiles() throws IOException
{
Scanner pt = new Scanner(new File("CryptoPlaintext.txt")); // Open the
plaintext file
Scanner dc = new Scanner(new File("CryptoDeciphered.txt")); // Open the
deciphered file
// Read through the files and compare them record by record.
// If any of the records do not match, the files are not identical.
while(pt.hasNextLine() && dc.hasNextLine())
if(!pt.nextLine().equals(dc.nextLine())) return false;
// If we have any records left over, then the files are not identical.
if(pt.hasNextLine() || dc.hasNextLine()) return false;
// The files are identical.
return true;
}
}
There are two errors in your code:
You forgot to generate a random IV and prefix it to your ciphertext (before encoding it to base 64). You'd need to find the IV from your ciphertext and then retrieve it back again during decryption.
Note that CBC code requires an IV indistinguishable from random. You can create it using new SecureRandom (only during encryption, of course) and IvParameterSpec. The code will probably run without this as the default implementation in Java defaults on an all-zero IV. Possibly that is enough for this assignment.
But that's not what generates the error; that's much more of a banality:
You're calling outputFile.write instead of outputFile.println which means that newlines aren't inserted, and all base 64 encodings are put in a single line.
Note that you should not use any classes from sun.misc. Those are private to the Java implementation and are not part of the Java API. The new Java versions have java.util.Base64 for your convenience. Actually, the sun.misc version may insert line endings within the base 64 encoding that will break your code for longer lines.
For example:
package nl.owlstead.stackoverflow;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.Key;
import java.util.Base64;
import java.util.Scanner;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class Crypto {
private Scanner inputFile;
private PrintWriter outputFile;
private static final String ALGO = "AES/CBC/PKCS5Padding";
private byte[] keyValue;
public Crypto(String key) {
keyValue = key.getBytes();
}
public String encrypt(String Data) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.ENCRYPT_MODE, key,
new IvParameterSpec(new byte[c.getBlockSize()]));
byte[] encVal = c.doFinal(Data.getBytes());
String encryptedValue = Base64.getEncoder().encodeToString(encVal);
return encryptedValue;
}
public String decrypt(String encryptedData) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key,
new IvParameterSpec(new byte[c.getBlockSize()]));
byte[] decodedValue = Base64.getDecoder().decode(encryptedData);
byte[] decValue = c.doFinal(decodedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
public Key generateKey() throws Exception {
Key key = new SecretKeySpec(keyValue, "AES");
return key;
}
public void encrypt_decrypt(String function_type, String source_file,
String target_file) {
String lineValue = "";
String convertedValue = "";
try {
inputFile = new Scanner(new File(source_file));
} catch (Exception e) {
System.out.println("( " + source_file + ") - File Opening Error");
}
try {
outputFile = new PrintWriter(new FileWriter(target_file));
} catch (Exception e) {
System.out.println("( " + target_file + ") - File Opening Error");
}
while (inputFile.hasNext()) {
lineValue = inputFile.nextLine();
System.out.println("Source Line: " + lineValue);
try {
if (function_type == "ENCRYPT") {
convertedValue = encrypt(lineValue);
} else if (function_type == "DECRYPT") {
convertedValue = decrypt(lineValue);
}
} catch (Exception e) {
System.out.println(e);
}
System.out.println("Converted Line : " + convertedValue);
outputFile.println(convertedValue);
}
inputFile.close();
outputFile.close();
}
public static void main(String args[]) throws IOException {
Crypto c = new Crypto("dk201anckse29sns");
c.encrypt_decrypt("ENCRYPT", "CryptoPlaintext.txt",
"CryptoCiphertext.txt");
c.encrypt_decrypt("DECRYPT", "CryptoCiphertext.txt",
"CryptoDeciphered.txt");
System.out.println(compareFiles() ? "The files are identical!"
: "The files are NOT identical.");
}
/**
* Compares the Plaintext file with the Deciphered file.
*
* #return true if files match, false if they do not
*/
public static boolean compareFiles() throws IOException {
Scanner pt = new Scanner(new File("CryptoPlaintext.txt")); // Open the
Scanner dc = new Scanner(new File("CryptoDeciphered.txt")); // Open the
// Read through the files and compare them record by record.
// If any of the records do not match, the files are not identical.
while (pt.hasNextLine() && dc.hasNextLine()) {
String ptl = pt.nextLine();
String dcl = dc.nextLine();
if (!ptl.equals(dcl))
{
System.out.println(ptl);
System.out.println(dcl);
continue;
// return false;
}
}
// If we have any records left over, then the files are not identical.
if (pt.hasNextLine() || dc.hasNextLine())
return false;
// The files are identical.
return true;
}
}
A working solution for you:
Just added a random IV value while initiating your cipher during encrypting and decrypting.
c.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(new byte[16]));
package com.samples;
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.io.PrintWriter;
import java.io.FileWriter;
// Don't forget to import any supporting classes you plan to use.
public class Crypto
{
private Scanner fileText;
private PrintWriter fileEncrypt;
private Scanner inputFile;
private PrintWriter outputFile;
private static final String ALGO = "AES/CBC/PKCS5Padding";
private byte[] keyValue;
public Crypto(String key)
{
keyValue = key.getBytes();
}
public String encrypt(String Data) throws Exception
{
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(new byte[16]));
byte[] encVal = c.doFinal(Data.getBytes());
String encryptedValue = new BASE64Encoder().encode(encVal);
return encryptedValue;
}
public String decrypt(String encryptedData) throws Exception
{
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(new byte[16]));
byte[] decodedValue = new BASE64Decoder().decodeBuffer(encryptedData);
byte[] decValue = c.doFinal(decodedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
public Key generateKey() throws Exception
{
Key key = new SecretKeySpec(keyValue, "AES");
return key;
}
// encrypt_decrypt("ENCRYPT", "CryptoPlaintext.txt", "CryptoCiphertext.txt" )
// encrypt_decrypt("DECRYPT", "CryptoCiphertext.txt", "CryptoDeciphered.txt")
public void encrypt_decrypt(String function_type, String source_file, String target_file)
{
String lineValue = "";
String convertedValue = "";
try
{
inputFile = new Scanner(new File(source_file));
}
catch(Exception e)
{
System.out.println("( " + source_file + ") - File Opening Error");
}
try
{
outputFile = new PrintWriter(new FileWriter(target_file));
}
catch(Exception e)
{
System.out.println("( " + target_file + ") - File Opening Error");
}
while(inputFile.hasNext())
{
lineValue = inputFile.nextLine();
System.out.println("Source Line: " + lineValue);
try
{
if (function_type == "ENCRYPT")
{
convertedValue = encrypt(lineValue);
}
else if (function_type == "DECRYPT")
{
convertedValue = decrypt(lineValue);
}
}
catch(Exception e)
{
System.out.println(e);
}
System.out.println("Converted Line : " + convertedValue);
outputFile.write(convertedValue);
}
inputFile.close();
outputFile.close();
}
public static void main( String args[] ) throws IOException
{
// Write your code here...
// You will read from CryptoPlaintext.txt and write to CryptoCiphertext.txt.
Crypto c = new Crypto("dk201anckse29sns");
c.encrypt_decrypt("ENCRYPT", "C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoPlaintext.txt", "C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoCiphertext.txt"
);
c.encrypt_decrypt("DECRYPT", "C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoCiphertext.txt",
"C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoDeciphered.txt");
//
// And then read from CryptoCiphertext.txt and write to CryptoDeciphered.txt.
//
// DON'T forget your comments!
// =============================== DO NOT MODIFY ANY CODE BELOW HE ==============================
// Compare the files
System.out.println(compareFiles() ? "The files are identical!" : "The files are NOT identical.");
}
/**
* Compares the Plaintext file with the Deciphered file.
*
* #return true if files match, false if they do not
*/
public static boolean compareFiles() throws IOException
{
Scanner pt = new Scanner(new File("C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoPlaintext.txt")); // Open the plaintext file
Scanner dc = new Scanner(new File("C:\\Users\\mundrap\\Eclipse_Workspace\\Java-8\\src\\com\\samples\\CryptoDeciphered.txt")); // Open the deciphered file
// Read through the files and compare them record by record.
// If any of the records do not match, the files are not identical.
while(pt.hasNextLine() && dc.hasNextLine())
if(!pt.nextLine().equals(dc.nextLine())) return false;
// If we have any records left over, then the files are not identical.
if(pt.hasNextLine() || dc.hasNextLine()) return false;
// The files are identical.
return true;
}
}
I want to exactly build a function which produces a HMAC with a secret key like this site provides:
http://www.freeformatter.com/hmac-generator.html
The Java 8 lib only provides MessageDigest and KeyGenerator which both only support up to SH256.
Also, Google doesn't give me any result for an implementation to generate a HMAC.
Does someone know a implementation?
I have this code to generate an ordinary SH256 but I guess this doesn't help me much:
public static String get_SHA_512_SecurePassword(String passwordToHash) throws Exception {
String generatedPassword = null;
MessageDigest md = MessageDigest.getInstance("SHA-512");
byte[] bytes = md.digest(passwordToHash.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
}
generatedPassword = sb.toString();
System.out.println(generatedPassword);
return generatedPassword;
}
The simplest way can be -
private static final String HMAC_SHA512 = "HmacSHA512";
private static String toHexString(byte[] bytes) {
Formatter formatter = new Formatter();
for (byte b : bytes) {
formatter.format("%02x", b);
}
return formatter.toString();
}
public static String calculateHMAC(String data, String key)
throws SignatureException, NoSuchAlgorithmException, InvalidKeyException
{
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), HMAC_SHA512);
Mac mac = Mac.getInstance(HMAC_SHA512);
mac.init(secretKeySpec);
return toHexString(mac.doFinal(data.getBytes()));
}
public static void main(String[] args) throws Exception {
String hmac = calculateHMAC("data", "key");
System.out.println(hmac);
}
You can change the HMAC_SHA512 variable to any of the Mac algorithm and the code will work the same way.
Hope this helps:
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Test1 {
private static final String HMAC_SHA512 = "HmacSHA512";
public static void main(String[] args) {
Mac sha512Hmac;
String result;
final String key = "Welcome1";
try {
final byte[] byteKey = key.getBytes(StandardCharsets.UTF_8);
sha512Hmac = Mac.getInstance(HMAC_SHA512);
SecretKeySpec keySpec = new SecretKeySpec(byteKey, HMAC_SHA512);
sha512Hmac.init(keySpec);
byte[] macData = sha512Hmac.doFinal("My message".getBytes(StandardCharsets.UTF_8));
// Can either base64 encode or put it right into hex
result = Base64.getEncoder().encodeToString(macData);
//result = bytesToHex(macData);
} catch (UnsupportedEncodingException | InvalidKeyException | NoSuchAlgorithmException e) {
e.printStackTrace();
} finally {
// Put any cleanup here
System.out.println("Done");
}
}
}
For converting from byte array to hex refer this stackoverflow answer : here
Also you can use a little wrapper by Apache Commons codec:
import static org.apache.commons.codec.digest.HmacAlgorithms.HMAC_SHA_512;
import org.apache.commons.codec.digest.HmacUtils;
public class HmacService {
private String sharedSecret;
public HmacService(String sharedSecret) {
this.sharedSecret = sharedSecret;
}
public String calculateHmac(String data) {
return new HmacUtils(HMAC_SHA_512, sharedSecret).hmacHex(data);
}
public boolean checkHmac(String data, String hmacHex) {
return calculateHmac(data).equals(hmacHex);
}
}
You could use Caesar (version 0.6.0 or later):
int blockSize = 128;
String secretKey = "My secret key";
String message = "Message to hash";
System.out.println(
new Hmac(
new ImmutableMessageDigest(
MessageDigest.getInstance("SHA-512")
),
blockSize,
new PlainText(secretKey),
new PlainText(message)
).asHexString()
);
I created ciphertext with javax.crypto.Cipher org.apache.commons.codec.binary.Base64 and using Java like following:
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class PwdCipher {
private static final Logger LOG = LoggerFactory.getLogger(PwdCipher.class);
private static final int BASE64_ARG0 = 32;
private static final String SECRET = "tvnw63ufg9gh5392";
private static byte[] linebreak = {};
private static SecretKey key;
private static Cipher cipher;
private static Base64 coder;
static {
key = new SecretKeySpec(SECRET.getBytes(), "AES");
try {
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "SunJCE");
} catch (NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException e) {
LOG.debug("Erro ao criar encriptador.", e);
}
coder = new Base64(BASE64_ARG0, linebreak, true);
}
private PwdCipher(){
}
public static synchronized String encrypt(String plainText) {
try {
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = cipher.doFinal(plainText.getBytes());
return new String(coder.encode(cipherText));
} catch (Exception e) {
throw new GdocException("Erro ao encriptar senha.", e);
}
}
public static synchronized String decrypt(String codedText) {
try {
byte[] encypted = coder.decode(codedText.getBytes());
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(encypted);
return new String(decrypted);
} catch (Exception e) {
throw new GdocException("Erro ao decriptar senha.", e);
}
}
}
I need to decrypt the text (encrypted with class PwdCipher) using Node.js, but when I use the following code:
exports.decryptLdapPassword = function(password){
var key = 'tvnw63ufg9gh5392';
var ciphertext = password;
var crypto = require('crypto');
var decipher = crypto.createDecipher('aes-128-ecb', key);
var decrypted = decipher.update(ciphertext, 'base64', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
};
It turns out the following exception:
> crypto.js:323 var ret = this._binding.final();
> ^ TypeError: error:00000000:lib(0):func(0):reason(0)
> at Decipher.Cipher.final (crypto.js:323:27)
> at Object.exports.decryptLdapPassword (C:\ProjetosTFS\GDOC\fSuporte\GDoc\Versionado\Fontes\woodstock\server\api\service\service.util.js:14:25)
> at Promise.<anonymous> (C:\ProjetosTFS\GDOC\fSuporte\GDoc\Versionado\Fontes\woodstock\server\api\service\service.controller.js:111:34)
> at Promise.<anonymous> (C:\ProjetosTFS\GDOC\fSuporte\GDoc\Versionado\Fontes\woodstock\node_modules\mongoose\node_modules\mpromise\lib\promise.js:177:8)
> at Promise.emit (events.js:95:17)
> at Promise.emit (C:\ProjetosTFS\GDOC\fSuporte\GDoc\Versionado\Fontes\woodstock\node_modules\mongoose\node_modules\mpromise\lib\promise.js:84:38)
> at Promise.fulfill (C:\ProjetosTFS\GDOC\fSuporte\GDoc\Versionado\Fontes\woodstock\node_modules\mongoose\node_modules\mpromise\lib\promise.js:97:20)
> at Promise.resolve (C:\ProjetosTFS\GDOC\fSuporte\GDoc\Versionado\Fontes\woodstock\node_modules\mongoose\lib\promise.js:114:23)
> at Promise.<anonymous> (C:\ProjetosTFS\GDOC\fSuporte\GDoc\Versionado\Fontes\woodstock\node_modules\mongoose\node_modules\mpromise\lib\promise.js:177:8)
> at Promise.emit (events.js:95:17)
Any idea?
Worked! Solution published in https://github.com/joyent/node/issues/20983#issuecomment-100885608