Hi there, it seems hex2bytes is really not safe, but depending on the concrete number, it will throw an error. Workaround: using "0" * string(65537, base=16), but this looks really weird.

Can someone explain why such a basic function does not work as described in its own documentation?

julia> hex2bytes(string(65537, base=16))
ERROR: ArgumentError: length of iterable must be even
Stacktrace:
[1] hex2bytes!(dest::Vector{UInt8}, itr::Base.CodeUnits{UInt8, String})
@ Base ./strings/util.jl:847
[2] hex2bytes!
@ ./strings/util.jl:831 [inlined]
[3] hex2bytes(s::String)
@ Base ./strings/util.jl:825
[4] top-level scope
@ REPL[57]:1

I guess at least, the documentation should be updated, it currently reads like above

julia> s = string(12345, base = 16)
"3039"
julia> hex2bytes(s)
2-element Vector{UInt8}:
0x30
0x39

each successive pair of hexadecimal digits in itr gives the value of one byte in the return vector.

(emphasis added). i.e. it is documented on working on pairs of hexadecimal digits, since this is the canonical way to represent bytes as hex.

If you are trying to parse arbitrary hexadecimal numbers that arenâ€™t representations of byte sequences (i.e. which donâ€™t consist of paired hex digits), then youâ€™re doing something different from what hex2bytes was intended for. What is your application?

I agree that the example in the docs with string(n, base=16) is misleading, however.

Do you just want something like digits(UInt8, n, base=256) or perhaps num2bytes(n) = reinterpret(UInt8, [n])? Or if you just want particular bytes you can use shift and mod operations on n.

In general, I would avoid the intermediate step of converting the number to a string and then parsing the string.

thank you both,
everything is indeed clarified already - just the example in the documentation should get an update

my background: I am using JWTs to create authentication pipeline and there the exponent of the private key needs to be given in hex2bytes(int2hexstr(my_exponent)), because JWTs expects this

I am now running with

function int2hexstr(n)
str = string(n, base=16)
iseven(length(str)) ? str : "0" * str
end

Padding unknown (or heck, even known) incoming data in a cryptographic context â€śto make the algorithm workâ€ť is NOT a good idea. Generally, neither is implementing a seemingly simple padding operation - you can introduce subtle bugs that leave your code vulnerable.

If you donâ€™t mind me asking, but how are you generating the input in the first place? Going via regular Int64 or similar things seems much more of a hassle instead of directly generating an array of bytes to pass to e.g. openssl.

for JWTs keys need to be given under yourdomain/jwks in a json format which includes modulus and exponend base64 encoded with some extra url handling.

While there is an easy way to extract the modulus from a private key using openssl, I couldnâ€™t find anything like that for the exponent, hence I am just assuming the default exponent will be used.

So here the answer: I am indeed using plain Int64 value as the source for my exponent because this is the best readable so that I or others can later check that this is really the default exponent.

final comment from my side

(EDIT: for further tips and tricks please ping me per private message or open a new discourse thread, so that this one is not further stacked up)