A website that bills itself as providing a safer way to store Bitcoin and other digital currencies has been using a coding sleight of hand to generate private keys that are suspiciously trivial for the operators to guess, leaving all funds stored in the wallets open to theft, researchers with a different service said on Friday.

WalletGenerator.net provides code for creating what are known as paper wallets for 197 different cryptocurrencies. Paper wallets were once billed as a secure way to store digital coins because—in theory, at least—the private keys that unlock the wallets are stored on paper, rather than on an Internet-connected device that can be hacked. (In reality, paper wallets are open to hack for a variety of reasons.) While the site advises people to download the code from this Github page and run it while the computer is unplugged from the Internet, it also hosted a simpler, stand-alone service above all the instructions for generating the same wallets.

Researchers from MyCrypto, which provides an open-source tool for cryptocurrency and blockchain users, compared the code hosted on Github and WalletGenerator.net and found some striking differences. Sometime between August 17 and August 25 of last year, the WalletGenerator.net code was changed to alter the way it produced the random numbers that are crucial for private keys to be secure.

Previously, mouse movements or key presses provided by the site visitor provided the random input needed to ensure the numbers weren’t predictable. The changed code introduced last August still allowed end users to see the text that prompted them to move their mouse or type characters, and it still showed a progress bar and graphics that responded in real time as the visitors complied. But behind the scenes, the MyCrypto researchers said, the code completely ignored this input.

Instead the WalletGenerator.net code used images supplied by the site to provide the random input. These changes resulted from the addition of a function called SecureRandomAdvanced, which modified the SecureRandom function previously used.

The code hosted on WalletGenerator.net was reverted back to its previous version sometime on Thursday, after the MyCrypto researchers reported the behavior to the site operator. As mentioned above, visitors who followed the advice to use the code hosted on Github—and not the code hosted on WalletGenerator.net—were never affected.

“In this strange turn of events, we still have no idea whether the current site owner is the malicious party, if the server is insecure, or both,” Harry Denley, MyCrypto’s director of security, wrote in a post published Friday. “We’re still considering this highly suspect and still recommending users who generated public/private keypairs after August 17, 2018 to move their funds. We do not recommend using WalletGenerator.net moving forward, even if the code at this very moment is not vulnerable.”

Unearthing a backdoor

One of the first differences MyCrypto researchers noticed in the changed code was that it requested an image be downloaded from the site. This request struck the researchers as odd, because the image had already loaded when their browser first visited the page. After more digging, they discovered that the newly added SecureRandomAdvanced function tapped data inside the image for the random input that previously came from mouse movements or inputted characters.

The researchers discovered some unusual characteristics to the image. For one, it was large. Stranger yet, while it appeared to be visually identical each time, different instances produced different cryptographic fingerprints known as checksums. These different sha256sums seemed to vary depending on the IP address of the computer that downloaded the image. Below are the checksums for the same file, named bitcoin.png, along with the file size and the IP location that received it:

sha256sum hashes of the file bitcoin.png : $ sha256sum bitcoin.png (United Kingdom) 27cfafd3fe3810a89375a2f3ccc253cd6b2f03b5ff30ec6b41a76f8f2393085d local.png $ du -hs bitcoin.png 156K bitcoin.png $ sha256sum bitcoin.png (Netherlands) 4798d4167a98b56dc112878aed578f64ff9fb20fc58774a468e9b53f9aa1fc59 nl.png $ du -hs bitcoin.png 16K bitcoin.png $ sha256sum bitcoin.png (California) 4798d4167a98b56dc112878aed578f64ff9fb20fc58774a468e9b53f9aa1fc59 na_cali.png $ du -hs bitcoin.png 16K bitcoin.png $ sha256sum bitcoin.png (N. Virginia us-east-1) 86b475b38b137e50e317ce4478cc9abf41d33c158e12d2174dc1dd6f786ec45f onvpn.png $ du -hs bitcoin.png 156K bitcoin.png $ sha256sum bitcoin.png (Spain) 4798d4167a98b56dc112878aed578f64ff9fb20fc58774a468e9b53f9aa1fc59 offvpn.png $ du -hs bitcoin.png 16K bitcoin.png

The second and third entries, with the checksum beginning 479, correspond to the unmodified image. The other three were somehow modified. The researchers used a tool called binwalk to analyze the modified images, but they still aren’t sure what causes the the modified images to have different checksums even though they all appear visually identical. The researchers suspect the modified images contain hidden data that the SecureRandomAdvanced function used to generate the random numbers.

“We know something is happening to manipulate the image, but are unable to determine what exactly is happening,” Denley wrote. “Most steganography tools include a password functionality, meaning successfully decrypting the ‘hidden’ data is impossible without knowing the password provided at the time of constructing the image.”

The researchers tested their hypothesis by using a bulk function to generate 1,000 keys. The code from Github provided 1,000 unique key pairs. The code hosted on WalletGenerator.net, however, produced only 120 unique key pairs. When the researchers refreshed their browser, changed the IP location used by their virtual private network, and used the WalletGenerator.net code to produce subsequent 1,000-keypair batches, they would once again get only 120 unique pairs, but each time, they were different from previous sessions. Here's a video of what it looked like

The researchers also found that using an image with the same checksum at a later date generated precisely the same set of 120 key pairs as previously generated. With that, they had proof the key pairs were fully deterministic based on the image. But that still didn’t explain how or why 120 unique key pairs were generated each time. In an email, Denley wrote:

I am not too versed in cryptography, but the general gist is only 120 keypairs generated instead of 1,000. These 120 keypairs are deterministic depending on the modified coin icon you have (since the keys are derived from the injected bytes of that file). There were other parts of the logic modified that weren't illustrated in the article that may better explain the math behind _why_ 120, but in short, the logic was modified with a random number between 0 and 119 to make it entirely predictable outcome (the attacker would need to seed the logic with the same bytes from the image and run it 120 times to get a key that a user _may_ have used). If you run the logic with the same coin icon, you'd get the same address each time, which is why a random number between 0 and 119 was added so it gave the illusion of a non-deterministic keypair generation.

Attempts to reach WalletGenerator.net operators for comment on Twitter didn’t succeed. According to Friday’s post, the operators told MyCrypto, “They were unable to verify our claims and asking if we were perhaps on a phishing site.”

In the operators’ defense, the site instructs users in two separate places not to run the code hosted on the site and instead to download the unmodified code from Github. Anyone who followed those directions would be unaffected by the insecure service hosted on WalletGenerator.net. Additionally, there’s no evidence—at least so far—that the wallets have been used to steal anyone’s cryptocurrency.

Still, the findings in Friday’s post are a red flag, not just about WalletGenerator.net in particular but for all free services that offer supposedly safe tools for storing cryptocurrency. Keeping digital coins secure from hackers is a full-time job that requires skill and diligence. People should invest huge amounts of investment, and serve generous portions of skepticism, before settling on a wallet.