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

Credentials hash does not work for H100 #878

Open
ngaertner opened this issue Apr 28, 2024 · 6 comments
Open

Credentials hash does not work for H100 #878

ngaertner opened this issue Apr 28, 2024 · 6 comments
Labels
bug Something isn't working

Comments

@ngaertner
Copy link

ngaertner commented Apr 28, 2024

When i control the Tapo Plugs (like P100) i can use KLAP encryption with --credentions-hash , but when i try to access the H100 Hub I have to use AES and --username and --password.

Using credentials-hash gives me:
Raised error: 'utf-8' codec can't decode byte 0xed in position 1: invalid continuation byte

Note:
I used the same credentials hash for the Hub (AES) as I used for the Plug (KLAP) - I already learned that the hashes have to be different, so that is probably related.

My other problem is that I cannot find out the correct credential hash for the hub...

For the Plug i use the following snippet:

    device = await Discover.discover_single(
        "192.168.1.211",
        credentials=Credentials("xxxx", "xxx"),
        discovery_timeout=10
    )

    config = device.config # DeviceConfig.to_dict() can be used to store for later

    later_device = await SmartDevice.connect(config=config)

    await later_device.update()

    print(later_device.credentials_hash)

But for the H100 this code does not work - result:

...
  File "C:\Users\ngaer\AppData\Local\Programs\Python\Python311\Lib\site-packages\kasa\discover.py", line 454, in _get_device_instance
    raise UnsupportedDeviceException(
kasa.exceptions.UnsupportedDeviceException: Unsupported device 192.168.1.86 of type SMART.TAPOHUB with encrypt_type AES
@rytilahti rytilahti added the bug Something isn't working label Apr 28, 2024
@rytilahti
Copy link
Member

rytilahti commented Apr 28, 2024

If you need only the hash and not the rest of the device config, you could try device.credentials_hash. But there's indeed a bug as reconstructing the instance from the device config should work.

Looking at the code, the credentials nor the credentials hash are not actually included, but you need to pass it manually:

device.config.to_dict(credentials_hash=device.credentials_hash)

I cannot recall the reasoning for this, maybe @sdb9696 has some ideas here :-)

@sdb9696
Copy link
Collaborator

sdb9696 commented Apr 29, 2024

Hi @ngaertner it looks like you might be using the 0.6.2.1 version of the library which does not support the SMART.TAPOHUB. You'd need to run the code above from master for it to work with the hub.

Out of interest why are you trying to get the credential_hashes as opposed to just using the username and password?

@ngaertner
Copy link
Author

Hi @sdb9696,
I am confused now - https://github.com/python-kasa/python-kasa says:

Supported Tapo* devices
...
Hubs: H100
...

I prefer the credentials hash as I dont want to store my TAPO username and password in a script.

@rytilahti
Copy link
Member

rytilahti commented May 2, 2024

Yeah, it's a good idea to use hashes for storage and we do this in homeassistant, too. The problem arises when we have two (or more) types of hashes. We could solve this either by:

  1. Adding explicit options (and environment variables) for AES and KLAP, or
  2. Making it possible to pass multiple hashes which are tried until exhausted, or
  3. Going one step further with number two and encoding the type of the hash in the entry.

The first may not work that well in practise, as different klap versions did use different way for hashing. It also clutters the environment, may confuse users, and is a bit complicated to extend when and if new ways for hashing appear.
The second will cause unwanted extra I/O, but be rather easy to implement by allowing passing the --credentials-hash multiple times (and allowing to store them as a list for the environment variable).
The third option is similar to what is used for password hashing of /etc/shadow where the format is something like $<hash type>$<salt>$<hash itself>. This would be an extension to the second one, and probably the best option.

@ngaertner Steven meant that you should try this again with the current master branch. FWIW, the code you gave is working for me and prints out the same hash as kasa --host <addr> -v.

There is a bug in the condition when passing the hash though, and you are forced to define at least --credentials-hash, --encrypt-type and --device-family for it to work. I just confirmed that the hash is working on my H100 with kasa --host 192.168.250.131 --credentials-hash xxx== --encrypt-type AES --login-version 2 --device-family SMART.KASAHUB

@ngaertner
Copy link
Author

I was able to generate an AES credentials-hash for the hub, but only after fixing lots of errors like this:

ModuleNotFoundError: No module named 'pydantic.v1'
-> i had to replace pydantic.v1 by pydantic to get it running.

I think i will anyways need to wait for the next stable release - any date for it?

@sdb9696
Copy link
Collaborator

sdb9696 commented May 3, 2024

If you need only the hash and not the rest of the device config, you could try device.credentials_hash. But there's indeed a bug as reconstructing the instance from the device config should work.

I'm not sure of the bug here as I believe it does work to reconstruct the device from the config. Is there an example I can try?

Looking at the code, the credentials nor the credentials hash are not actually included, but you need to pass it manually:
device.config.to_dict(credentials_hash=device.credentials_hash)

If you provide a credentials_hash the return dict will be saved with the hash, otherwise the clear text credentials will be included in the dict unless exclude_credentials is set to True.

There is a bug in the condition when passing the hash though, and you are forced to define at least --credentials-hash, --encrypt-type and --device-family for it to work. I just confirmed that the hash is working on my H100 with kasa --host 192.168.250.131 --credentials-hash xxx== --encrypt-type AES --login-version 2 --device-family SMART.KASAHUB

I wouldn't call this a bug at the moment because the credentials_hash is dependant on the encryption scheme so these parameters are required for connect. However based on this suggestion:

The third option is similar to what is used for password hashing of /etc/shadow where the format is something like $<hash type>$<salt>$<hash itself>. This would be an extension to the second one, and probably the best option.

This is not that different from storing the dict and then restoring it although it does give an easy way to pass it on the command line. If we think there's a broad use case out there for this behaviour we could extend the cli to support a credentials-hash command that returns a hash with encryption scheme information embedded.

I think i will anyways need to wait for the next stable release - any date for it?

Not yet but aiming for this month.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants