passman icon indicating copy to clipboard operation
passman copied to clipboard

Unable to process TOTP

Open jkaberg opened this issue 7 years ago • 26 comments

Bug report

Passman is unable to process TOTP.

Steps to reproduce

  1. Insert TOTP into Passman

NN5VK226JVKVE3ZKJFEFESB7FR3CYRBSOESUELRGINVTM42SKZYA last ned

Expected behaviour

Passman outputs TOTP code

Actual behaviour

No code is generated

asds

In the Chrome console I can see

framework.js:14327 String of HEX type must be in byte increments
(anonymous)	@	framework.js:14327

Configuration

Operating system:

Browser:
Latest Chrome

Extensions that might cause interference: uBlock

Passman version: Latest

Operating system: Ubuntu Xenial

Web server: Nginx 1.12.1

Database: sqlite

PHP version: 7.1.3

cloud server: Nextcloud

cloud version: 11.0.2 (stable)


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

jkaberg avatar Apr 20 '17 16:04 jkaberg

I'd just like to mention that Google Authenticator handle's this just fine

jkaberg avatar Apr 20 '17 16:04 jkaberg

The reason that GAuth can read is that they use a different lib. We use the llqrcode lib for reading qrcodes. I think the lib has trouble reading your qr code.

brantje avatar Apr 20 '17 16:04 brantje

@brantje Sorry, my bad. Here you go: (same as above) image

jkaberg avatar Apr 20 '17 16:04 jkaberg

Note to self: this lib works https://github.com/LazarSoft/jsqrcode

brantje avatar Apr 20 '17 16:04 brantje

@brantje I just tested removing 2 last characters from the secret makes it present an OTP value again (incorrect but still). Perhaps the secret is to long for the decoder?

jkaberg avatar Apr 20 '17 16:04 jkaberg

The mouse cursor in the image messes up the reading of the qr code image

brantje avatar Apr 20 '17 16:04 brantje

@brantje The cursor is there because I screenshoted the QR code. The secret I'm talking about is present just above the QR code in orignal post which I'm 100% diden't have any cursor when I uploaded it to passman.

Just create an new credential and upload the QR below as OTP to Passman and you'll see what I mean.

last ned

jkaberg avatar Apr 20 '17 17:04 jkaberg

Hmmm both give different secrets. Think that will be solved once i switched the lib.

brantje avatar Apr 20 '17 17:04 brantje

I have the same issue with Amazon.de. The QR code is recognised by passman and resolved to the identical secret. Passman however does not show me the 6 digit key. As it was the first OTP I wanted to use I tried the GitHub.com QR code and everything works fine and as expected.

blacs30 avatar Aug 13 '17 14:08 blacs30

Now that I switched from Chromium to Firefox I have that problem too :( Any chance to get it resolved soon as it's really boring ? :/

vincegre avatar Nov 15 '17 14:11 vincegre

@vincegre so you say it depends on the browser?

blacs30 avatar Nov 15 '17 18:11 blacs30

I have the exact same problem. I uploaded the QR code from Amazon, which Passman resolved to the exact secret displayed on the Amazon website, but no secret is generated.

I tried inputing the secret by hand (or rather copy-pasting), and then a 6 digits secret is generated, but it doesn't validate on the Amazon website.

Freeben666 avatar Jan 23 '18 11:01 Freeben666

I'm experiencing the same issue. When I delete two characters from the end of the code, it appears to accept it visually (OTP is generated, timer starts counting down, etc.). It should be mentioned that the code from Amazon is 52 characters, and without the aforementioned two characters, is exactly 50 characters long. This seems like a hard limitation somewhere in Passman that is silently failing :thinking:

synthead avatar Jan 25 '18 06:01 synthead

I encountered the same bug and decided to dig deeper:

Turn out passman failes if the OTP secret in not exact a multiply of eight characters - as needed for base32 decoding the secret. Passman is not padding the hex key with zeros at the end as it (probably?) should.

With a 52 ascii secret - as used in the bug report here - the last character is only needed for the last bit of the last byte of the secret. Now the character itself is also used to encode the first four bits of a potential followup byte, which we don't have here. The passman code is still extracting those extra four bits, leading to an string which ends with half a byte at the end! While that extra nibble is zero and functional irrelevant, we now have a hex string with a odd length. That finally triggers a sanity check in sha.js, aborting the script execution with the "String of HEX type must be in byte increments" error message.

As a workaround we can just pad the secret manually: Just fill up the secret with "A" at the end till you reach the next multiply of eight characters in the secret.

The workaround secret for the sample above is therefore: NN5VK226JVKVE3ZKJFEFESB7FR3CYRBSOESUELRGINVTM42SKZYAAAAA This produced correct codes for me.

The correct fix seems to be to handle those "not a multiply of eight" character secrets correctly in passman. Here how I've implemented that for me:

--- passman-master/js/app/directives/otp.js     2018-02-04 02:27:24.000000000 +0100
+++ passman-mod/js/app/directives/otp.js        2018-02-04 14:53:48.360029328 +0100
@@ -53,10 +53,15 @@
                                                bits += leftpad(val.toString(2), 5, '0');
                                        }
 
+                                       for (i = i % 8; i > 0; i--) {
+                                               bits += leftpad('0', 5, '0');
+                                       }
+
                                        for (i = 0; i + 4 <= bits.length; i += 4) {
                                                var chunk = bits.substr(i, 4);
                                                hex = hex + parseInt(chunk, 2).toString(16);
                                        }
+
                                        return hex;
 
                                }

The same problem is also in the Firefox (and probably Chrome) Plugin. Without fixing it there also it will only work in the plugin if you used the workaround.

edit: fixed patch

alexw65500 avatar Feb 04 '18 13:02 alexw65500

@alexw65500 workaround is working here, so the patch should work too :)

Oliv4945 avatar Apr 24 '18 12:04 Oliv4945

@alexw65500 Can confirm! The workaround is working great for Amazon!

synthead avatar Jul 24 '18 20:07 synthead

I am also facing the same issue with Mastodon.

3mic y2hg uz5j 2p6s mnno elcn gpch n4sq -> This is the secret and Passman generates wrong OTP everytime, I tested it with another app and it worked.

Update: I just tested it after removing the space between those characters and it worked! 3micy2hguz5j2p6smnnoelcngpchn4sq -> This works with Passman

ghost avatar Aug 13 '18 15:08 ghost

This is an interesting topic. I presume passman is using the jssha lib. We have experienced the same problem with a 52 character long base 32 string. But when I apply this workaround the jssha fails for base 32 strings of length 103 or 26 which worked previously. A string of length 32 functions with and without the workaround because it is a modulus of 8 so that makes sense. But to catch the other cases I cannot see what is the distinction as neither a length of 52 or 103 or 26 are divisible by 8 yet the padding fails for the 103 and 26 (dropbox by the way). Any ideas?

gurnard123 avatar Oct 04 '18 12:10 gurnard123

@alexw65500 - have you submitted this as a PR?

This should get fixed as it's still a problem, and the workaround above is valid.

mainmachine avatar Aug 14 '19 17:08 mainmachine

@alexw65500 - have you submitted this as a PR?

No, the patch is super ugly and nothing I would merge as maintainer. That's basically the first time I used JS and it's just using the code around the problem for the fix with zero JS knowledge. So this is only a quick hack and it's not hard to do that better...

alexw65500 avatar Aug 28 '19 18:08 alexw65500

Just confirming that manually padding the value worked for me as well!

paulcalabro avatar Feb 10 '20 17:02 paulcalabro

I encountered the same bug and decided to dig deeper:

Turn out passman failes if the OTP secret in not exact a multiply of eight characters - as needed for base32 decoding the secret. Passman is not padding the hex key with zeros at the end as it (probably?) should.

With a 52 ascii secret - as used in the bug report here - the last character is only needed for the last bit of the last byte of the secret. Now the character itself is also used to encode the first four bits of a potential followup byte, which we don't have here. The passman code is still extracting those extra four bits, leading to an string which ends with half a byte at the end! While that extra nibble is zero and functional irrelevant, we now have a hex string with a odd length. That finally triggers a sanity check in sha.js, aborting the script execution with the "String of HEX type must be in byte increments" error message.

As a workaround we can just pad the secret manually: Just fill up the secret with "A" at the end till you reach the next multiply of eight characters in the secret.

The workaround secret for the sample above is therefore: NN5VK226JVKVE3ZKJFEFESB7FR3CYRBSOESUELRGINVTM42SKZYAAAAA This produced correct codes for me.

The correct fix seems to be to handle those "not a multiply of eight" character secrets correctly in passman. Here how I've implemented that for me:

--- passman-master/js/app/directives/otp.js     2018-02-04 02:27:24.000000000 +0100
+++ passman-mod/js/app/directives/otp.js        2018-02-04 14:53:48.360029328 +0100
@@ -53,10 +53,15 @@
                                                bits += leftpad(val.toString(2), 5, '0');
                                        }
 
+                                       for (i = i % 8; i > 0; i--) {
+                                               bits += leftpad('0', 5, '0');
+                                       }
+
                                        for (i = 0; i + 4 <= bits.length; i += 4) {
                                                var chunk = bits.substr(i, 4);
                                                hex = hex + parseInt(chunk, 2).toString(16);
                                        }
+
                                        return hex;
 
                                }

The same problem is also in the Firefox (and probably Chrome) Plugin. Without fixing it there also it will only work in the plugin if you used the workaround.

edit: fixed patch

Fixed: https://github.com/nextcloud/passman/pull/649

zandercodes avatar Mar 03 '20 13:03 zandercodes

The problem remains for me with Amazon (52 characters OTP code). I'm using Nextcloud 18.0.3 and Passman 2.3.5. The workaround mentioned above still solves the issue for now though (right padding with A). Has the official fix made it to production yet ? Is it released ? Thanks

p6ril avatar Apr 19 '20 21:04 p6ril

The problem remains for me with Amazon (52 characters OTP code). I'm using Nextcloud 18.0.3 and Passman 2.3.5. The workaround mentioned above still solves the issue for now though (right padding with A). Has the official fix made it to production yet ? Is it released ? Thanks

You should pass at an other tool, passman is unhappy a dead project since a while :(

vincegre avatar Apr 20 '20 06:04 vincegre

I encountered the same bug and decided to dig deeper:

Turn out passman failes if the OTP secret in not exact a multiply of eight characters - as needed for base32 decoding the secret. Passman is not padding the hex key with zeros at the end as it (probably?) should.

With a 52 ascii secret - as used in the bug report here - the last character is only needed for the last bit of the last byte of the secret. Now the character itself is also used to encode the first four bits of a potential followup byte, which we don't have here. The passman code is still extracting those extra four bits, leading to an string which ends with half a byte at the end! While that extra nibble is zero and functional irrelevant, we now have a hex string with a odd length. That finally triggers a sanity check in sha.js, aborting the script execution with the "String of HEX type must be in byte increments" error message.

As a workaround we can just pad the secret manually: Just fill up the secret with "A" at the end till you reach the next multiply of eight characters in the secret.

The workaround secret for the sample above is therefore: NN5VK226JVKVE3ZKJFEFESB7FR3CYRBSOESUELRGINVTM42SKZYAAAAA This produced correct codes for me.

The correct fix seems to be to handle those "not a multiply of eight" character secrets correctly in passman. Here how I've implemented that for me:

--- passman-master/js/app/directives/otp.js     2018-02-04 02:27:24.000000000 +0100
+++ passman-mod/js/app/directives/otp.js        2018-02-04 14:53:48.360029328 +0100
@@ -53,10 +53,15 @@
                                                bits += leftpad(val.toString(2), 5, '0');
                                        }
 
+                                       for (i = i % 8; i > 0; i--) {
+                                               bits += leftpad('0', 5, '0');
+                                       }
+
                                        for (i = 0; i + 4 <= bits.length; i += 4) {
                                                var chunk = bits.substr(i, 4);
                                                hex = hex + parseInt(chunk, 2).toString(16);
                                        }
+
                                        return hex;
 
                                }

The same problem is also in the Firefox (and probably Chrome) Plugin. Without fixing it there also it will only work in the plugin if you used the workaround.

edit: fixed patch

Really thanks. It works! Have a nice day.

nguyendptse62666 avatar Jun 20 '20 02:06 nguyendptse62666

Issue can be closed fix with #649

zandercodes avatar Nov 05 '20 08:11 zandercodes