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

Sharing credentials between phone client & pwdsphinx client doesn't work for me #8

Closed
rolfschr opened this issue Mar 24, 2021 · 20 comments

Comments

@rolfschr
Copy link
Contributor

rolfschr commented Mar 24, 2021

Hi,

I managed to compile & run the software on my phone.

I also setup an oracle server (from https://github.com/stef/pwdsphinx). The pwdsphinx server works fine on my local machine (i.e. I can run the oracle process and access it using the python sphinx.py client). I have used these commands here stef/pwdsphinx#9 to generate the ssl certificate.

Here's a picture of pwdshinx working fine locally:

server+client

(The ip address provided in the config is the one of my development maschine. The logged request on the left comes from the client on the right.)

Here's a picture of androsphinx using my phone:
Screenshot_20210324-1200292

Here is my actual problem. Below you'll see two requests. The first is from my phone and it works just fine. Requesting the same site/user information using the local client doesn't work (2nd request on the left, 'fail' on the right). I was expecting to be able to fetch from one client what the other client had sent to the server before.

server+client_from_phone_doesnt_work

Requesting a different user/site combination from the pwdsphinx client yields an exception, so the user/site params are correct. I just don't get the password back. I verified the master password. I guess I am doing something wrong but I don't know what...

@dnet
Copy link
Owner

dnet commented Mar 24, 2021

You used echo but without the -n parameter, it puts a newline (ASCII 0x0A) at the end, which results in a different master password ("m" vs. "m\n"). Try it with -n like echo -n "m" | ...

@rolfschr
Copy link
Contributor Author

Ah, thanks for the quick hint. Unfortunately, this doesn't seem to fix my issue. printf doesn't work neither.

By the way, the other way around doesn't work neither: I can add user/site from the cli and cannot access it from the android app ("a server error occurred"). The app doesn't show me the created accounts. Also, from the cli, I cannot add accounts to the same site ("site") I used in the android app.

# creating a new entry works fine. I cannot find "cli.com" in the app, though.
$ printf 'm' | ../result/bin/sphinx create username cli.com ulsd 5
&!_] 
$ printf 'm' | ../result/bin/sphinx get username cli.com
&!_] 

# "user" and "site" has been created using androsphinx but I'm unable to access it using the cli
$ printf 'm' | ../result/bin/sphinx get user site
fail

# Trying to access something else.
$ printf 'm' | ../result/bin/sphinx get user doesnt-exists
Traceback (most recent call last):
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/bin/.sphinx-wrapped", line 9, in <module>
    sys.exit(main())
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/lib/python3.8/site-packages/pwdsphinx/sphinx.py", line 424, in main
    ret = cmd(s, pwd, *args)
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/lib/python3.8/site-packages/pwdsphinx/sphinx.py", line 296, in get
    return doSphinx(s, GET, pwd, user, host)
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/lib/python3.8/site-packages/pwdsphinx/sphinx.py", line 151, in doSphinx
    raise ValueError("error: sphinx protocol failure.")
ValueError: error: sphinx protocol failure.

# "user" and "site" has been created using androsphinx 
$ printf 'm' | ../result/bin/sphinx create otheruser site ulsd 5                                                                                                                                                   
Traceback (most recent call last):
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/bin/.sphinx-wrapped", line 9, in <module>
    sys.exit(main())
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/lib/python3.8/site-packages/pwdsphinx/sphinx.py", line 424, in main
    ret = cmd(s, pwd, *args)
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/lib/python3.8/site-packages/pwdsphinx/sphinx.py", line 289, in create
    update_rec(s, host, user)
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/lib/python3.8/site-packages/pwdsphinx/sphinx.py", line 206, in update_rec
    blob = decrypt_blob(blob, b'')
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/lib/python3.8/site-packages/pwdsphinx/sphinx.py", line 108, in decrypt_blob
    res = pysodium.crypto_secretbox_open(blob,nonce,sk)
  File "/nix/store/hz51jzsgk9is4k2m9pm7h5bppm5a0vmy-python3.8-pysodium-0.7.5/lib/python3.8/site-packages/pysodium/__init__.py", line 640, in crypto_secretbox_open
    __check(sodium.crypto_secretbox_open(msg, padded, ctypes.c_ulonglong(len(padded)), nonce, k))
  File "/nix/store/hz51jzsgk9is4k2m9pm7h5bppm5a0vmy-python3.8-pysodium-0.7.5/lib/python3.8/site-packages/pysodium/__init__.py", line 267, in __check
    raise ValueError
ValueError

@dnet
Copy link
Owner

dnet commented Mar 24, 2021

Which versions (release version or commit hash) of pwdsphinx and Androsphinx are you using? Also, take a look at the conformance test suite (see README) which runs tests exactly like these, maybe that could help you debug on your side.

@rolfschr
Copy link
Contributor Author

Hi,

I'm using pwdsphinx b0518878dc31f27d555becb9e5ed8056564da11d and androsphinx 0bf34e1. I only compiled the app using gradle (i.e. without even accessing any GUI like Android Studio). I will have to check whether I can reproduce the issue with the test suite.

@stef
Copy link

stef commented Mar 24, 2021

ok. did you somehow copy over from host/phone the masterkey to the other device? if not that explains it. and there is an untagged version of pwdsphinx which allows to export the masterkey using a qrcode that can be conveniently read in by androsphinx.

@rolfschr
Copy link
Contributor Author

HI @stef ,

thanks for commenting here, too. I have a development machine and a phone. I run the pwdsphinx oracle process and the pwdsphinx client process (sphinx.py) on the development machine. The master key is also on that machine. I used the qr code instructions

(printf '\x01' ; cat ~/.sphinx/masterkey ;
	printf '\x09\x33%s' "my.local.ip.address") | qrencode -8 -t ANSI256

to generate the QR code. I used the barcode scanner on the phone to read that code. I did not copy any file to the phone.

@dnet
Copy link
Owner

dnet commented Mar 24, 2021

I used the qr code instructions

that should be fine, thanks for confirming that you indeed probably have the same keys on both devices (PC and phone)

@stef
Copy link

stef commented Mar 24, 2021

aah. great. thanks. let's dig deeper then.

@stef
Copy link

stef commented Mar 24, 2021

would you also be able to tell us which git revision of libsphinx you use on your host?

@stef
Copy link

stef commented Mar 24, 2021

if you use the latest release of libsphinx, then this is my fault, i should do a new release, because since 2018 we had some changes that might be significant: https://github.com/stef/libsphinx/commits/master/src/sphinx.c

@stef
Copy link

stef commented Mar 24, 2021

i actually just tagged v0.11 for libsphinx

@rolfschr
Copy link
Contributor Author

@stef
Copy link

stef commented Mar 24, 2021

hrmpf, that seems like a very good choice, however it gets us back to square one. let me figure out something. sorry for the inconvenience!

@stef
Copy link

stef commented Mar 25, 2021

let's look at this methodically

By the way, the other way around doesn't work neither: I can add user/site from the cli and cannot access it from the android app ("a server error occurred"). The app doesn't show me the created accounts. Also, from the cli, I cannot add accounts to the same site ("site") I used in the android app.

# creating a new entry works fine. I cannot find "cli.com" in the app, though.
$ printf 'm' | ../result/bin/sphinx create username cli.com ulsd 5
&!_] 
$ printf 'm' | ../result/bin/sphinx get username cli.com
&!_] 

this is obviously ok.

# "user" and "site" has been created using androsphinx but I'm unable to access it using the cli
$ printf 'm' | ../result/bin/sphinx get user site
fail

looking at the code it seems this is the only place that can trigger such a message without a traceback: https://github.com/stef/pwdsphinx/blob/b0518878dc31f27d555becb9e5ed8056564da11d/pwdsphinx/sphinx.py#L159

which means the rules blob encrypted by the phone cannot be decrypted by the host.

# Trying to access something else.
$ printf 'm' | ../result/bin/sphinx get user doesnt-exists
Traceback (most recent call last):
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/bin/.sphinx-wrapped", line 9, in <module>
    sys.exit(main())
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/lib/python3.8/site-packages/pwdsphinx/sphinx.py", line 424, in main
    ret = cmd(s, pwd, *args)
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/lib/python3.8/site-packages/pwdsphinx/sphinx.py", line 296, in get
    return doSphinx(s, GET, pwd, user, host)
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/lib/python3.8/site-packages/pwdsphinx/sphinx.py", line 151, in doSphinx
    raise ValueError("error: sphinx protocol failure.")
ValueError: error: sphinx protocol failure.

this looks ok, and seems to behave as expected.

# "user" and "site" has been created using androsphinx 
$ printf 'm' | ../result/bin/sphinx create otheruser site ulsd 5                                                                                                                                                   
Traceback (most recent call last):
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/bin/.sphinx-wrapped", line 9, in <module>
    sys.exit(main())
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/lib/python3.8/site-packages/pwdsphinx/sphinx.py", line 424, in main
    ret = cmd(s, pwd, *args)
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/lib/python3.8/site-packages/pwdsphinx/sphinx.py", line 289, in create
    update_rec(s, host, user)
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/lib/python3.8/site-packages/pwdsphinx/sphinx.py", line 206, in update_rec
    blob = decrypt_blob(blob, b'')
  File "/nix/store/7y4311acxqnqddxnvgb84jcqmh1imj8f-python3.8-pwdsphinx-0.5/lib/python3.8/site-packages/pwdsphinx/sphinx.py", line 108, in decrypt_blob
    res = pysodium.crypto_secretbox_open(blob,nonce,sk)
  File "/nix/store/hz51jzsgk9is4k2m9pm7h5bppm5a0vmy-python3.8-pysodium-0.7.5/lib/python3.8/site-packages/pysodium/__init__.py", line 640, in crypto_secretbox_open
    __check(sodium.crypto_secretbox_open(msg, padded, ctypes.c_ulonglong(len(padded)), nonce, k))
  File "/nix/store/hz51jzsgk9is4k2m9pm7h5bppm5a0vmy-python3.8-pysodium-0.7.5/lib/python3.8/site-packages/pysodium/__init__.py", line 267, in __check
    raise ValueError
ValueError

this clearly says, that when creating the new entry, the client wants to update the list of usernames associated with this host, and the record returned by the server cannot be decrypted by the client. so for some reason the blob encrypted by the phone cannot be decrypted by the client on the host.

so looking at the two causes above it seems that the decryption does not work the same way on the phone and the host.

the decryption function is quite simple:

def decrypt_blob(blob, rwd):
  # todo implement padding
  sk = get_sealkey(rwd)
  nonce = blob[:pysodium.crypto_secretbox_NONCEBYTES]
  blob = blob[pysodium.crypto_secretbox_NONCEBYTES:]
  res = pysodium.crypto_secretbox_open(blob,nonce,sk)
  clearmem(sk)
  return res

this is called from the update_rec function with an empty rwd:

blob = decrypt_blob(blob, b'')

similarly, the unpack_rules() function calls decrypt_blob() with an empty rwd. unless androsphinx sometimes sets rwd to the rwd (narrator: it doesn't), this should not be a reason for failing.

let's have a look at get_sealkey():

def get_sealkey(rwd):
  mk = get_masterkey()
  sk = pysodium.crypto_generichash(ENC_CTX, mk)
  clearmem(mk)
  # rehash with rwd so the user always contributes his pwd and the sphinx server it's seed
  if rwd_keys:
    sk = pysodium.crypto_generichash(sk, rwd)
  return sk

looking at your screenshot in the first comment on this thread, it seems rwd_keys is not set. in androsphinx rwd_keys is not even handled, so this should also not be the problem. Also ENC_CTX is the same as Context.ENCRYPTION

fun Protocol.CredentialStore.getSealKey(rwd: ByteArray = ByteArray(0)): SecretBoxKey =
    SecretBoxKey.fromByteArray(key.foldHash(Context.ENCRYPTION, rwd))

My kotlin-fu is basically non-existant but it looks like the masterkey is not contributing to the SealKey in the androsphinx version? @dnet could that be the problem?

@dnet
Copy link
Owner

dnet commented Mar 25, 2021

My kotlin-fu is basically non-existant but it looks like the masterkey is not contributing to the SealKey in the androsphinx version? @dnet could that be the problem?

key.foldHash takes care of that part, since key is masterkey in this context, and I recognized that the repeated hashing in pwdsphinx is essentially a fold/reduce operation, so Androsphinx treats it as such. So key.foldHash(Context.ENCRYPTION, rwd) is the same as hashing ENC_CTX with mk (3rd line of Python code above) and then hashing this with rwd.

However, thinking all this through leads me to believe that in case no rwd should be used, Androsphinx hashes it with an empty byte array instead of skipping it like the Python implementation. Let me check this and come back later.

@stef
Copy link

stef commented Mar 25, 2021

i simplified get_sealkey() since there was some useless code in there into:

def get_sealkey():
  mk = get_masterkey()
  sk = pysodium.crypto_generichash(ENC_CTX, mk)
  clearmem(mk)
  return sk

here's the full commit: stef/pwdsphinx@7480e7b

dnet added a commit that referenced this issue Mar 26, 2021
 - removed empty rwd from seal key
 - made rwd optional depending on boolean flag
 - probably the root cause of gh-8
@dnet
Copy link
Owner

dnet commented Mar 26, 2021

I think we've identified the root cause, @rolfschr could you please try compiling afcab74 and see if it fixes your issue?

@rolfschr
Copy link
Contributor Author

rolfschr commented Mar 27, 2021

@dnet @stef thanks a lot for your efforts. It works fine now! I can share the credentials between pwdsphinx cli client and androsphinx (in both directions). I was not sure whether I needed to supply 0x02 during the config process (since afcab74 also changed the readme in that direction). This was not needed. Maybe you want to make this somehow clear in the readme.

Awesome!

@stef
Copy link

stef commented Mar 27, 2021

hey, thank you rolf! for packaging, testing, reporting and your patience! <3

@dnet
Copy link
Owner

dnet commented Mar 27, 2021

I was not sure whether I needed to supply 0x02 during the config process (since afcab74 also changed the readme in that direction). This was not needed. Maybe you want to make this somehow clear in the readme.

This is only needed when using the (non-default) rwd_keys feature, in which case both QR generators (pwdsphinx and Androsprinx) include it when so. I'll think about whether this could be made clearer in the readme.

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

3 participants