The Everyday Thinfoilhead: A USB Armory with a Mimblewimble Grin Wallet
The USB Armory MK 1 (https://inversepath.com/usbarmory) is an open design linux thumbdrive with certain interesting security features, first of all, of course, being open design hardware. One should not, however, confuse this with an open hardware design.
Its NXP/Freescale i.MX53 SoC is a Cortex A8 (ARMv8) clocking at 800MHz and providing 0.5 GB memory. It has a Security Controller (SCCv2), a cryptographic accelerator (SAHARAv4 Lite) and ARM TrustZone on board. A Debian that has the SSCv2 kernel driver already compiled into is one of the supported OS.
I am not affiliated with InversePath, the company behind the Armory, besides being a customer. I am interested in decentralized tech with the goal of developing best of breed: trust-less infrastructure vs. user centric hardware-software stacks join forces to protect privacy. There is an intricate tension between privacy in a blockchain (confidential transactions, zero knowledge proof systems, compression, routing/mixing) and an imperfect user space. With all those remarkable capabilities of blockchains in place, born in the midst of the most hostile environment, one can expect the user’s wallet to become the main target of attention soon enough — both, in order to steal funds, as for breaking privacy. Hardware anchored security comes to the rescue. But not the sort of hardware that just claims to be trustworthy by placing a black cryptographic box right in the middle of the user’s best beloved secrets. There is more to it than trusted 3rd party TEEs or one trick pony style tailored hardware wallets, or U2F sort of authenticating devices and so forth.
Low tech like HD (hierarchical deterministic) wallets, though not invented for privacy reasons, open up a convenience road to paper and wetware (thanx to mnemonics), but I do not like the idea of backup/recovery at all. For instance, in Mimblewimble-Grin (https://github.com/mimblewimble/grin), it is entirely possible to backup a seed/password combination and delete the wallet once funds have been received by it. The high value assets it holds sit on the blockchain. Once I need access, the wallet recovery is easy. The UTXOs(Confidential Transactions in this case) are intact, the history is deleted, privacy is preserved. So far so good, but the idea of the keys to the kingdom lurking around in a backup somewhere all the time is frightening. Either my brain looses control (a.k.a. I forget) or I loose my brain’s crutch — and somebody finds it. Either way, I have to be very disciplined to avoid this.
Thats why I want to find a sweeter spot, a computing platform that is open and commodity enough and can be tied down with best linux techniques and opsec. One approach could be a versatile, full featured linux box that acts as an ultra mobile proxy to a cheap SD card. With this objective, we can start small and increase the security level with the value of the assets stored accordingly. There is even a microkernel based architecture (Genode) available for this piece, but right now, all I care is commodity access capabilities and formfactor. This gives a chance to implement non-torturing opsec.
How is this: Having a Grin wallet on an Armory, which itself is plugged in a battery-powered Raspi3. The Armory is accessible via ssh from the Raspi3 only. The Grin node that the Armory-Grin-wallet is affiliated with, runs on an Ubuntu18.04–64 virtual machine somewhere in the local network and is synced to testnet4. The potential number of wallets on the Armory is limited only by the size of the SD card, as is the number of accounts per wallet. We could build a whole banking institution on this small silicon. This of course is limited by the number of parallel processes then. As this use case is beyond our intention so far, let’s move on.
One might ask why not having the Raspi hosting the Grin server node, or plug the Armory directly to the PC. Well, first of all I like the idea of low cost indirection and covert operation (including plausible deniability). And second, I do not want to end up in an unwanted state (after patching drivers or kernel modules) with the Armory’s SD card ending up as a mass storage device at the Grin server node’s computer. This cheap trick prevents us from needing other methods of compartmentalization, methods that are not commodity or might not survive on the long run.
Besides this separation of concerns trick it is not obvious which of Armory’s security features are low hanging fruits for our use case. Of course, this depends on the attack model and our assumptions on the strength of the attacker. Right now I just go for a very simple model. Two types of attackers: the ordinary one wants to get access to the seed/pwd in order to steal funds. An online wallet that sits right on a fully synced online Grin server node is his easy prey. The other type does a half hearted targeted attack on my environment to break privacy of past and future transactions. Stealing or seizing funds might be nice but is a side concern. This guy could try to attack the blockchain itself in order to reach his goal, but a Mimblewimble chain has no history and making copies of the mempool every millisecond starting from genesis needs serious resources and does not scale. That would be a nation state’s strategy. This is not our concern here. Thats why we call our attacker half heartedly motivated. Our attacker is not weak. He has physical access and can seize every piece of equipment, can intrude offline and online, but does not know where to look for. He can install trojans and malware on mainstream computing equipment and consumer electronics. But he is bound by the nature of scalability (a.k.a. budget under opportunity cost model).
So, I am going to separate the wallet from the nodes, from p2p traffic at all actually. And in times of commodity cloud backups, telcos and consumer electronics vendors spying at us, I cut off most of the comfort: a headless Debian must do it.
On the other hand, this piece should be more than a stone cold wallet though. It should be a core functional space for transfers, a safe for my funds and a singleton provider of truth for my transaction history with a last line of privacy defense around it. But it is too early to get our hands dirty with tweaking secure boot, encrypted storage, side channel countermeasures, physical penetration and the like. This piece is not a HSM - yet. Right now all we care is bringing it to life. Having said that, a low hanging fruit could be some opsec one can place on handling the stick, because this it is: a USB formfactor with the look and feel of an old fat thumbdrive and a removable MicroSD card as storage.
The regime is this:
Instead of making backups of a wallet’s seed, I set up many SD cards with the same binaries. Every SD card holds other wallets. I spread my funds between my wallet/SDcards with respect to their value. If a SD card faults, I realize the loss of value. I spread the risk of loss by investing in better SD cards or more SD cards only. This is it: my objective stays always the same. Every SD card is unique — like a money bill. As soon as I would backup the seed, I would give up the last line of defense of privacy or ownership, especially without further steps towards encryption including keymanagement and secure boot. (These steps induce new problems and complicate things tremendously. See the ToDo chapter at the end of this article.)
So, I buy a couple Armories, just to be able to replace a broken piece without having to wait for a replacement order to be fulfilled, or, in case the Armory is not manufactures anymore, and has not even a successor model (which it has: it is called MK 2) and the SD card is not accessible from a different device because it is encrypted or an outdated filesystem or whatever. Well, thousand ways to fail there are, but after all, we still have the design schematics, to task someone to rebuild our stick.
Then I buy a few SD cards. Once I have a running system with the Grin project compiled on the stick (not crosscompiled), but not initialized yet, I `dd` clone the image to the other cards. (We will never again make `dd` copies once a wallet is initialized.) As said before, if a specific SD card faults, it is unfortunate.
The idea behind this regime is simple: I use a TRNG for generating the wallet’s entropy. Every wallet on a particular Armory+SDcard uses the same sort of randomness generation process AND the same exact silicon to do this. Every UTXO/commitment is tied to this combination. If it turns out one day, that this randomness has structure and other’s don’t, we have evidence and a short path to find the root cause of evil. By restricting the use of the wallet binaries to use Armories’ TRNG only, we have set a boundary. A SoC does not save the day. All it does is setting up an easy to grasp and well defined environment.
We use an out of the box Raspbian Stretch. The Armory acts as a network interface once plugged in one of Raspi’s USB ports. Also, we have to take into account that we not only want to ssh into it but want to use the network access capabilities of the Raspi3 from within the Armory too. (We don’t want the Armory be deaf and blind, we want it slick and shielded though.)
sudo /sbin/ip link set usb0 up sudo /sbin/ip addr add 10.0.0.2/24 dev usb0 sudo /sbin/iptables -t nat -A POSTROUTING -s 10.0.0.1/32 -o wlan0 -j MASQUERADEsudo nano /proc/sys/net/ipv4/ip_forward
In the ip_forward file, replace 0 by 1. Next make sure we will not get into trouble with ssh due to some access restrictions resulting from past logins. Just delete the old entries and log in — the factory password is “usbarmory”:
ssh-keygen -f “/home/pi/.ssh/known_hosts“ -R 10.0.0.1 ssh firstname.lastname@example.org
ping 188.8.131.52 cat /etc/debian_version >>>8.6
Version 8.6 is good enough for us. I tried upgrading to 9.6 but ran into compile errors with Grin afterwards. Speaking of which, we need some libraries:
sudo apt install build-essential cmake git libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev pkg-config libssl-dev
Install Rust. (We practice some bad habits by getting rid of boring certchecks, thereby letting plenty of room for further rework …)
sudo apt install wget cd ~ mkdir rust cd rust wget --no-check-certificate https://static.rust-lang.org/dist/rust-1.30.1-arm-unknown-linux-gnueabi.tar.gz tar -zxvf rust-1.30.1-arm-unknown-linux-gnueabi.tar.gz cd rust* sudo ./install.sh
Install the Grin sources (November 12, 2018).
cd ~ GIT_SSL_NO_VERIFY=true git clone https://github.com/mimblewimble/grin.git cd grin git config http.sslVerify false
Now we can’t avoid it anymore. Otherwise we get stuck in the build process:
sudo update-ca-certificates --fresh sudo reboot
Restart the Raspi as well, but be aware: After every reboot and before we ssh into Armory we have to repeat the network configuration steps, because we did not make the network config changes prevail so far.
sudo /sbin/ip link set usb0 up ...
cd ~/grin sudo cargo build -release
… 8 hours pass by (seriously) …
sudo ln -s /home/usbarmory/grin/target/release/grin /usr/local/bin grin wallet -help
Our software is set. Unplug the Armory, take remove the SD card and make a bit exact copy of the Micro SD card on another linux box (other than Armory or Raspi) via `dd`. If the original SD card is a 4GB model, that should work. We went with 32GB and used up less than 3GB. (No additional swap increasing techniques were being applied.) One can start with a small card, make an image and restore the image to a larger card if appropriate. If the wasted space is a concern, one can fill the available space using fdisk and resize2fs.
Once this duplication to an image file is done we head back to initialize our first wallet. A neat thing of our Armory and the reason why I like the SAHARAv4 Lite cryptographic accelerator is the availability of a True Random Number Generator. Before we initialize the wallet we check if the TRNG’s security coprocessor driver is operational in the linux kernel log message.
sudo cat /var/log/messages | grep sahara >>>sahara 63ff8000.crypto: SAHARA v 4 initialized
Not much info is available on the specifics of the TRNG in the public domain. It is not open hardware, unfortunately. Anyway, we are good to go now:
grin wallet -p „password“ init
After this setup is done, a folder that holds config, local database and seed has been created. We can set up various accounts within this wallet, as much as we’d like. In terms of secrecy, it doesn’t change anything, as we deal with an HD wallet structure here. Everything is under control of the master secret. If we want more entropy in the game, we need to set up another wallet, again, as much as we’d like, but with special consideration of other paths in the filesystem. From a blockchain’s perspective, these are different parties. We omit the steps of setting up accounts or other wallets for sake of clarity. Instead, we are going to configure the wallet now.
nano ~/.grin/grin-wallet.toml api_listen_interface = „0.0.0.0“ api_listen_port = 13415 #the address of the fully synced grin node in the local network: check_node_api_http_addr = „http://192.168.178.43:13413“ #disable http basic auth #node_api_secret_pathgrin wallet info
The check_node_api_http_addr is certainly the most important parameter here because we set the bond with a Grin server node in our local network. The api_listen_interface we set open for testing purposes only. Open it up (0.0.0.0) or closing it down (127.0.0.1) depends on our workflow. If we only want to send and receive coins asynchronously via email, chat or owl, we can close it down.
The wallet displays the current blockheight that the associated Grin server node is aware of. Crosscheck with a blockexplorer (e.g. grinscan.net) in a browser window at Raspi. Or have a look at our Grin server console at the other linux box.
In a second ssh shell we start the wallet listener. As stated above there is no need to keep the listener operational all the time, or even at any time. Basically the Mimblewimble communication pattern is 1.5-way asynchronous (sender wallet to receiver wallet, receiver wallet to sender wallet, sender wallet to grin server node) without any timing restrictions, just causal dependencies. The Grin blockchain p2p network provides the source of all truth. The onlinestatus of a wallet (wallet listener) does not change anything at this circumstance. It just influences the back and forth of value transfer, making it more or less fluid. In addition, we don’t use our Armory wallet to collect blockrewards from our miner. So, for our purpose, I shut it down .
Before we initiate some action we check our wallet status:
grin wallet info
What we can see is the blockheight that the associated Grin server node sees. Also, we see that our wallet does not own any funds yet.
(In a second ssh shell we start the listener, just to check if it works:
grin wallet listen
… and close it down as mentioned before.)
Apart from collecting blockrewards that we omit for opsec reasons, we can get some Grins from a faucet like gringod.info, but we have to expose port 13415 to the internet. Again, counterproductive. But that’s not a problem, because the 1.5way protocol for token transfer is neither bound to a specific transport mechanism nor to an address type that enforces a specific channel (like for instance ENS, DNS, IP address). On the cost of 1.5way-ness we get anonymity and a certain degree of tech-freedom. (We could even use an owl or a spell accordingly.)
So let’s head over to http://gitter.im/grin_community in order to ask around for some Grins on testnet4. What we get from a good neighbor is a JSON file which is basically a request: “I want to send You this specific amount of Grins. If You want this to happen, reply with some of Your derived and encrypted randomness.” (This is an extreme oversimplification but enough to get a picture of the flow.)
We hand the structure over (from Raspi to Armory) and feed it into the grin wallet command (on Armory). The response file we get from the wallet we transfer back to the Raspi, where we pick it up and send it to the Grin-sender (via Pastebin, eMail, owl, etc.).
scp senderfile.json email@example.com:/home/usbarmory/tmpgrin wallet request -i senderfile.jsonscp firstname.lastname@example.org:/home/usbarmory/tmp/senderfile.json.response /home/pi/tmp
The sender finishes the construction of the transaction and broadcasts it to the network where it lurks around until a miner picks it up, verifies it and includes it into a block (in case he was happy and won the PoW lottery).
We can check that the funds have arrived once the transaction made it into a block and the block is finalized and synced with our own Grin server node by asking the server node from within our wallet realm:
grin wallet info grin wallet txs
These calls act like a filter and decrypter for funds(UTXOs/CTs) that we own.
Now that we own some Grins, we are going to send them to some other needy wallet, let’s say some wallet on another Armory on another Raspi in the local network, for a starter. So, we decide that we are going to send 1 Grin to someone. (We omit test-transactions to `self` or from account to account within the same wallet for sake of clarity. Also, we omit user strategies to improve the privacy in the network once the transaction is on its way.)
We just start with:
grin wallet send -m file -d /home/usbarmory/tmp/requReceiver.json 1
(No noticeable delay at all. Nice.)We transfer the request to the other wallet’s box. There we do the step we already know from the first workflow:
grin wallet request -i requReceiver.json
Once we have sent back the response file of this distant operation, we feed it into the final process step on the primary, sending edge:
grin wallet finalize -i requReceiver.json.response
Again, no noticeable delay on the Armory, not even for the rangeproof computation. And after a few minutes we can see the blockchain confirmation on both sides of this payment workflow with a blockexplorer and with
grin wallet info grin wallet txs
Don’t forget to clean up the mess of all the temporary files we created along the line, as we do not want to leave traces of our activities.
Grin wallet compiles on an ARMv8 embedded platform without any problem. On a first impression, it performs very well and can be used with a remote Grin server node which is p2p synced in Grin’s testnet4 instantaneously. An opsec regime can be set up to bind wallet functionality to a well defined TRNG. We consider predictable randomness becoming a major issue in hostile environments (aka public blockchains) one day, but we have to be prepared today for this to happen, as the current funds might stay on a chain for a very long time.
From a hardware protective ankle one could say, that the Armory occupies a niche between special purpose vehicles on one side of the spectrum and HSMs on the other side. The problem with expensive HSMs though is a gametheoretic principal agent kind of delusion: In theory you buy yourself trust in a vendor. But in fact you never know what you get because it is designed to not let you find a smoking gun in it (a.k.a. backdoors, hidden channels, channels in structured randomness), even with all audits and certifications. Therefor, if crypto-acceleration is not of your concern, you could even skip the top end products at all and focus on the ease of extensibility for sake of better opsec, better crypto, better protocols and communication channels (Tor, Whisper, VPN), a.k.a. security at depth.
With all this in mind, I like the way the Armory paves, especially when it comes to find a sweet spot between affordability, extensibility, size, commodity and state of the art tooling. It sets a benchmark.
So far I have not focused on the various security implications. More investigation has to be done in order to get more confidence in the SW/HW stack of the Armory. Having peripherals, circuitry, kernel modules and application SW that suit you in place is a good starter, especially if it is well maintained and limited in footprint. But it is a long path to the promised land. Right now, NXP is our trust anchor, which is somewhat counterintuitive for a proclaimed trustless environment and decentralization objective.
For a holistic security review we have to take into account the various methods of
- toolchain poisoning
- device backdooring
- active and passive side channel attacks of the various flavors
Related to this is Inverse Path’s supply chain. Although they did an incredible job with this, we still have to stay wary, especially because it is not open hardware what we get. At least not in a thinfoilhead’s sense.
Beside linux hardening (and more patience with certificate management), the Armory’s capabilities in terms of Trustzone, filesystem encryption, steganographic techniques are vast.
Kudos to both projects: Grin & USB Armory !