I need to translate a short code in java to python 3.
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class DesEncrypterPdys {
private static DesEncrypterPdys desEncrypter;
private static Cipher ecipher;
private static Cipher dcipher;
private DesEncrypterPdys() throws DesEncrypterException{
try {
if(ecipher == null || dcipher == null){
String cryptoKey;
cryptoKey = "RAMPOLO S.O. Plokity Lopiokiujhygh ;)";
SecretKey k = SecretKeyFactory.getInstance("DES").generateSecret(new DESKeySpec(cryptoKey.getBytes()));
ecipher = Cipher.getInstance("DES");
dcipher = Cipher.getInstance("DES");
ecipher.init(Cipher.ENCRYPT_MODE, k);
dcipher.init(Cipher.DECRYPT_MODE, k);
}
}catch (Exception e) {
throw new DesEncrypterException(e);
}
}
public static DesEncrypterPdys getInstance() throws DesEncrypterException{
if (desEncrypter == null || ecipher == null || dcipher == null) {
desEncrypter = new DesEncrypterPdys();
}
return desEncrypter;
}
public String encrypt(String str) throws DesEncrypterException{
try {
if(str == null) return null;
// Encode the string into bytes using utf-8
byte[] utf8 = str.getBytes("UTF8");
// Encrypt
byte[] enc = ecipher.doFinal(utf8);
// Encode bytes to base64 to get a string
return new sun.misc.BASE64Encoder().encode(enc);
} catch (javax.crypto.BadPaddingException e) {
throw new DesEncrypterException(e);
} catch (IllegalBlockSizeException e) {
throw new DesEncrypterException(e);
}
catch (java.io.IOException e) {
throw new DesEncrypterException(e);
}
}
public String decrypt(String str) throws DesEncrypterException{
try {
if(str == null) return null;
// Decode base64 to get bytes
byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);
// Decrypt
byte[] utf8 = dcipher.doFinal(dec);
// Decode using utf-8
return new String(utf8, "UTF8");
} catch (javax.crypto.BadPaddingException e) {
throw new DesEncrypterException(e);
} catch (IllegalBlockSizeException e) {
throw new DesEncrypterException(e);
} catch (java.io.IOException e) {
throw new DesEncrypterException(e);
}
}
}
Im tried to use something like this:
import pyDes as pds
import base64 as b64
cryptoKey = "RAMPOLO S.O. Plokity Lopiokiujhygh ;)";
data = b" " # here should be a data for decrypting
k = pds.des(cryptoKey, pds.ECB, b"\0\0\0\0\0\0\0\0", pad=None, padmode=pds.PAD_PKCS5)
d = k.encrypt(data)
print("Encrypted: %r" % d)
print("Decrypted: %r" % k.decrypt(d))
print(b64.b64encode(d))
but unfortunately no luck:/
What I want to receive is a short program to encrypt and decode passwords. unfortunately I encountered a problem with too long cryptokey(?). Once I was able to translate an analogous piece of code but it was probably a matter of luck that old case was corresponded to the case from the pydes documentation. Now is different...
Can some one help me with translation this java code to python?
When running your code the error returned is:
>>> import pyDes as pds
>>> import base64 as b64
>>> cryptoKey = "RAMPOLO S.O. Plokity Lopiokiujhygh ;)"
>>> data = b"qwertyuiop" # Random gibberish
>>> k = pds.des(cryptoKey, pds.ECB, b"\0\0\0\0\0\0\0\0", pad=None, padmode=pds.PAD_PKCS5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/pyDes.py", line 400, in __init__
raise ValueError("Invalid DES key size. Key must be exactly 8 bytes long.")
ValueError: Invalid DES key size. Key must be exactly 8 bytes long.
if you take a look at the Github documentation for pyDES it specifies that for DES encryption the key should be 8bytes long, yours is way longer. You need to use a shorter key, then it works fine.
>>> k = pds.des('12345678', pds.ECB, b"\0\0\0\0\0\0\0\0", pad=None, padmode=pds.PAD_PKCS5)
>>> k
<pyDes.des object at 0x7fc4ade1f9d0>
Important sidenote, from a security point of view you should avoid using DES as it's completely broken for today's standards, even the Wikipedia page (which is not a great source of cryptographic knowledge) shows that DES breaking is feasible. Also ECB mode is broken as it doesn't provide any security guarantees because each block is encrypted in the exact same way, check this.
Related
I've been trying to port this Java Program to Node.js. I've tried a few ways and still unable to get this done so far. Could be due to my limited knowledge in Cryptography.
The Node.js Program I've written is this.
var crypto = require('crypto');
var iv = crypto.randomBytes(8);
var encrypt = function(data, key) {
var decodeKey = crypto.createHash('sha512').update(key, 'utf-8').digest().slice(0, 24);
var cipher = crypto.createCipheriv('des-ede-cbc', decodeKey, iv);
return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
};
var data = 'abc101'
var key = '1785851816255252-8887772';
var cipher = encrypt(data, key);
console.log(cipher);
I keep receiving the following error:
Error: Invalid key length
The original program I am trying to port is this:
import java.security.MessageDigest;
import java.security.spec.KeySpec;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class PasswordEncryptor {
public static void main(String[] args) {
String passwd = "abc101";
String msgId = "1785851816255252-8887772";
String result = "";
try {
if (passwd == null && passwd.equals("") && msgId == null && msgId.equals("")) {
System.out.println("Wrong Inputs");
} else {
result = PasswordEncryptor.encryptPassword(msgId, passwd);
}
System.out.println(result);
} catch (Exception e) {
System.out.println("Exception in PasswordEncryption ::: " + e);
}
}
public static String encryptPassword(String msgId, String password) {
String finalValue = "";
try {
MessageDigest mDigest = MessageDigest.getInstance("SHA-512");
byte[] digestSeed = mDigest.digest(msgId.getBytes());
byte[] seedEncArray = Arrays.copyOf(digestSeed, 24);
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
SecretKeySpec skspec = new SecretKeySpec(seedEncArray, "DESede");
IvParameterSpec iv = new IvParameterSpec(new byte[8]);
cipher.init(Cipher.ENCRYPT_MODE, skspec, iv);
byte[] finalByteArray = cipher.doFinal(password.getBytes());
finalValue = new String(Base64.encodeBase64(finalByteArray));
} catch (Exception e) {
System.out.println("Exception in encryptPassword ::::" + e);
}
return finalValue;
}
}
Any help is appreciated. Thank you.
nodejs calls OpenSSL, whose naming schemes have some odd warts due to hysterical raisins. des-ede-$mode in OpenSSL is actually Keying Option 2, aka 2-key TDEA. For 'real' 3-key TDEA you must ask for des-ede3-$mode in this case des-ede3-cbc.
Also the Java code uses new byte[8] for the IV value, which is 8 bytes all zero, but your nodejs code uses random bytes. Random is actually better cryptographically, but if your goal is to produce the same results as the Java code you need to replicate its mistake.
Finally the Java code encodes the result in base64 while your nodejs code uses hex. These are semantically equivalent and easily interconvertible, but are not the same. If you do want the same, nodejs does support base64.
Aside: the attempted error check in the Java code
if (passwd == null && passwd.equals("") && msgId == null && msgId.equals(""))
is just stupid; no Java String can be == null and .equals("") simultaneously. All those && log-and should be || log-or. This code has clearly not been written or tested or reviewed competently; if I were you (which I'm not) I would avoid having anything to do with it.
Trying to create java class which will encrypt and decrypt as like C# code in below.
Below is my code for C#, I need to convert it to Java. Can someone help me how to do it?
I've been doing this for almost 2 days yet can't find any solutions on how to convert it. I am new to crypto.
Note - It seems C# code used ACME libraries. But in my java, i should not use ACME jar files.
public static string EncryptBase64(string key, string clearText)
{
if (key.Length > 8)
key = key.Substring(0, 8);
byte[] keyBytes = System.Text.Encoding.ASCII.GetBytes(key);
byte[] clearBytes = GetClearTextBytes(clearText);
// calculate the number of legitimate bytes in the last block
byte lastByte = (byte)(8 - (clearBytes.Length - textEncoding.GetByteCount(clearText)));
MemoryStream ms = new MemoryStream();
DES des = new DESCryptoServiceProvider();
des.Padding = PaddingMode.None;
des.GenerateIV();
System.Security.Cryptography.ICryptoTransform ict = des.CreateEncryptor(keyBytes, des.IV);
CryptoStream cs = new CryptoStream(ms, ict, CryptoStreamMode.Write);
cs.Write(clearBytes, 0, clearBytes.Length);
cs.FlushFinalBlock();
ms.Close();
byte[] cipherBytes = ms.ToArray();
// create a byte output stream for Acme compatibality
MemoryStream acmeCompatStream = new MemoryStream();
// Acme writes the IV to the frist block
acmeCompatStream.Write(des.IV, 0, 8);
for (int i = 0; i < cipherBytes.Length; i = i + 8)
{
// write the next block
acmeCompatStream.Write(cipherBytes, i, 8);
// write the number of valid bytes in the block
if (i == cipherBytes.Length - 8)
acmeCompatStream.WriteByte(lastByte);
else
acmeCompatStream.WriteByte(8);
}
acmeCompatStream.Close();
cipherBytes = acmeCompatStream.ToArray();
return (System.Convert.ToBase64String(cipherBytes));
}
Below is the code which i have tried in java. I have two different encryption function. I have tried both of the encryption method. But both are not giving expected encrypted string to decrypt in acme.
package com.abc.some.common.nativeDES;
import java.io.ByteArrayOutputStream;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.xml.bind.DatatypeConverter;
public class DESEncrypt {
public String keyValue = "123456789";
public static void main(String[] args) {
String text = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><SomeRequest><OrderNumber>1564578</OrderNumber></SomeRequest>";
String codedtext ="not encrypted";
try{
codedtext = new DESEncrypt().Encrypt1(text);
//codedtext = new DESEncrypt().encrypt(text);
}catch (Exception e) {
System.out.println("Exception in Encryption.. " + e.getMessage());
}
System.out.println(codedtext);
}
public String Encrypt1(String CXML) {
try {
KeySpec myKey = new DESKeySpec(keyValue.getBytes("UTF8"));
SecretKey key = SecretKeyFactory.getInstance("DES").generateSecret(myKey);
Cipher ecipher = Cipher.getInstance("DES");
ecipher.init(Cipher.ENCRYPT_MODE, key);
byte[] data = CXML.getBytes("ASCII");
Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");
c.init(Cipher.ENCRYPT_MODE, key);
byte[] crypt = ecipher.doFinal(data);
//String encoded = DatatypeConverter.printBase64Binary(crypt.toString().getBytes("ASCII"));
//String encoded = DatatypeConverter.printBase64Binary(crypt.getBytes("ASCII"));
String encoded = DatatypeConverter.printBase64Binary(crypt).toString();
System.out.println(encoded);
return encoded;
} catch (Exception ex) {
}
return null;
}
}
But I have used below java file to encrypt the string which is using acme jar files. This was working as expected. But as per my project requirement i should not use the external(ACME) jar files.
package com.abc.common.encryption;
import java.io.FileInputStream;
import java.util.Properties;
import Acme.Crypto.SecurityDES;
public class ESBCryptoDES {
public static void main(String args[]){
// DESEncrypt("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><SomeRequest><OrderNumber>1564578</OrderNumber></SomeRequest>"
// ,"D:\\name\\proj\\order\\Encryption\\st.properties");
DESDecrypt("vQ9C7ZrLzjQpHvZjtHvUb0mFCr824/aClY2jKbeciczsRVr+kEETFvDuHgdBS/aLskYV3WX3U5TANSlK3pH80r3xOyn9Q8rTjlB/yXyU7J9MgibJ66jJx0wrqeloAkmQzqj+b5+I/lXANSlK3pH80kT1D+jqWAeV"
,"D:\\name\\proj\\order\\Encryption\\stDecrypt.properties");
}
public static String DESEncrypt(String SourceStrForCrypt,String PropPath) {
String encrypt = "";
String decrypt = "";
// Load the property file.
Properties prop = new Properties();
try {
FileInputStream in = new FileInputStream(PropPath);
prop.load(in);
in.close();
} catch (Exception e) {
System.out.println("Exception in loading property file.. "
+ e.getMessage());
}
// Encrypt the given content.
try {
String keypath = prop.getProperty("proj.sample.DEV");
System.out.println("sample" + keypath);
String SourceToEncrypt = SourceStrForCrypt; //This will provide the xml string to encrypt
// Encryption
encrypt = SecurityDES.DesEncryptBase64(keypath,SourceToEncrypt);
System.out.println(encrypt);
// Decryption
decrypt = SecurityDES.DesDecryptBase64(keypath, encrypt);
System.out.println(decrypt);
} catch (Exception e) {
System.out.println("Exception in Encryption.. " + e.getMessage());
}
return encrypt;
}
public static String DESDecrypt(String SourceStrForCrypt,String PropPath) {
// TODO Auto-generated method stub
String decrypt = "";
Properties prop = new Properties();
try {
FileInputStream in = new FileInputStream(PropPath);
prop.load(in);
in.close();
} catch (Exception e) {
System.out.println("Exception in loading property file.. "+ e.getMessage());
}
try {
String abc_keyPath = prop
.getProperty("proj.abc.DEV");
System.out.println("keypath" + abc_keyPath);
// Decryption
decrypt = SecurityDES.DesDecryptBase64(abc_keyPath, SourceStrForCrypt);
System.out.println("decrypted..."+decrypt);
} catch (Exception e) {
System.out.println("Exception in Encryption.. " + e.getMessage());
}
return decrypt;
}
}
Calling doFinal() twice doesn't make sense.
Printing the value of byte[].toString() doesn't make sense. It doesn't contain the ciphertext.
Converting that to base-64 doesn't make sense. It still doesn't contain the ciphertext.
You need to convert the byte[] array returned by the first doFinal() call directly to base-64, without the round-trip to and from String() caused by calling toString() and then `getBytes().
NB For some reason you have a variable called encrypt in your decrypt method, and for some even stranger reason you are returning it instead of decrypt, which is the only variable that actually contains plaintext.
I am trying to encrypt a file using the RSA algorithm with a public key (which I build using a given modulus and exponent).
My code works fine with Android 4.3, and I get all I need. But I am trying to make it work for other Android versions such (2.3.3) and there is no way. It complains about a "input too large for RSA cipher".
If I have understood the theory well the block cipher size is relative to the publicKey.size(), therefore if this don't change from one version of Android to another I should get the same result, should't I?
Here is my code:
package com.example.rsa_ex;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.spec.RSAPublicKeySpec;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import android.app.Activity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
public class MainActivity extends Activity
{
private byte[] mKeyModulus = {...};
private byte[] mKeyExponent = {...};
private String tag = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String token = "";
try
{
token = readTokenFromFile("token.base64");
}
catch (IOException e)
{
Log.d(tag, "Failed to open property file");
}
byte[] encodedBytes = Base64.encode(token.getBytes(), 0);
Log.d(tag, "Encrypt Token"+ onEncrypt(encodedBytes));
}
public String readTokenFromFile(String fileName) throws IOException
{
String token = "empty";
try
{
AssetManager assetManager = getAssets();
InputStream iS = assetManager.open(fileName);
byte[] buffer = new byte[iS.available()];
iS.read(buffer);
ByteArrayOutputStream oS = new ByteArrayOutputStream();
oS.write(buffer);
token = oS.toString();
oS.close();
iS.close();
Log.d(tag, "token ==> "+token);
}
catch (IOException e)
{
Log.d(tag, "Failed to open property file");
}
return token;
} // readTokenFromFile end
public String onEncrypt(byte[] token)
{
Log.d(tag,"onEncrypt entry");
String encryptedTranspherable = "";//null;
// get the publicKey
try
{
BigInteger m = new BigInteger(mKeyModulus);
BigInteger e = new BigInteger(mKeyExponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
Key pubKey = fact.generatePublic(new RSAPublicKeySpec(m, e));
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] encrypted = blockCipher(token,cipher);
encryptedTranspherable = Base64.encodeToString(encrypted, Base64.DEFAULT);
}
catch (Exception e)
{
throw new RuntimeException("serialisation error got issue here !! ==>"+ e.getMessage(), e);
}
return encryptedTranspherable;
}// onEncrypt end
private byte[] blockCipher(byte[] bytes,Cipher cipher) throws IllegalBlockSizeException, BadPaddingException
{
Log.d(tag,"ISecurityProvider blockCipher entry");
Log.d(tag,"ISecurityProvider byteArray =>"+ Arrays.toString(bytes));
byte[] scrambled = new byte[0];
// toReturn will hold the total result
byte[] toReturn = new byte[0];
int length = 256;
// another buffer. this one will hold the bytes that have to be modified in this step
byte[] buffer = new byte[Math.min(bytes.length, length)];//(bytes.length > length ? length : bytes.length)];
for (int i=0; i< bytes.length; i++)
{
// if we filled our buffer array we have our block ready for de- or encryption
if ((i > 0) && (i % length == 0))
{
Log.d(tag,"ISecurityProvider blockCipher processing block i ="+i);
scrambled = cipher.doFinal(buffer);
toReturn = append(toReturn,scrambled);
// here we calculate the length of the next buffer required
int newlength = length;
// if newlength would be longer than remaining bytes in the bytes array we shorten it.
if (i + length > bytes.length)
{
newlength = bytes.length - i;
}
// clean the buffer array
buffer = new byte[newlength];
}
// copy byte into our buffer.
buffer[i%length] = bytes[i];
}
// this step is needed if we had a trailing buffer. should only happen when encrypting.
// example: we encrypt 110 bytes. 100 bytes per run means we "forgot" the last 10 bytes. they are in the buffer array
scrambled = cipher.doFinal(buffer);
// final step before we can return the modified data.
toReturn = append(toReturn,scrambled);
return toReturn;
}
private byte[] append(byte[] prefix, byte[] suffix)
{
byte[] toReturn = new byte[prefix.length + suffix.length];
int prefixSize = prefix.length;
int suffixSize = suffix.length;
for (int i=0; i< prefixSize; i++)
{
toReturn[i] = prefix[i];
}
for (int i=0; i< suffixSize; i++)
{
toReturn[i+prefixSize] = suffix[i];
}
return toReturn;
}
}
Any suggestion or advise will be more than welcome.
Thanks a lot.
From Android 4.2 enhancements:
Cryptography - Modified the default implementations of SecureRandom and Cipher.RSA to use OpenSSL. Added SSL Socket support for TLSv1.1 and TLSv1.2 using OpenSSL 1.0.1
This means that they are using another provider, and probably another default RSA padding mechanism. You should always provide a complete algorithm string and not rely on provider defaults, e.g. try "RSA/ECB/OAEPWithSHA1AndMGF1Padding" for new applications and "RSA/ECB/PKCS1Padding" for compatibility with older libraries.
Note that you usually do not encrypt a file directly using RSA. Usually you encrypt the file with a random data key using e.g. AES, a symmetric cipher. Then you encrypt that AES key with the RSA public key and send the result with the ciphertext. This way you can encrypt an (almost) arbitrary number of bytes. This is called hybrid cryptography.
I am currently writing a program in Java that will accept strings from PHP and either encrypt or decrypt them depending on need. The mechanism of encryption is AES-256 and I am using the BouncyCastle API to do it. To ensure that there are fewer problems in transferring the data back and forth, I use Base64 to encode the strings. The problem I am experiencing is that randomly, I cannot decrypt a string-some string can be decrypted ok, others cannot. I found a great article here at stackoverflow I thought could help here.
But I could not really see how it could fit my circumstances (I am not an encryption expert). Here's my current code. Thanks for your help.
class AES {
private final BlockCipher AESCipher = new AESEngine();
private PaddedBufferedBlockCipher pbbc;
private KeyParameter key;
AES()
{
init();
}
private void init()
{
try
{
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(256);
SecretKey sk = kg.generateKey();
key=new KeyParameter(sk.getEncoded());
pbbc=new PaddedBufferedBlockCipher(AESCipher, new PKCS7Padding());
}
catch (Exception e)
{
//Take care of later
}
}
private byte[] processing(byte[] input, boolean encrypt)
throws DataLengthException, InvalidCipherTextException {
pbbc.init(encrypt, key);
byte[] output = new byte[pbbc.getOutputSize(input.length)];
int bytesWrittenOut = pbbc.processBytes(
input, 0, input.length, output, 0);
pbbc.doFinal(output, bytesWrittenOut);
return output;
}
private byte[] _encrypt(byte[] input)
throws DataLengthException, InvalidCipherTextException {
return processing(input, true);
}
private byte[] _decrypt(byte[] input)
throws DataLengthException, InvalidCipherTextException {
return processing(input, false);
}
public String Encrypt(String input)
{
try
{
byte[] ba = input.getBytes("UTF-8");
byte[] encr = _encrypt(ba);
byte[] encryptedByteValue = new Base64().encode(encr);
String encryptedValue = new String(encryptedByteValue);
return encryptedValue;//+" and decrypted is "+Decrypt(encryptedValue);
}
catch (Exception e)
{
return "ENCRYPT_ERROR "+e.getMessage();
}
}
public String Decrypt(String input)
{
try
{
byte[] decodedValue = new Base64().decode(input.getBytes());
byte[] retr = _decrypt(decodedValue);
return new String(retr, "UTF-8").replaceAll("\\u0000", "");
}
catch (Exception e)
{
return "DECRYPT_ERROR "+e.getMessage();
}
}
I figured out what the problem is, and it was two fold. This is what I wound up doing:
1) I was using cURL to communicate strings between Java and PHP and encoding encrypted text as Base64. Since the plus sign is valid in Base64 and not handled by cURL (at least by older versions), I would have mangled strings, thus leading to the error. I switched to hex encoding.
2) I had to remove carriage return (\r\n) characters from strings that went into the Java layer.
Hope this helps someone.
I am trying to create a signature using the HMAC-SHA256 algorithm and this is my code.
I am using US ASCII encoding.
final Charset asciiCs = Charset.forName("US-ASCII");
final Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
final SecretKeySpec secret_key = new javax.crypto.spec.SecretKeySpec(asciiCs.encode("key").array(), "HmacSHA256");
sha256_HMAC.init(secret_key);
final byte[] mac_data = sha256_HMAC.doFinal(asciiCs.encode("The quick brown fox jumps over the lazy dog").array());
String result = "";
for (final byte element : mac_data)
{
result += Integer.toString((element & 0xff) + 0x100, 16).substring(1);
}
System.out.println("Result:[" + result + "]");
The result that I am getting from the above code is:
f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
This is same as to that of shown in the wiki
HMAC_SHA256("key", "The quick brown fox jumps over the lazy dog") = 0x f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
except for the 0x.
I am looking for ideas/comments if I am doing everything right or may be I can improve my code.
Here is my solution:
public static String encode(String key, String data) throws Exception {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
return Hex.encodeHexString(sha256_HMAC.doFinal(data.getBytes("UTF-8")));
}
public static void main(String [] args) throws Exception {
System.out.println(encode("key", "The quick brown fox jumps over the lazy dog"));
}
Or you can return the hash encoded in Base64:
Base64.encodeBase64String(sha256_HMAC.doFinal(data.getBytes("UTF-8")));
The output in hex is as expected:
f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8
The 0x just denotes that the characters after it represent a hex string.
0x1A == 1Ah == 26 == 1A
So the 0x is just to clarify what format the output is in, no need to worry about it.
If you're using Guava, its latest release now lets you use
Hashing.hmacSha256()
One example of using this:
String hash = Hashing.hmacSha256("mykey".getBytes(StandardCharsets.UTF_8)).hashString("my_message", StandardCharsets.UTF_8).toString()
Further documentation here: https://guava.dev/releases/23.0/api/docs/com/google/common/hash/Hashing.html#hmacSha256-byte:A-
The answer that you got there is correct. One minor thing in the code above, you need to init(key) before you can call doFinal()
final Charset charSet = Charset.forName("US-ASCII");
final Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
final SecretKeySpec secret_key = new javax.crypto.spec.SecretKeySpec(charSet.encode("key").array(), "HmacSHA256");
try {
sha256_HMAC.init(secret_key);
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
...
This is working fine for me
I have add dependency
compile 'commons-codec:commons-codec:1.9'
ref: http://mvnrepository.com/artifact/commons-codec/commons-codec/1.9
my function
public String encode(String key, String data) {
try {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256_HMAC.init(secret_key);
return Hex.encodeHexString(sha256_HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8)));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
Try this
Sorry for being late, I have tried all above answers but none of them is giving me correct value, After doing the lot of R&D I have found a simple way that gives me exact value.
Declare this method in your class
private String hmacSha(String KEY, String VALUE, String SHA_TYPE) {
try {
SecretKeySpec signingKey = new SecretKeySpec(KEY.getBytes("UTF-8"), SHA_TYPE);
Mac mac = Mac.getInstance(SHA_TYPE);
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(VALUE.getBytes("UTF-8"));
byte[] hexArray = {(byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f'};
byte[] hexChars = new byte[rawHmac.length * 2];
for ( int j = 0; j < rawHmac.length; j++ ) {
int v = rawHmac[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
Use this like
Log.e("TAG", "onCreate: "+hmacSha("key","text","HmacSHA256"));
Verification
1.Android studio output
2. Online HMAC generator Output(Visit here for Online Genrator)
Java simple code to generate encoded(HMAC-x) signatures. (Tried using Java-8 and Eclipse)
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import com.sun.org.apache.xml.internal.security.utils.Base64;
/**
* Encryption class to show how to generate encoded(HMAC-x) signatures.
*
*/
public class Encryption {
public static void main(String args[]) {
String message = "This is my message.";
String key = "your_key";
String algorithm = "HmacMD5"; // OPTIONS= HmacSHA512, HmacSHA256, HmacSHA1, HmacMD5
try {
// 1. Get an algorithm instance.
Mac sha256_hmac = Mac.getInstance(algorithm);
// 2. Create secret key.
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), algorithm);
// 3. Assign secret key algorithm.
sha256_hmac.init(secret_key);
// 4. Generate Base64 encoded cipher string.
String hash = Base64.encode(sha256_hmac.doFinal(message.getBytes("UTF-8")));
// You can use any other encoding format to get hash text in that encoding.
System.out.println(hash);
/**
* Here are the outputs for given algorithms:-
*
* HmacMD5 = hpytHW6XebJ/hNyJeX/A2w==
* HmacSHA1 = CZbtauhnzKs+UkBmdC1ssoEqdOw=
* HmacSHA256 =gCZJBUrp45o+Z5REzMwyJrdbRj8Rvfoy33ULZ1bySXM=
* HmacSHA512 = OAqi5yEbt2lkwDuFlO6/4UU6XmU2JEDuZn6+1pY4xLAq/JJGSNfSy1if499coG1K2Nqz/yyAMKPIx9C91uLj+w==
*/
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
}
}
NOTE: You can use any other Algorithms and can try generating HmacMD5, HmacSHA1, HmacSHA256, HmacSHA512 signatures.
If but any chance you found a solution how to calculate HMAC-SHA256 here, but you're getting an exception like this one:
java.lang.NoSuchMethodError: No static method
encodeHexString([B)Ljava/lang/String; in class
Lorg/apache/commons/codec/binary/Hex; or its super classes
(declaration of 'org.apache.commons.codec.binary.Hex' appears in
/system/framework/org.apache.http.legacy.boot.jar)
Then use:
public static String encode(String key, String data) {
try {
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
hmac.init(secret_key);
return new String(Hex.encodeHex(hmac.doFinal(data.getBytes("UTF-8"))));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Here is my solution:
public String HMAC_SHA256(String secret, String message)
{
String hash="";
try{
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
hash = Base64.encodeToString(sha256_HMAC.doFinal(message.getBytes()), Base64.DEFAULT);
}catch (Exception e)
{
}
return hash.trim();
}