Sto cercando di implementare HOTP (rfc-4226) a Golange sto lottando per generare un HOTP valido. Posso generarlo in Java ma per qualche ragione la mia implementazione in Golang è diversa. Ecco gli esempi:
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));
}
e 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))
}
Credo che il problema sia che la linea Java: ByteBuffer.allocate(8).putLong(counter).array();
genera un array di byte diverso rispetto alla linea Go: binary.BigEndian.PutUint64(bs, counter)
.
In Java, viene generato il seguente array di byte: 83 -116 -9 -98 115 -126 -3 -48
e in Go: 83 140 247 158 115 130 253 207
.
Qualcuno sa la differenza tra le due linee e come posso portare la linea Java per andare?
risposte:
10 per risposta № 1Il byte
digitare in Java è firmato, ha un intervallo di -128..127
, mentre sei in viaggio byte
è un alias di uint8
e ha una gamma di 0..255
. Quindi, se si desidera confrontare i risultati, è necessario spostare i valori Java negativi di 256
(Inserisci 256
).
Suggerimento: per visualizzare un Java byte
valore in modo non firmato, utilizzare: byteValue & 0xff
che lo converte in int
usando gli 8 bit di byte
come gli 8 bit più bassi in int
. O meglio: visualizza entrambi i risultati in forma esadecimale in modo da non doverti preoccupare della significatività ...
Aggiungendo 256 ai valori di byte Java negativi, l'output è quasi identico a Go "s: l'ultimo byte è spento da 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)
L'output è:
[83 140 247 158 115 130 253 208]
Quindi l'ultimo byte dell'array Java è 208
mentre Go "s è 207
. Sto indovinando il tuo counter
viene incrementato una volta altrove nel codice che non è stato pubblicato.
Ciò che differisce è che in Java si restituisce l'esagonorisultato codificato mentre in Go si restituisce il risultato codificato Base64 (sono 2 codifiche diverse che danno risultati completamente diversi). Come hai confermato, in Vai a tornare hex.EncodeToString(h.Sum(nil))
i risultati corrispondono.
Suggerimento n. 2: per visualizzare i byte di Go in modo firmato, è sufficiente convertirli in int8
(che è firmato) in questo modo:
gobytes := []byte{83, 140, 247, 158, 115, 130, 253, 207}
for _, b := range gobytes {
fmt.Print(int8(b), " ")
}
Questo produce:
83 -116 -9 -98 115 -126 -3 -49