Java与Golang for HOTP(rfc-4226) [英] Java vs. Golang for HOTP (rfc-4226)

查看:186
本文介绍了Java与Golang for HOTP(rfc-4226)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在Golang中实现HOTP(rfc-4226),我正在努力生成有效的HOTP。我可以在java中生成它但由于某种原因我在Golang中的实现是不同的。以下是示例:

  public static String constructOTP(final Long counter,final String key)
throws NoSuchAlgorithmException,DecoderException ,InvalidKeyException {
final Mac mac = Mac.getInstance(HmacSHA512);

final byte [] binaryKey = Hex.decodeHex(key.toCharArray());

mac.init(new SecretKeySpec(binaryKey,HmacSHA512));
final byte [] b = ByteBuffer.allocate(8).putLong(counter).array();
byte [] computedOtp = mac.doFinal(b);

返回new String(Hex.encodeHex(computedOtp));
}

和Go:

  func getOTP(counter uint64,key string)string {
str,err:= hex.DecodeString(key)
if err!= nil {
panic(错误)
}
h:= hmac.New(sha512.New,str)
bs:= make([] byte,8)
binary.BigEndian。 PutUint64(bs,counter)
h.Write(bs)
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

我认为问题在于Java行: ByteBuffer.allocate(8).putLong(counter).array(); 生成一个与Go行不同的字节数组: binary.BigEndian.PutUint64(bs,counter)



在Java中,生成以下字节数组: 83 -116 -9 -98 115 -126 -3 -48 并且在Go中: 83 140 247 158 115 130 253 207



有没有人知道这两行的区别以及如何移植java行去?

解决方

Java中的字节类型已签名,其范围 -128..127 ,在Go byte 中的别名为 uint8 ,其范围为 0。 0.255 。因此,如果要比较结果,则必须将负Java值移动 256 (添加 256 )。 / p>

提示:要以无符号方式显示Java byte 值,请使用: byteValue& 0xff 使用字节的8位将其转换为 int 作为最低值8 int 中的位。或者更好:以十六进制形式显示两个结果,因此您不必关心签名...



将256添加到负Java字节值,输出几乎与Go相同:最后一个字节关闭1:

  javabytes := [] int {83,-116,-9,-98,115,-126,-3,-48} 
表示i,b:=范围javabytes {
如果b< 0 {
javabytes [i] + = 256
}
}
fmt.Println(javabytes)

输出为:

  [83 140 247 158 115 130 253 208] 

所以Java数组的最后一个字节是 208 当Go的 207 时。我猜你的计数器会在代码中的其他地方递增一次你还没有发布。



什么不同的是,在Java中,您返回十六进制编码结果,而在Go中,您返回Base64编码结果(它们是两种不同的编码,给出完全不同的结果)。如你所知,在Go返回 hex.EncodeToString(h.Sum(nil))结果匹配。



提示#2:要以签名方式显示Go的字节,只需将它们转换为 int8 (已签名),如下所示:

  gobytes:= [] byte {83,140,​​247,158,115,130,253,207} 
for _, b:=范围gobytes {
fmt.Print(int8(b),)
}

此输出:

  83 -116 -9 -98 115 -126 -3 -49 


I'm trying to implement HOTP (rfc-4226) in Golang and I'm struggling to generate a valid HOTP. I can generate it in java but for some reason my implementation in Golang is different. Here are the samples:

public static String constructOTP(final Long counter, final String key)
        throws NoSuchAlgorithmException, DecoderException, InvalidKeyException {
    final Mac mac = Mac.getInstance("HmacSHA512");

    final byte[] binaryKey = Hex.decodeHex(key.toCharArray());

    mac.init(new SecretKeySpec(binaryKey, "HmacSHA512"));
    final byte[] b = ByteBuffer.allocate(8).putLong(counter).array();
    byte[] computedOtp = mac.doFinal(b);

    return new String(Hex.encodeHex(computedOtp));
}

and in Go:

func getOTP(counter uint64, key string) string {
    str, err := hex.DecodeString(key)
    if err != nil {
        panic(err)
    }
    h := hmac.New(sha512.New, str)
    bs := make([]byte, 8)
    binary.BigEndian.PutUint64(bs, counter)
    h.Write(bs)
    return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

I believe the issue is that the Java line: ByteBuffer.allocate(8).putLong(counter).array(); generates a different byte array than the Go line: binary.BigEndian.PutUint64(bs, counter).

In Java, the following byte array is generated: 83 -116 -9 -98 115 -126 -3 -48 and in Go: 83 140 247 158 115 130 253 207.

Does anybody know the difference in the two lines and how I can port the java line to go?

解决方案

The byte type in Java is signed, it has a range of -128..127, while in Go byte is an alias of uint8 and has a range of 0..255. So if you want to compare the results, you have to shift negative Java values by 256 (add 256).

Tip: To display a Java byte value in an unsigned fashion, use: byteValue & 0xff which converts it to int using the 8 bits of the byte as the lowest 8 bits in the int. Or better: display both results in hex form so you don't have to care about sign-ness...

Adding 256 to your negative Java byte values, the output is almost identical to Go's: the last byte is off by 1:

javabytes := []int{83, -116, -9, -98, 115, -126, -3, -48}
for i, b := range javabytes {
    if b < 0 {
        javabytes[i] += 256
    }
}
fmt.Println(javabytes)

Output is:

[83 140 247 158 115 130 253 208]

So the last byte of your Java array is 208 while Go's is 207. I'm guessing your counter is incremented once somewhere else in your code which you haven't posted.

What differs is that in Java you return the hex encoded result while in Go you return the Base64 encoded result (they are 2 different encodings giving entirely different results). As you confirmed, in Go returning hex.EncodeToString(h.Sum(nil)) the results match.

Tip #2: To display Go's bytes in a signed fashion, simply convert them to int8 (which is signed) like this:

gobytes := []byte{83, 140, 247, 158, 115, 130, 253, 207}
for _, b := range gobytes {
    fmt.Print(int8(b), " ")
}

This outputs:

83 -116 -9 -98 115 -126 -3 -49 

这篇关于Java与Golang for HOTP(rfc-4226)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆