我从http://tools.ietf.org/html/rfc6238借用了HMAC-
SHA1 Java代码,并稍加修改以对其进行硬编码,以使用一个具有已知输出的已知密钥/消息对。
然后,我尝试在Python中编写相同的代码以验证结果,但是在Python和Java中获得了不同的值。
已知Java值很好。
Java代码:
import java.lang.reflect.UndeclaredThrowableException;
import java.security.GeneralSecurityException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.util.TimeZone;
import java.util.Arrays;
public class make_hmac {
private make_hmac() {}
private static byte[] hmac_sha(String crypto, byte[] keyBytes,
byte[] text){
try {
System.out.println("Key is..." + bytesToHex(keyBytes) + "\n");
Mac hmac;
hmac = Mac.getInstance(crypto);
SecretKeySpec macKey =
new SecretKeySpec(keyBytes, "RAW");
hmac.init(macKey);
return hmac.doFinal(text);
} catch (GeneralSecurityException gse) {
throw new UndeclaredThrowableException(gse);
}
}
private static byte[] hexStr2Bytes(String hex){
// Adding one byte to get the right conversion
// Values starting with "0" can be converted
byte[] bArray = new BigInteger("10" + hex,16).toByteArray();
// Copy all the REAL bytes, not the "first"
byte[] ret = new byte[bArray.length - 1];
for (int i = 0; i < ret.length; i++)
ret[i] = bArray[i+1];
return ret;
}
private static final int[] DIGITS_POWER
// 0 1 2 3 4 5 6 7 8
= {1,10,100,1000,10000,100000,1000000,10000000,100000000 };
public static String generateTOTP(String key,
String time,
String returnDigits,
String crypto){
int codeDigits = Integer.decode(returnDigits).intValue();
String result = null;
// Using the counter
// First 8 bytes are for the movingFactor
// Compliant with base RFC 4226 (HOTP)
while (time.length() < 16 )
time = "0" + time;
// Get the HEX in a Byte[]
byte[] msg = hexStr2Bytes(time);
byte[] k = hexStr2Bytes(key);
byte[] hash = hmac_sha(crypto, k, msg);
System.out.println("I hashed key " + bytesToHex(k) + " against message " + bytesToHex(msg) + " and got...\n");
System.out.println("HASHED: " + bytesToHex(hash) + "\n");
// put selected bytes into result int
int offset = hash[hash.length - 1] & 0xf;
int binary =
((hash[offset] & 0x7f) << 24) |
((hash[offset + 1] & 0xff) << 16) |
((hash[offset + 2] & 0xff) << 8) |
(hash[offset + 3] & 0xff);
int otp = binary % DIGITS_POWER[codeDigits];
result = Integer.toString(otp);
while (result.length() < codeDigits) {
result = "0" + result;
}
return result;
}
public static String bytesToHex(byte[] bytes) {
final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[] hexChars = new char[bytes.length * 2];
int v;
for ( int j = 0; j < bytes.length; j++ ) {
v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
public static void main(String[] args) {
// Seed for HMAC-SHA1 - 20 bytes
String seed = "3132333435363738393031323334353637383930";
long T0 = 0;
long X = 30;
long testTime = 1111111109L;
String steps = "0";
long T = (testTime - T0)/X;
steps = Long.toHexString(T).toUpperCase();
while (steps.length() < 16) steps = "0" + steps;
System.out.println(generateTOTP(seed, steps, "8",
"HmacSHA1"));
}
}
Python代码:
import hmac
from hashlib import sha1
k = "3132333435363738393031323334353637383930"
msg = "00000000023523EC"
print "I hashed key", k, "against msg", msg, "and got...\n"
a = hmac.new(k, msg, sha1)
print a.digest().encode('hex')
运行Java的结果:
Key is...3132333435363738393031323334353637383930
I hashed key 3132333435363738393031323334353637383930 against message 00000000023523EC and got...
HASHED: 278C02E53610F84C40BD9135ACD4101012410A14
07081804
运行Python的结果:
I hashed key 3132333435363738393031323334353637383930 against msg 00000000023523EC and got...
fa9362e87c80a1ac61f705b5f9d5095adaec9525
“键”和“消息”相同,但是Java版本获得的HMAC与Python实现获得的HMAC不同。
我怀疑Python代码中的某个地方有一个微妙的错误(因为Java版本与RFC的预期结果匹配),但是我不确定在哪里。看起来很简单。
我认为问题是在Java中,您将原始字节用作键(仅将它们转换为十六进制字符串以进行输出):
System.out.println("Key is..." + bytesToHex(keyBytes) + "\n");
// ...
SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW");
但是在Python中,您使用的是十六进制字符串:
k = "3132333435363738393031323334353637383930"
看起来您可以使用以下方式解码十六进制字符串:
raw_key = k.decode('hex')
问题内容: 我从http://tools.ietf.org/html/rfc6238借用了HMAC- SHA1 Java代码,并稍加修改以对其进行硬编码,以使用一个具有已知输出的已知密钥/消息对。 然后,我尝试在Python中编写相同的代码以验证结果,但是在Python和Java中获得了不同的值。 Java值众所周知是好的。 Java代码: Python代码: 运行Java的结果: 运行Pytho
问题内容: 我有一个包含用户名和密码的SQL表。密码使用MessageDigest的digest()方法进行编码。如果我使用MessageDigest的digest()方法对密码进行编码(比如说“ abcdef12”),然后将其转换为十六进制值,则该字符串与使用PHP的SHA1-方法进行的编码不同。我希望这些值可以完全相同。 用于编码密码的代码: 使用以下方法将String转换为十六进制: 密码:
但是,我看到的每一个地方,似乎NodeJS代码都是100%正确的。所以我猜我的Java和Python代码中存在一个共同的缺陷。 任何洞察力将非常感谢。 下面是一些我看过的其他网页; 更新:使用更简单的字符串“asdfghjkl”而不是复杂的JSON字符串,生成相同的签名。因此,在比较Java/Python和NodeJS时,似乎有一些不可见的字符在改变摘要。
问题内容: 我有一个大问题。我使用此C#函数对消息进行编码: 在Java方面,我使用以下代码段: 我的消息是:阻止|注释|文本!£$%&/()=?^€> <{}ç°§;:_-。,@#ùàòè+ 我有这个结果: 你能帮我吗??谢谢… 问题答案: 我的猜测是您似乎正在将ASCII字节与Latin1字节进行比较。尝试切换 对此 那可能会解决您的问题。 (或切换C#以使用Latin1) 程序中发生的事情是
import "crypto/sha1" sha1包实现了SHA1哈希算法,参见RFC 3174。 Constants func Sum(data []byte) [Size]byte func New() hash.Hash Examples New Sum const BlockSize = 64 SHA1的块大小。 const Size = 20 SHA1校验和的字节数。 func Sum