SHA-1 HMAC示例

时间:2016-09-17 19:41:51

标签: java cryptography sha1 hmac

我在大学的一个安全课上,我们现在正在研究哈希算法。我一直在寻找一个很好的解释HMAC如何从密钥和消息到哈希,但我找不到一个。维基页面和我去过的每个其他页面都非常模糊。他们说如果你有这个密钥和这个消息它变成了这个哈希,但没有解释它是如何到达那里的。我一直在https://en.wikipedia.org/wiki/Hash-based_message_authentication_code尝试使用java复制SHA-1哈希。

在Java中我正在使用:

byte[] bytes;
java.security.MessageDigest d = null;
d = java.security.MessageDigest.getInstance("SHA-1");
d.reset();
d.update(str.getBytes());
bytes = d.digest();
StringBuilder s = new StringBuilder();
for(byte b : bytes){
    s.append(Util.binToHex(Util.unsign(b)));
}
return s.toString();

Java处理有符号的位,所以
Util.unsign将其从有符号转换为无符号 Util.binToHex将字节转换为十六进制 我已经验证了这些,他们工作得很好 据我所知,我这样做的方式我必须给函数一个byte [],我总是从字符串类中获取,所以每当我进行sha-1哈希我将十六进制代码转换为字符串然后得到字节数组 示例:0x65 0x73将变为“es”。

Key: "key"
Message: "The quick brown fox jumps over the lazy dog"
BlockSize: 64
IPad: "0x36" repeated 64 times (3636363636...)
OPad: "0x5C" repeated 64 times (5C5C5C5C5C...)

我知道我说得对。接下来的一切都是让我的。

首先我将Key转换为hex KeyInHex = 0x6B 0x65 0x79
然后,因为KeyInHex比BlockSize字节短,所以我不必哈希它 我必须用0x00填充KeyInHex,直到它的大小为BlockSize KeyInHex = 0x6B 0x65 0x79 0x00 0x00 ...
我用IPad键入KeyInHex IKeyPad = 0x5D 0x53 0x4F 0x36 0x36 ...
接下来,我将消息附加到IKeyPad
BeforeFirstHash = 0x5D 0x53 0x4F 0x36 ... 0x36 + 0x54 0x68 0x65 ...
我将我的十六进制转换为字符串,然后获取字节数组并将其哈希 BeforeFirstHash = "]SO6...6The..."
FirstHash = 0x0E 0xFE 0x15 0xF9 0x16 0x1A 0xB7 ...
接下来我与OPad一起使用KeyInHex OKeyPad = 0x37 0x39 0x25 0x5C 0x5C ...
将FirstHash添加到OKeyPad中 BeforeSecondHash = 0x37 0x39 0x25 0x5C 0x5C ... 0x5C + 0x0E 0xFE 0x15 ...
转换为String,获取字节数组和散列
BeforeSecondHash = "79%\\...\(Shift out)~(carriage return)..."
SecondHash = 0x5D 0x8C 0xF2 0x45 0x8A ...
正确的哈希是0xDE 0x7C 0x9B 0x85 0xB8 ......这不是我得到的。

有人可以帮帮我吗?

修改

main(){
    int blockSize = 64;
    String key = "key";
    String message = "The quick brown fox jumps over the lazy dog";
    StringBuilder ipad = new StringBuilder();
    StringBuilder opad = new StringBuilder();
    StringBuilder prime = new StringBuilder();
    for(byte b : key.getBytes()){
        prime.append(Util.binToHex(Util.unsign(b)));
    }
    while(prime.length() < blockSize * 2){
        prime.append("00");
    }
    for(int i = 0; i < blockSize; ++i){
        opad.append("5c");
        ipad.append("36");
    }

    String iKeyPad = Util.xOr(prime.toString(), ipad.toString());
    String oKeyPad = Util.xOr(prime.toString(), opad.toString());

    String first = hash(Util.hexToString(iKeyPad) + message);
    String second = hash(Util.hexToString(oKeyPad + first));
    if(second.equals("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9")){
        System.out.println("Success");
    }
    else{
        System.out.println(second);
    }
}
private String hash(String str){
    try{
        byte[] bytes;
        java.security.MessageDigest d = null;
        d = java.security.MessageDigest.getInstance("SHA-1");
        d.reset();
        d.update(str.getBytes());
        bytes = d.digest();
        StringBuilder s = new StringBuilder();
        for(byte b : bytes){
            s.append(Util.binToHex(Util.unsign(b)));
        }
        return s.toString();
    }
    catch(Exception e){
        e.printStackTrace();
    }
    return null;
}
public static String xOr(String a, String b){
    a = hexToBin(a);
    b = hexToBin(b);
    StringBuilder str = new StringBuilder();
    for(int i = 0; i < a.length(); ++i){
        if(a.charAt(i) != b.charAt(i)){
            str.append("1");
        }
        else{
            str.append("0");
        }
    }
    return binToHex(str.toString());
}

public static String hexToString(String str){
    StringBuilder string = new StringBuilder();
    for(int i = 0; i < str.length(); i += 2){
        int number = Integer.valueOf(str.substring(i, i + 2), 16);
        string.append((char)number);
    }
    return string.toString();
}
public static String binToHex(String str){
    StringBuilder string = new StringBuilder();
    for(int i = 0; i < str.length(); i += 4){
        String temp = str.substring(i, i + 4);
        string.append(Integer.toString(Integer.valueOf(temp, 2), 16));
    }
    return string.toString();
}
public static String unsign(byte b){
    int x = b;
    if(x < 0){
        x = x * -1;
        String str = Integer.toString(x, 2);
        while(str.length() != 8){
            str = "0" + str;
        }
        str = inverse(str);
        str = addOne(str);
        return str;
    }
    else{
        String str = Integer.toString(x, 2);
        while(str.length() != 8){
            str = "0" + str;
        }
        return str;
    }
}

更新

感谢您的帮助,当我将其保留为byte []时,它可以工作。我仍然不完全确定原因,但我得到了正确答案。谢谢你的帮助!我真的很感激。

0 个答案:

没有答案