HMAC-SHA1 Java kodunu http://tools.ietf.org/html/rfc6238'dan ödünç aldım ve bilinen çıkışlı bilinen bir anahtar/mesaj çiftini kullanmak için biraz kodlamaya adapte ettim.Python HMAC-SHA1 vs Java HMAC-SHA1 farklı sonuçlar
Daha sonra sonuçları doğrulamak için Python'da aynı kodu yazmaya çalıştım, ancak Python ve Java'da farklı değerler alıyorum.
Java değerlerinin iyi olduğu bilinir.
Java kodu:
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 kodu: çalışan Java
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')
Sonuçlar: Python çalışan
Key is...3132333435363738393031323334353637383930
I hashed key 3132333435363738393031323334353637383930 against message 00000000023523EC and got...
HASHED: 278C02E53610F84C40BD9135ACD4101012410A14
07081804
Sonuçlar:
I hashed key 3132333435363738393031323334353637383930 against msg 00000000023523EC and got...
fa9362e87c80a1ac61f705b5f9d5095adaec9525
"Anahtar" ve "ileti" aynıdır, ancak Java sürümü Python uygulamasının yaptığıdan farklı bir HMAC alır.
Python kodunun herhangi bir yerinde (Java sürümü RFC'den beklenen sonuçlarla eşleştiğinden) ince bir hata olduğundan şüpheleniyorum ancak emin değilim. Çok basit görünüyor.
System.out.println("Key is..." + bytesToHex(keyBytes) + "\n");
// ...
SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW");
Ama Python
, kullandığınız:
İyi catch. Düzeltme: a = hmac.new (k.decode ('hex'), msg.decode ('hex'), sha1) teşekkürler! – ashgromnies
Ayrıca bunu RFC - "" "de ekledim. Ek B. Test Vektörleri ||| Test belirteci paylaşılan sırrı, ASCII dize değeri" 123456789"kullanır. Zaman Adımı X = 30 ile ve Unix çağında başlangıç değeri olarak T0 = 0 olduğunda, TOTP algoritması belirtilen mod zaman damgaları için aşağıdaki değerleri gösterecektir. "" "Tablodaki" T (onaltılık) "değerinin" 00000000023523EC "olduğunu söylemeye devam eder. Bu yüzden farklı girişlerde biraz kafa karışıklığı olduğunu düşünüyorum. –