问题描述
我试图使用 ripemd160
模拟Java中的字符串来模拟以下php的输出:
$ string ='string';
$ key ='test';
hash_hmac('ripemd160',$ string,$ key);
//输出:37241f2513c60ae4d9b3b8d0d30517445f451fa5
尝试1
最初我试图用下面的方法来模拟它......但我不相信可以使用<$ c作为一个getInstance算法?
或者它可能并且我没有在本地启用它?
public String signRequest(String uri,String secret){
try {
byte [] keyBytes = secret.getBytes();
SecretKeySpec signingKey = new SecretKeySpec(keyBytes,HmacSHA1);
Mac mac = Mac.getInstance(ripemd160);
mac.init(signingKey);
//计算输入数据字节的hmac
byte [] rawHmac = mac.doFinal(uri.getBytes());
//将原始字节转换为十六进制
byte [] hexBytes = new Hex()。encode(rawHmac);
//向字符串隐藏十六进制字节数组
返回新字符串(hexBytes,UTF-8);
} catch(Exception e){
throw new RuntimeException(e);
}
}
尝试2 p>
这使我通过SO和Google寻找其他方式来完成上述任务,我发现查看BouncyCastle可能是更好的选择。
然后我发现这篇文章讨论了使用相同的算法进行哈希处理,还有BouncyCastle,它只是不使用关键字。 ( :
public static String signRequest(String uri,String secret)throws Exception {
byte [] r = uri。的getBytes( US-ASCII);
//这些密钥必须与哈希算法具有相同的块大小,在这种情况下,
// 64字节用右填充零。
byte [] k_outer = new byte [64];
System.arraycopy(secret.getBytes(US-ASCII),0,k_outer,0,
secret.getBytes(US-ASCII)。
byte [] k_inner = new byte [64];
System.arraycopy(secret.getBytes(US-ASCII),0,k_inner,0,
secret.getBytes(US-ASCII)。
//您将创建两个嵌套散列。内部的一个用
//关键字xor 0x36(字节方式)初始化,另一个用关键字xor 0x5c进行初始化。
for(int i = 0; i< k_outer.length; i ++)
k_outer [i] ^ = 0x5c;
for(int i = 0; i< k_inner.length; i ++)
k_inner [i] ^ = 0x36;
//用你想签名的密钥和数据更新内部散列
RIPEMD160Digest d_inner = new RIPEMD160Digest();
d_inner.update(k_inner,0,k_inner.length);
d_inner.update(r,0,r.length);
//使用键和内部哈希更新外部哈希
RIPEMD160Digest d_outer = new RIPEMD160Digest();
d_outer.update(k_outer,0,k_outer.length);
byte [] o_inner = new byte [d_inner.getDigestSize()];
d_inner.doFinal(o_inner,0);
d_outer.update(o_inner,0,o_inner.length);
//最后,返回十六进制编码的散列
byte [] o_outer = new byte [d_inner.getDigestSize()];
d_outer.doFinal(o_outer,0);
return new String((new Hex())。encode(o_outer),US-ASCII);
}
Bouncy Castle在 ,所以这个代码的一个简短变体是
pre $ public static String signRequest(String uri,String secret)throws Exception {
byte [] r = uri.getBytes(US-ASCII);
byte [] k = secret.getBytes(US-ASCII);
HMac hmac = new HMac(new RIPEMD160Digest());
hmac.init(new KeyParameter(k));
hmac.update(r,0,r.length);
byte [] out = new byte [hmac.getMacSize()];
hmac.doFinal(out,0);
return new String((new Hex())。encode(out),US-ASCII);
}
I'm trying to hash a String in Java using ripemd160
to emulate the output of the following php:
$string = 'string';
$key = 'test';
hash_hmac('ripemd160', $string, $key);
// outputs: 37241f2513c60ae4d9b3b8d0d30517445f451fa5
Attempt 1
Initially I'd tried to emulate it using the following... however I don't believe it's possible to use ripemd160
as a getInstance` algorithm?
Or maybe it is and I just don't have it locally enabled?
public String signRequest(String uri, String secret) {
try {
byte[] keyBytes = secret.getBytes();
SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA1");
Mac mac = Mac.getInstance("ripemd160");
mac.init(signingKey);
// Compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(uri.getBytes());
// Convert raw bytes to Hex
byte[] hexBytes = new Hex().encode(rawHmac);
// Covert array of Hex bytes to a String
return new String(hexBytes, "UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Attempt 2
This led me to look for other ways to accomplish the above, through SO and Google I found that looking at BouncyCastle may be a better way to go.
I then found this post that talks about hashing using the same algorithm as I'd like and also BouncyCastle, it just doesn't use a key. (Cannot output correct hash in Java. What is wrong?)
public static String toRIPEMD160(String in) {
try {
byte[] addr = in.getBytes();
byte[] out = new byte[20];
RIPEMD160Digest digest = new RIPEMD160Digest();
byte[] rawSha256 = sha256(addr);
String encodedSha256 = getHexString(rawSha256);
byte[] strBytes = base64Sha256.getBytes("UTF-8");
digest.update(strBytes, 0, strBytes.length);
digest.doFinal(out, 0);
return getHexString(out);
} catch (UnsupportedEncodingException ex) {
return null;
}
}
I have this working as it would be expected to.
Issue
You'll note that in attempt 2 there is currently no way to supply a key for the hashing, my question is how can I adapt this function to be able to supply a key and accomplish the last stage of what I need to do to be able to emulate the original php function: hash_hmac('ripemd160', $string, $key);
Using RIPEMD160 from Bouncy Castle is fine, but you'll have to implement HMAC, not just hash your data. HMac it just H(K XOR opad, H(K XOR ipad, text))
, where H
is your hash function, K
is the secret, text
the message and opad
and ipad
are predefined constants. To demonstrate how it works, I translated the following from Python's implementation:
public static String signRequest(String uri, String secret) throws Exception {
byte[] r = uri.getBytes("US-ASCII");
// The keys must have the same block size as your hashing algorithm, in this case
// 64 bytes right-padded with zeros.
byte[] k_outer = new byte[64];
System.arraycopy(secret.getBytes("US-ASCII"), 0, k_outer, 0,
secret.getBytes("US-ASCII").length);
byte[] k_inner = new byte[64];
System.arraycopy(secret.getBytes("US-ASCII"), 0, k_inner, 0,
secret.getBytes("US-ASCII").length);
// You'll create two nested hashes. The inner one is initialized with the
// key xor 0x36 (byte-wise), the other one with the key xor 0x5c.
for(int i=0; i<k_outer.length; i++)
k_outer[i] ^= 0x5c;
for(int i=0; i<k_inner.length; i++)
k_inner[i] ^= 0x36;
// Update inner hash with the key and data you want to sign
RIPEMD160Digest d_inner = new RIPEMD160Digest();
d_inner.update(k_inner, 0, k_inner.length);
d_inner.update(r, 0, r.length);
// Update outer hash with the key and the inner hash
RIPEMD160Digest d_outer = new RIPEMD160Digest();
d_outer.update(k_outer, 0, k_outer.length);
byte[] o_inner = new byte[d_inner.getDigestSize()];
d_inner.doFinal(o_inner, 0);
d_outer.update(o_inner, 0, o_inner.length);
// Finally, return the hex-encoded hash
byte[] o_outer = new byte[d_inner.getDigestSize()];
d_outer.doFinal(o_outer, 0);
return new String((new Hex()).encode(o_outer), "US-ASCII");
}
Bouncy Castle implements this algorithm in its HMac
class, so a shorter variant of this code is
public static String signRequest(String uri, String secret) throws Exception {
byte[] r = uri.getBytes("US-ASCII");
byte[] k = secret.getBytes("US-ASCII");
HMac hmac = new HMac(new RIPEMD160Digest());
hmac.init(new KeyParameter(k));
hmac.update(r, 0, r.length);
byte[] out = new byte[hmac.getMacSize()];
hmac.doFinal(out, 0);
return new String((new Hex()).encode(out), "US-ASCII");
}
这篇关于在Java中使用ripemd160和一个密钥来模拟PHP函数hash_hmac的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!