Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nitrocli-0.2.4 fails to parse some base32 OTP secrets #93

Closed
bircoph opened this issue Oct 11, 2019 · 4 comments
Closed

Nitrocli-0.2.4 fails to parse some base32 OTP secrets #93

bircoph opened this issue Oct 11, 2019 · 4 comments

Comments

@bircoph
Copy link

bircoph commented Oct 11, 2019

Hi there!

I found an base32 secret which nitrocli fails to parse (it is a test example based on an invalidated real one):

$ nitrocli otp set -f base32 5 test FBILDWWGA23ZG5NVMEWT57M7RXXDYXTC
Could not write OTP slot: The supplied string is not in hexadecimal format

Oathtool is happy with this secret:
$ oathtool --totp --base32 FBILDWWGA23ZG5NVMEWT57M7RXXDYXTC
753834

If I convert it to hex via a shell script nitrocli is happy as well:
$ nitrocli otp set 5 test $(echo -n FBILDWWGA23ZG5NVMEWT57M7RXXDYXTC | base32 -d | xxd -p)
and then nitrocli otp get 5 returns the same result as oathtool --totp -b within the same time slot.

Looks like base32 parser is somehow broken for some inputs (e.g. if I replace first F to A it works).

@d-e-s-o
Copy link
Owner

d-e-s-o commented Oct 12, 2019

Interesting. From a preliminary investigation it appears that we may be missing some padding bytes in the decoded string we ultimately produce. With the following patch your example input works:

--- nitrocli/src/commands.rs
+++ nitrocli/src/commands.rs
@@ -666,7 +666,7 @@ pub fn otp_set(
   with_device(ctx, |ctx, device| {
     let secret = match secret_format {
       args::OtpSecretFormat::Ascii => prepare_ascii_secret(&data.secret)?,
-      args::OtpSecretFormat::Base32 => prepare_base32_secret(&data.secret)?,
+      args::OtpSecretFormat::Base32 => "0".to_string() + &prepare_base32_secret(&data.secret)?,
       args::OtpSecretFormat::Hex => data.secret,
     };
     let data = nitrokey::OtpSlotData { secret, ..data };

Theoretically it should be as simple as prepending a '0' when the decoded secret has an uneven number of characters. Will dig some more tomorrow or when I have time.

@d-e-s-o
Copy link
Owner

d-e-s-o commented Oct 13, 2019

Okay, I traced that down more. The error is ultimately emitted by libnitrokey. The call stack should look like this:

  • Admin::write_totp_slot
  • nitrokey_sys::NK_write_totp_slot
  • NitrokeyManager::write_TOTP_slot
  • NitrokeyManager::write_OTP_slot_no_authorize
  • misc::hex_string_to_byte

This hex_string_to_byte function looks as follows:

::std::vector<uint8_t> hex_string_to_byte(const char* hexString){
    const size_t big_string_size = 257; //arbitrary 'big' number
    const size_t s_size = strnlen(hexString, big_string_size);
    const size_t d_size = s_size/2;
    if (s_size%2!=0 || s_size>=big_string_size){
        throw InvalidHexString(0);                    //  <------ what I suspect we hit
    }
    ...

So, any uneven number of characters is treated as "not a hexadecimal string".

In my opinion this is a deficiency in the implementation here. Why impose this unnecessary restriction to all clients when it is very well defined what, say, 0xa is equal to 0x0a? And of course, it's not documented anywhere.

@d-e-s-o
Copy link
Owner

d-e-s-o commented Oct 13, 2019

So the issue should be resolved in devel now. Can you please try it out?

It seems unlikely that I'll cut another release for this fix right now, though. I am still waiting for the nitrokey crate to be released as 0.4 as the plan was to get that out soon. However, the maintainer has gone dormant.

If you need that urgently and can't consume devel we can probably find a solution, though.

@d-e-s-o d-e-s-o closed this as completed Oct 13, 2019
@bircoph
Copy link
Author

bircoph commented Jan 4, 2020

Hi! I confirm that it works fine for me with nitrocli-0.3.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants