nextcloud / passman-webextension

Webextension for the Passman Nextcloud app. Also offers browser extension & Android app.
https://passman.cc
GNU Affero General Public License v3.0
115 stars 43 forks source link

No OTP for long secrets #334

Open rkilchmn opened 2 years ago

rkilchmn commented 2 years ago

More and more sites seem to have quite long secrets e.g. JREEWT1JJRFTGNCKLF7UMVJVJBETEQ2CIJGD6NKGGRLU6RJWJ54A

With such a secret no OTP is displayed

passman_longsecret_screenshot

Interestingly it works in the Nextcloud app and the Android Passman app

Thimoty44 commented 1 year ago

Same for me I can confirm

wilya7 commented 7 months ago

Workaround: the secret key must have a length divisible by 8. If necessary, add 'A' characters to the end of the key until it meets this requirement. This is because adding "A" (which decodes to zero in base32) does not alter the meaningful part of the secret but allows it to pass the length check

see https://github.com/nextcloud/passman/issues/293#issuecomment-362905855

EDIT: I just realized that my comment is completely wrong here. These long strings are > 64 bit, therefore the padding would not work. Also the string provided by @rkilchmn is divisible by 8. This is a completely different issue of passman.

olfek commented 3 weeks ago

@wilya7 ...

This is because adding "A" (which decodes to zero in base32) does not alter the meaningful part of the secret

So a secret with leading or trailing zero bits does not change the output TOTP code? Is this a feature of the TOTP algorithm? Where is it mentioned in the TOTP RFC?

wilya7 commented 3 weeks ago

@olfek This is how I understand the issue, but I am not an expert so take all this with a grain of salt.

The issue doesn't lie within the TOTP or HMAC algorithms themselves (*), but rather in the handling of the Base32-encoded key during the transition to the hexadecimal format required by HMAC. Base32 encoding, using 5-bit groups, can lead to incomplete byte representations when the key's length isn't a multiple of 8 bits. Padding with 'A's (representing 0 bits) ensures correct Base32 decoding, preventing truncated bytes that would disrupt the TOTP generation process.

For example, Amazon gives to passman a key 30 bit long encoded in base32. This key needs to be converted in binary and then in hex and fed to HMAC algorithm. While 30 bits form complete Base32 blocks (6 characters in Base32, as each character represents 5 bits), they don't translate to complete bytes when converted to hexadecimal. Therefore you pad the number with zeros to a 40 bit number, which is a multiple of 8 and gives a correct binary representation of the original number, although the numbers are different. While this padded representation results in a different hexadecimal string, it doesn't affect the HMAC calculation due to how HMAC handles the keys.

HMAC (**) uses a fixed block size (64 bytes for SHA-1, SHA-256, etc.), If the key is shorter than the block size, it's padded with zeros anyway. If the key is longer than the block size, it's hashed to create a shorter key. In this case, both the 30-bit and 40-bit keys are shorter than the block size, so they are both zero-padded to the full block size internally by the HMAC function leading to the same MAC values.

(*) the HMAC algorithm is used as a basis for many cryptographic protocols and applications, including TOTP (**) RFC2104

olfek commented 3 weeks ago

@wilya7 ...

After some experimentation, I can confirm the following -