doudu5029
doudu5029
2017-12-13 15:47
浏览 94
已采纳

Java与Golang for HOTP(RFC-4226)

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?

图片转代码服务由CSDN问答提供 功能建议

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

 公共静态字符串构造OTP(最终长计数器,最终字符串键)
引发NoSuchAlgorithmException,DecoderException,InvalidKeyException {
最终Mac mac = Mac.getInstance  (“ HmacSHA512”); 
 
最后一个字节[] binaryKey = Hex.decodeHex(key.toCharArray()); 
 
 mac.init(new SecretKeySpec(binaryKey,“ HmacSHA512”)); 
最后一个字节 [] b = ByteBuffer.allocate(8).putLong(counter).array(); 
 byte [] computeOtp = mac.doFinal(b); 
 
返回新的String(Hex.encodeHex(computedOtp));  
} 
   
 
 

并在Go中:

  func getOTP(counter uint64,key string)string {\  n 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)
返回base64.StdEncoding.EncodeToString(h.Sum(nil))
} 
   
 
 

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

在Java中,将生成以下字节数组: 83 -116 -9 -98 115 -126 -3 -48 和在Go中: 83140247158115 130 253 207

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

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • dsf6565
    dsf6565 2017-12-13 15:49
    已采纳

    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 
    
    点赞 评论

相关推荐