As we can see from the following questions:
Java vs. Golang for HOTP (rfc-4226)
, Java doesn't really play nicely when using a key in a TOTP / HOTP / HmacSHA256 use case. My analysis is that the following cause trouble:
String.getBytes
will (of course) give negative byte values for characters with a character value > 127;javax.crypto.Mac
andjavax.crypto.spec.SecretKeySpec
both externally and internally usebyte[]
for accepting and transforming the key.
We have acquired a number of Feitian C-200 Single Button OTP devices, and they come with a hexadecimal string secret which consist of byte values > 127.
We have successfully created a PoC in Ruby for these tokens, which works flawlessly. Since we want to integrate these in Keycloak, we need to find a Java solution.
Since every implementation of TOTP / HOTP / HmacSHA256 we have seen makes use the javax.crypto
library and byte[]
, we fear we have to rewrite all the used classes but using int
in order to support this scenario.
Q: Is there another way? How can we use secrets in a HmacSHA256 calculation in Java of which the bytes have values > 127 without having to rewrite everything?
Update
I was looking in the wrong direction. My problem was that the key was represented a String (UTF-16 in Java), which contained Unicode characters that were exploded into two bytes by getBytes()
, before being passed into the SecretKeySpec
.
Forcing StandardCharsets.ISO_8859_1
on this conversion fixes the problem.