/ / Java vs. Golang per HOTP (rfc-4226) - java, go, crittografia, sha512

Java vs Golang per HOTP (rfc-4226) - java, go, crittografia, sha512

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 № 1

Il 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