romanz / trezor-agent

Hardware-based SSH/GPG/age agent
GNU Lesser General Public License v3.0
566 stars 152 forks source link

Adding support for Android #252

Open feklee opened 6 years ago

feklee commented 6 years ago

Would it be possible to install trezor-agent for use with gpg in a shell on Android? If so, this requires root access, right?

romanz commented 6 years ago

I never tried to run this tool on Android :( IIUC, the main issue will probably be to make sure that USB library (used by trezor-agent) and UNIX-domain socket communication (with gpg binary) work correctly.

What kind of an Android device would you like to run this tool on?

feklee commented 6 years ago

What kind of an Android device would you like to run this tool on?

Just the average Android phone, ARM powered.

Without knowing the technical details, I guess a user friendly implementation on Android could be done as follows:

In the meantime, it could be interesting to get trezor-agent running in a rooted phone.

romanz commented 6 years ago

Got it, thanks for the elaboration :)

Currently, it's a bit out of scope (for me), but I'd be happy to help to anyone to add this feature.

lpww commented 6 years ago

@feklee mentioned in another repo that adding trezor to open keychain would require custom code because they are not based on the openpgp standard.

Can you expand on that? Is it the trezor itself that isn't based on openpgp or is it the trezor-agent. It seems like integrating trezor onto open keychain would be the path of least resistance to android support.

feklee commented 6 years ago

@lpww The Trezor firmware does not implement the OpenPGP smart card API. For more information, see issue 160: Why is this (trezor-agent) needed, why is Trezor not compatible with gpg-agent?

Anyhow, in the meantime I tried two things:

romanz commented 6 years ago

@feklee Thanks for the update!

it should be possible to interface with the Trezor without udev.

With the latest trezor-agent, you can use trezord-go, which can be connected via HTTP:

$ ./trezord-go &
$ trezor-agent foo@bar.com -vv

You can run trezord on another machine - and connect to it from your Android device.

feklee commented 6 years ago

Don’t understand it:

$ ./trezord-go &
$ trezor-agent foo@bar.com -vv

This I would run on another machine? How do I connect trezor-agent to the HTTP connection?

Anyhow, the whole point is to be able to interface with the Trezor on the go, i.e. without another machine around.

If I run ./trezord-go on my phone, I get LIBUSB_ERROR_OTHER. This is as an ordinary user. If I switch to root, then I get trezord is starting without error. So this looks not too bad, although I am not too optimistic: The trezord-go installation instructions do mention udev, and that clearly is not available on Android.

If I then start trezor-agent felix.klee@inka.de -vv also on my phone, I get:

2018-08-20 13:01:36,385 DEBUG        parsed identity: {'proto': None, 'user': 'felix.klee', 'host': 'inka.de', 'port': None, 'path': None} [interface.py:30]
2018-08-20 13:01:36,386 DEBUG        identity parts: ['ssh://', 'felix.klee@', 'inka.de']                                                 [interface.py:46]
2018-08-20 13:01:36,386 INFO         identity #0: <ssh://felix.klee@inka.de|nist256p1>                                                    [__init__.py:274]
2018-08-20 13:01:36,421 WARNING      DISPLAY not defined                                                                                  [ui.py:65]
2018-08-20 13:01:36,421 INFO         using [b'ttyname=/dev/pts/0'] for pinentry options                                                   [ui.py:67]
2018-08-20 13:01:36,667 INFO         Failed to import module hid: No module named 'hid'                                                   [__init__.py:83]
2018-08-20 13:01:36,951 DEBUG        Starting new HTTP connection (1): 127.0.0.1:21325                                                    [connectionpool.py:205]
POST /enumerate
romanz commented 6 years ago

Anyhow, the whole point is to be able to interface with the Trezor on the go, i.e. without another machine around.

You're right, my solution assumes that the TREZOR is connected to another machine :(

Can you take a look at https://github.com/trezor/trezor-android (maybe there is an easy way to connect from Python to this library)?

feklee commented 6 years ago

Can you take a look at https://github.com/trezor/trezor-android (maybe there is an easy way to connect from Python to this library)?

Yes, that can be interesting. It may be possible to write an add-on app similar to Termux-API, to provide an interface in Termux to the Trezor.

jonathancross commented 5 years ago

Hi there, just checking in to see if any progress has been made over the last 7 months?

AlexanderPavlenko commented 5 years ago

https://github.com/trezor/trezord-go/issues/145

AlexanderPavlenko commented 1 day ago

Took another look at this. It seems trezorlib can be patched to work on Android via webusb transport thanks to termux-usb and updated python-libusb1. But trezor-agent depends on hidapi/udev instead of webusb.

diff --git a/python/src/trezorlib/transport/webusb.py b/python/src/trezorlib/transport/webusb.py
index 8e2d08147..55d671343 100644
--- a/python/src/trezorlib/transport/webusb.py
+++ b/python/src/trezorlib/transport/webusb.py
@@ -14,6 +14,7 @@
 # You should have received a copy of the License along with this library.
 # If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.

+import os
 import atexit
 import logging
 import sys
@@ -69,7 +70,7 @@ def close(self) -> None:
         if self.handle is not None:
             try:
                 self.handle.releaseInterface(self.interface)
-                self.handle.close()
+                #self.handle.close()
             except Exception as e:
                 raise TransportException(f"USB close failed: {e}") from e
         self.handle = None
@@ -150,15 +151,21 @@ def enumerate(
         cls, models: Optional[Iterable["TrezorModel"]] = None, usb_reset: bool = False
     ) -> Iterable["WebUsbTransport"]:
         if cls.context is None:
-            cls.context = usb1.USBContext()
-            cls.context.open()
-            atexit.register(cls.context.close)
+            cls.context = usb1.USBContext(with_device_discovery=False)
+            #cls.context.open()
+            #atexit.register(cls.context.close)

         if models is None:
             models = TREZORS
         usb_ids = [id for model in models for id in model.usb_ids]
         devices: List["WebUsbTransport"] = []
-        for dev in cls.context.getDeviceIterator(skip_on_error=True):
+
+        # install APKs: Termux, Termux:API
+        # pkg install termux-api libusb python-pip
+        # pip3 install https://github.com/vpelletier/python-libusb1/archive/refs/heads/next.zip
+        # see https://wiki.termux.com/wiki/Termux-usb
+        usb_devs = [cls.context.wrapSysDevice(int(os.environ['TERMUX_USB_FD'], 10)).getDevice()]
+        for dev in usb_devs:
             usb_id = (dev.getVendorID(), dev.getProductID())
             if usb_id not in usb_ids:
                 continue
termux-usb -r -E -e 'trezorctl list' $(termux-usb -l | jq -r '.[0]')