Trying to generate Azure SAS token in order to be able to use Service Bus REST Api.
Found this link:
http://blog.simontimms.com/2015/01/30/sending-message-to-azure-service-bus-using-rest/
How to achieve the same on Android?
My Current attempt looks like this:
private String generateSasToken(String uri, String keyName, String key){
String ret = "";
long tokenExpirationTime = (System.currentTimeMillis() / 1000) + (10 * 365 * 24 * 60 * 60);
try {
String stringToSign = new URL(uri).toString() + "\n" + tokenExpirationTime;
SecretKey secretKey = null;
byte[] keyBytes = key.getBytes("UTF-8");
Mac mac = Mac.getInstance("HMACSHA256");
secretKey = new SecretKeySpec(keyBytes, mac.getAlgorithm());
mac.init(secretKey);
String signature = Base64.encodeToString(mac.doFinal(stringToSign.getBytes("UTF-8")), Base64.DEFAULT);
ret = String.format("SharedAccessSignature sr=%s&sig=%s&se=%s&skn=%s",
URLEncoder.encode(uri),
URLEncoder.encode(signature),
String.valueOf(tokenExpirationTime),
keyName);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return ret;
}
After calling the Rest API of service bus using Postman i get the following :
401 40103: Invalid authorization token signature
Time 261 ms
Update: Found this link
https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-android-get-started/
Under section 6 the code for android
I have no Android environment to test, I have a similar scenario in only java environment, it works fine, the following is my code:
private static String generateSasToken(String uri, String keyName, String key){
String ret = "";
// long tokenExpirationTime = (System.currentTimeMillis() / 1000) + (10 * 365 * 24 * 60 * 60);
Date now = new Date();
Date previousDate=new Date(1970);
long tokenExpirationTime = ((now.getTime() - previousDate.getTime()) / 1000 )+3600;
try {
String stringToSign = URLEncoder.encode(new URL(uri).toString(),java.nio.charset.StandardCharsets.UTF_8.toString()) + "\n" + tokenExpirationTime;
System.out.println(stringToSign);
SecretKey secretKey = null;
byte[] keyBytes = key.getBytes("UTF-8");
Mac mac = Mac.getInstance("HMACSHA256");
secretKey = new SecretKeySpec(keyBytes, mac.getAlgorithm());
mac.init(secretKey);
byte[] digest = mac.doFinal(stringToSign.getBytes());
//We then use the composite signing key to create an oauth_signature from the signature base string
String signature = Base64.encodeBase64String(digest);
System.out.println( URLEncoder.encode(signature, java.nio.charset.StandardCharsets.UTF_8.toString()));
// String signature = Base64.encodeBase64String(mac.doFinal(stringToSign.getBytes("UTF-8")));
ret = String.format("SharedAccessSignature sr=%s&sig=%s&se=%s&skn=%s",
URLEncoder.encode(uri, java.nio.charset.StandardCharsets.UTF_8.toString()),
URLEncoder.encode(signature, java.nio.charset.StandardCharsets.UTF_8.toString()),
String.valueOf(tokenExpirationTime),
keyName);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return ret;
}
I have changed two places, 1) the tokenExpirationTime 2) URLEncoder.encode the String stringTosign, please try with my suggestion, hope this could give you some tips.
I don't know if this helps you, but here is an example in C#:
class Program
{
static void Main(string[] args)
{
var sasToken = createToken("yournamespace.servicebus.windows.net”,
"device_send_listen", "xxxxxxx");
}
private static string createToken(string resourceUri, string keyName, string key)
{
TimeSpan sinceEpoch = DateTime.UtcNow - new DateTime(1970, 1, 1);
var expiry = Convert.ToString((int)sinceEpoch.TotalSeconds + 3600); //EXPIRES in 1h
string stringToSign = HttpUtility.UrlEncode(resourceUri) + "\n" + expiry;
HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
var sasToken = String.Format(CultureInfo.InvariantCulture,
"SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}",
HttpUtility.UrlEncode(resourceUri), HttpUtility.UrlEncode(signature), expiry, keyName);
return sasToken;
}
}
Related
I am trying to encrypt the password using the PBKDF2WithHmacSHA3-256. Based on the bouncycastle sample, I have the following sample
JAVA Code
The output from the Java code and Node JS seems to be different.
public static void main (String args[]) {
String saltVal = "a5dcea8d0bba2f1fcfa5824085bf06e65fa1255484dafd499984323672b71fee";
String passwordToHash = "password";
int iterations = 10000;
try {
PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator((new SHA3Digest(256)));
generator.init(passwordToHash.getBytes("UTF-8"),
saltVal.getBytes(),
iterations);
byte[] derivedKey = ((KeyParameter)generator.generateDerivedParameters(32 * 8)).getKey();
BigInteger bi = new BigInteger(1, derivedKey);
System.out.println(String.format("%0" + (derivedKey.length << 1) + "x", bi));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
Node JS
const crypto = require("crypto");
const iteration = 10000;
const length = 32;
const digest = "sha3-256";
const sharedSecret = "a5dcea8d0bba2f1fcfa5824085bf06e65fa1255484dafd499984323672b71fee";
const valuesToHash = ["password"];
const hashFn = (value, salt) => {
const saltBuf = Buffer.from(salt, "hex")
const key = crypto.pbkdf2Sync(value, saltBuf, iteration, length, digest);
return key.toString("hex");
}
for (const value of valuesToHash) {
console.log(`>>> ${value}: ${hashFn(value, sharedSecret)}`);
}
Thanks!
This is the updated code. The salt and iterations are defined outside.
private static String encodePassword (String password)
{
String returnVal = "";
try {
PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator((new SHA3Digest(256)));
generator.init(password.getBytes("UTF-8"),
Hex.decode(saltVal),
iterations);
byte[] derivedKey = ((KeyParameter)generator.generateDerivedParameters(32 * 8)).getKey();
returnVal = Hex.toHexString(derivedKey);
System.out.println(">>> " + password + " : " + returnVal);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return returnVal;
}
Hoping somebody can point me in the right direction here.
I'm not particularly familiar with encryption (in Java or otherwise), but I said that I'd help somebody out with a task they have that specifies using RSA encrypt/decrypt.
To familiarise myself with what is trying to be accomplished, I've put together a little example program that:
Generates 6 random numbers, and puts them in a comma-separated string
Encrypts the sequence of numbers
Appends the encrypted numbers sequence to a file - the same file can be written to more than once if the program is run multiple times
Reads the encrypted file - should get all sequences that have been written
Decrypt each sequence and print out a collection of comma-separated strings
This works fine on the first attempt - i.e. when the first sequence is written into an empty file - and the correct number sequence is returned.
When the file contains more than one encrypted sequence, this causes the decrypt routine to crash with a BadPaddingException. I've done a step-through at this point, and each of the byte[] (representing an encrypted sequence) to be decrypted is 128 bytes, so it's not like an irregular number of bytes is causing the problem.
I know that RSA isn't the recommended way to go about it anymore, but this is the specification that I'm having to get my head around.
I'm also aware that there's a ton of SO questions to do with RSA and BadPaddingException, but I haven't come across one that deals with this issue.
My example code is below:
public class EncryptDecrypt {
private static Cipher cipher;
private static KeyPair keyPair;
public static void main(String[] args)
{
String[] numbers = getNumbers();
String numbersStr = String.join(", ", numbers);
System.out.println("Generated: " + numbersStr + ", NumBytes: " + numbersStr.getBytes().length);
byte[] encryptedNumbers = encrypt(numbersStr);
System.out.println("Encrypted: " + encryptedNumbers.toString() + ", NumBytes: " + encryptedNumbers.length);
writeToFile(encryptedNumbers);
System.out.println("Encrypted numbers written to data.txt");
ArrayList<byte[]> encryptedData = readFromFile();
System.out.println("Encrypted numbers read from data.txt, NumSequences: " + encryptedData.size());
ArrayList<String> decryptedSequences = decrypt(encryptedData);
for (int i = 0; i < decryptedSequences.size(); i++)
{
String sequence = decryptedSequences.get(i);
System.out.println("Sequence " + i + ": " + sequence);
}
}
private static String[] getNumbers()
{
String[] numbers = new String[6];
int min = 1;
int max = 60;
for (int i = 0; i < numbers.length; i++)
{
double number = (Math.random() * (max - min) + min);
numbers[i] = number >= 10 ? Integer.toString((int) number) : "0" + Integer.toString((int) number);
}
return numbers;
}
private static byte[] encrypt(String data)
{
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
cipher.update(data.getBytes());
byte[] encrypted = cipher.doFinal();
return encrypted;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex) {
Logger.getLogger(EncryptDecrypt.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
private static void writeToFile(byte[] data)
{
FileOutputStream fileOut = null;
try {
File file = new File("data.txt");
file.createNewFile();
fileOut = new FileOutputStream(file, true);
fileOut.write(data);
fileOut.flush();
fileOut.close();
} catch (FileNotFoundException ex) {
Logger.getLogger(EncryptDecrypt.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(EncryptDecrypt.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
fileOut.close();
} catch (IOException ex) {
Logger.getLogger(EncryptDecrypt.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
private static ArrayList<byte[]> readFromFile()
{
File file = new File("data.txt");
if (file.exists())
{
try {
ArrayList<byte[]> encryptedSequences = new ArrayList<>();
FileInputStream fileIn = new FileInputStream(file);
int blockSize = 128;
int numBlocks = fileIn.available() / blockSize;
for (int i = 0; i < numBlocks; i++)
{
byte[] encryptedSequence = new byte[blockSize];
fileIn.read(encryptedSequence);
encryptedSequences.add(encryptedSequence);
}
fileIn.close();
return encryptedSequences;
} catch (FileNotFoundException ex) {
Logger.getLogger(EncryptDecrypt.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(EncryptDecrypt.class.getName()).log(Level.SEVERE, null, ex);
}
}
return null;
}
private static ArrayList<String> decrypt(ArrayList<byte[]> data)
{
try {
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
PrivateKey privateKey = keyPair.getPrivate();
cipher.init(Cipher.DECRYPT_MODE, privateKey);
ArrayList<String> decryptedStrings = new ArrayList<>();
for (byte[] sequence : data)
{
byte[] decryptedBytes = cipher.doFinal(sequence);
String decryptedString = new String(decryptedBytes);
decryptedStrings.add(decryptedString);
}
return decryptedStrings;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException ex) {
Logger.getLogger(EncryptDecrypt.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}
If anyone can spot what's wrong with this, I'd really appreciate it!
Thanks
I have my c# server and my java client, their communication is encrypted but when the client sends an encrypted query, the server cant decrypt it, well it can but its totally unreadable, its like converting a byte array to a string, totally unreadable, this is the encryption on the clients side:
public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException
{
byte[] encryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
final Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5PADDING);
final byte[] keyData = Arrays.copyOf(passwordBytes, KEY_SIZE
/ Byte.SIZE);
final byte[] ivBytes = Arrays.copyOf(keyData, cipher.getBlockSize());
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyData, "AES"),
new IvParameterSpec(ivBytes));
encryptedBytes = cipher.doFinal(bytesToBeEncrypted);
return encryptedBytes;
}
And the decryption on the server side:
internal string DecryptText(string inputString, Key k)
{
try
{
inputString = inputString.Replace("\0", "");
byte[] decryptedBytes = null;
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
byte[] bytesToBeDecrypted = Convert.FromBase64String(inputString);
byte[] passwordBytes = Encoding.UTF8.GetBytes("azaz");
passwordBytes = SHA256.Create().ComputeHash(passwordBytes);
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Padding = PaddingMode.None;
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
cs.Close();
}
decryptedBytes = ms.ToArray();
}
}
return Encoding.UTF8.GetString(decryptedBytes);
}
catch (Exception ex)
{
throw new SystemException(ex.Message);
}
}
Thanks in advance
EDIT On the java client, this function call the AES_Encrypt function:
public String EncryptText(String input) throws NoSuchAlgorithmException
{
byte[] bytesToBeEncrypted = input.getBytes();
byte[] passwordBytes = Config.ServerKey.getBytes();
MessageDigest md = MessageDigest.getInstance("SHA-256");
passwordBytes = md.digest(passwordBytes);
byte[] bytesEncrypted = null;
try {
bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);
} catch (NoSuchPaddingException ex) {
Logger.getLogger(CryptoClass.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidAlgorithmParameterException ex) {
Logger.getLogger(CryptoClass.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidKeyException ex) {
Logger.getLogger(CryptoClass.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalBlockSizeException ex) {
Logger.getLogger(CryptoClass.class.getName()).log(Level.SEVERE, null, ex);
} catch (BadPaddingException ex) {
Logger.getLogger(CryptoClass.class.getName()).log(Level.SEVERE, null, ex);
}
return Base64.getEncoder().encodeToString(bytesEncrypted);
}
EDIT Implemented basic SslStream and verification server side
private void Do()
{
int requestCount = 0;
string serverResponse = null;
string rCount = null;
string dataFromClient = null;
Byte[] sendBytes = null;
requestCount = 0;
Responder.Responder R = new Responder.Responder();
while ((true))
{
try
{
byte[] buffer = new byte[4];
requestCount = requestCount + 1;
bool leaveInnerStreamOpen = true;
RemoteCertificateValidationCallback validationCallback =
new RemoteCertificateValidationCallback(ClientValidationCallback);
LocalCertificateSelectionCallback selectionCallback =
new LocalCertificateSelectionCallback(ServerCertificateSelectionCallback);
EncryptionPolicy encryptionPolicy = EncryptionPolicy.AllowNoEncryption;
_sslStream = new SslStream(clientSocket.GetStream(),
leaveInnerStreamOpen, validationCallback, selectionCallback, encryptionPolicy);
X509Certificate2 certificate = ServerCertificate.Servercertificate(); //method that has access to the embedded certificate
bool requireClientCertificate = true;
SslProtocols enabledSslProtocols = SslProtocols.Tls11 | SslProtocols.Tls12;
bool checkCertificateRevocation = true;
_sslStream.AuthenticateAsServer
(certificate, requireClientCertificate, enabledSslProtocols, checkCertificateRevocation);
buffer = new byte[4];
int readBytes = _sslStream.Read(buffer, 0, 4);
if (readBytes == 0)
break;
int MessageSize = BitConverter.ToInt32(buffer, 0);
byte[] bufferreader = new byte[MessageSize];
clientSocket.ReceiveBufferSize = MessageSize;
readBytes = _sslStream.Read(bufferreader, 0, MessageSize);
Console.WriteLine(Convert.ToString(MessageSize));
rCount = Convert.ToString(requestCount);
dataFromClient = Encoding.ASCII.GetString(bufferreader);
byte[] outbuffer = new byte[4];
serverResponse = R.Respond(dataFromClient, K, clientSocket);
sendBytes = Encoding.ASCII.GetBytes(serverResponse);
outbuffer = new byte[4];
outbuffer = BitConverter.GetBytes(sendBytes.Length);
_sslStream.Write(outbuffer, 0, 4);
_sslStream.Flush();
clientSocket.SendBufferSize = sendBytes.Length;
MessageBox.Show(serverResponse);
_sslStream.Write(sendBytes, 0, sendBytes.Length);
_sslStream.Flush();
}
catch (Exception ex)
{
EndPointHandler.RemoveEndPoint(clientSocket);
clientSocket.Close();
Console.WriteLine("User Server >> " + ex.ToString());
Thread.CurrentThread.Abort();
}
}
EndPointHandler.RemoveEndPoint(clientSocket);
Console.WriteLine("User Server >> " + "Client No:" + Convert.ToString(clNo) + " Stopped!");
}
private bool ClientValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
switch (sslPolicyErrors)
{
case SslPolicyErrors.RemoteCertificateNameMismatch:
Console.WriteLine("Client's name mismatch. End communication ...\n");
return false;
case SslPolicyErrors.RemoteCertificateNotAvailable:
Console.WriteLine("Client's certificate not available. End communication ...\n");
return false;
case SslPolicyErrors.RemoteCertificateChainErrors:
Console.WriteLine("Client's certificate validation failed. End communication ...\n");
return false;
}
Console.WriteLine("Client's authentication succeeded ...\n");
return true;
}
private X509Certificate ServerCertificateSelectionCallback(object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers)
{
return ServerCertificate.Servercertificate();
}
In your Java code you have:
final Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5PADDING);
Which likely means you are using PKCS5/7 Padding, unless you are just really terrible at picking names for your constants.
However, in your C# code, you have:
AES.Padding = PaddingMode.None;
Which is clearly not PKCS5/7 Padding... So you should probably change that to PaddingMode.PKCS7.
EDIT: Please also don't disregard my comment about your IV. If you want your code to actually be worth using, you should automatically generate the IV for each encryption and prepend it to the ciphertext.
Also just noticed that you derive your key data in different ways. You are using PBKDF2 w/ SHA1 in C# (Rfc2898DeriveBytes) but using a single iteration of SHA256 in Java. You'll need to pick one or another.
This question already has an answer here:
Better way to create AES keys than seeding SecureRandom
(1 answer)
Closed 6 years ago.
I just finished an AES Class for decrypt or encrpyt ,and it runs well on windows but can't run on linux throwing errors as following :
Given final block not properly padded
the full code as following :
/**
* AESTest.java
*
* #author liuyincan
* #Time 2013-12-12 下午1:25:44
*/
public class AES {
public static String generateKey(int len) {
try {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(len);
Key key = keyGen.generateKey();
return ParserStringUtils.toHexString(key.getEncoded());
} catch (Exception e) {
return null;
}
}
/**
* 加密
*
* #param content
* 待加密内容
* #param key
* 加密的密钥
* #return
*/
public static String encode(String content, String key) {
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(key.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] byteRresult = cipher.doFinal(byteContent);
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteRresult.length; i++) {
String hex = Integer.toHexString(byteRresult[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
/**
* 解密
*
* #param content
* 待解密内容
* #param key
* 解密的密钥
* #return
*/
public static String decode(String content, String key) {
if (content.length() < 1)
return null;
byte[] byteRresult = new byte[content.length() / 2];
for (int i = 0; i < content.length() / 2; i++) {
int high = Integer.parseInt(content.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(content.substring(i * 2 + 1, i * 2 + 2), 16);
byteRresult[i] = (byte) (high * 16 + low);
}
try {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(key.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] result = cipher.doFinal(byteRresult);
return new String(result);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return null;
}
please help me to fix the problem or else my boss will fire me ,thanks a lot
Cipher.getInstance("AES"); - this gives the default implementation of AES.
Somewhere between Oracle Java 6 and late Java 7 this changed form AES/ECB/NoPadding to AES/ECB/PKCS5Padding.
Change such lines to:
Cipher.getInstance("AES/ECB/PKCS5Padding");
I'm trying to convert this hashing function to Ruby from Java.
Java code:
Mac localMac = "HMAC-SHA256";
String str1 = "a4d1b77bbb1a4a5ca695ad72c84b77e5";
localMac.init(new SecretKeySpec(str1.getBytes("UTF-8"), localMac.getAlgorithm()));
byte[] arrayOfByte = localMac.doFinal("{"_uid":"3396112","_csrftoken":"a23482932482sdsf4428","media_id":"616150302791211280_187036957"}");
BigInteger localBigInteger = new BigInteger(1, arrayOfByte);
String str3 = String.format("%0" + (arrayOfByte.length << 1) + "x", new Object[] { localBigInteger });
return str3;
Ruby code:
require 'openssl'
require 'base64'
secret = "a4d1b77bbb1a4a5ca695ad72c84b77e5"
digest = OpenSSL::Digest::Digest.new('sha256')
hash = OpenSSL::HMAC.hexdigest(digest, secret,'{"_uid":"3396112","_csrftoken":"a23482932482sdsf4428","media_id":"616150302791211280_187036957"}')
p hash
For some reason the hashes are never the same. Any help?
You can do it like this
public static void main(String[] args) {
String str1 = "a4d1b77bbb1a4a5ca695ad72c84b77e5";
byte[] keyBytes = str1.getBytes();
SecretKeySpec localMac = new SecretKeySpec(
keyBytes, "HmacSHA256");
final String inputStr = "{\"_uid\":\"3396112\",\"_csrftoken\":"
+ "\"a23482932482sdsf4428\","
+ "\"media_id\":\"616150302791211280_187036957\"}";
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(localMac);
// Compute the hmac on input data bytes
byte[] arrayOfByte = mac.doFinal(inputStr
.getBytes());
BigInteger localBigInteger = new BigInteger(1,
arrayOfByte);
String str3 = String.format("%0"
+ (arrayOfByte.length << 1) + "x",
new Object[] { localBigInteger });
System.out.println(str3);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
Which will output e48d690dc6825e8f2895845be112fb1e5ee22f5283f2243512d6cca2714e8b35.
$ cat test.rb
#!/usr/bin/env ruby
require 'openssl'
require 'base64'
secret = "a4d1b77bbb1a4a5ca695ad72c84b77e5"
digest = OpenSSL::Digest::Digest.new('sha256')
hash = OpenSSL::HMAC.hexdigest(digest, secret,'{"_uid":"3396112","_csrftoken":"a23482932482sdsf4428","media_id":"616150302791211280_187036957 "}')
p hash
$ ./test.rb
"e48d690dc6825e8f2895845be112fb1e5ee22f5283f2243512d6cca2714e8b35"