Tuesday, May 03, 2016

Satoshi: how Craig Wright's deception worked

My previous post shows how anybody can verify Satoshi using a GUI. In this post, I'll do the same, with command-line tools (openssl). It's just a simple application of crypto (hashes, public-keys) to the problem.

I go through this step-by-step discussion in order to demonstrate Craig Wright's scam. Dan Kaminsky's post and the redditors comes to the same point through a different sequence, but I think my way is clearer.

Step #1: the Bitcoin address


We know certain Bitcoin addresses correspond to Satoshi Nakamoto him/her self. For the sake of discussion, we'll use the address 15fszyyM95UANiEeVa4H5L6va7Z7UFZCYP. It's actually my address, but we'll pretend it's Satoshi's. In this post, I'm going to prove that this address belongs to me.

The address isn't the public-key, as you'd expect, but the hash of the public-key. Hashes are a lot shorter, and easier to pass around. We only pull out the public-key when we need to do a transaction. The hashing algorithm is explained on this website [http://gobittest.appspot.com/Address]. It's basically base58(ripemd(sha256(public-key)).

Step #2: You get the public-key


Hashes are one-way, so given a Bitcoin address, we can't immediately convert it into a public-key. Instead, we have to look it up in the blockchain, the vast public ledger that is at the heart of Bitcoin. The blockchain records every transaction, and is approaching 70-gigabytes in size.

To find an address's match public-key, we have to search for a transaction where the bitcoin is spent. If an address has only received Bitcoins, then its matching public-key won't appear in the Blockchain. In that case, a person trying to prove their identity will have to tell you the public-key, which is fine, of course, since the keys are designed to be public.

Luckily, there are lots of websites that store the blockchain in a database and make it easy for us to browse. I use Blockchain.info. The URL to my address is:


There is a list of transactions here where I spend coin. Let's pick the top one, at this URL:


Toward the bottom are the "scripts". Bitcoin has a small scripting language, allowing complex transactions to be created, but most transactions are simple. There are two common formats for these scripts, and old format and a new format. In the old format, you'll find the public-key in the Output Script. In the new format, you'll find the public-key in the Input Scripts. It'll be a long long number starting with "04".

In this case, my public-key is:

04b19ffb77b602e4ad3294f770130c7677374b84a7a164fe6a80c81f13833a673dbcdb15c29857ce1a23fca1c808b9c29404b84b986924e6ff08fb3517f38bc099

You can verify this hashes to my Bitcoin address by the website I mention above.

Step #3: You format the key according to OpenSSL


OpenSSL wants the public-key in it's own format (wrapped in ASN.1 DER, then encoded in BASE64). I should just insert the JavaScript form to do it directly in this post, but I'm lazy. Instead, use the following code in the file "foo.js":

KeyEncoder = require('key-encoder');
sec = new KeyEncoder('secp256k1');
args = process.argv.slice(2);
pemKey = sec.encodePublic(args[0], 'raw', 'pem');
console.log(pemKey);

Then run:

npm install key-encoder

node foo.js 04b19ffb77b602e4ad3294f770130c7677374b84a7a164fe6a80c81f13833a673dbcdb15c29857ce1a23fca1c808b9c29404b84b986924e6ff08fb3517f38bc099

This will output the following file pub.pem:

-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEsZ/7d7YC5K0ylPdwEwx2dzdLhKehZP5q
gMgfE4M6Zz282xXCmFfOGiP8ocgIucKUBLhLmGkk5v8I+zUX84vAmQ==
-----END PUBLIC KEY-----

To verify that we have a correctly formatted OpenSSL public-key, we do the following command. As you can see, the hex of the OpenSSL public-key agrees with the original hex above 04b19ffb... that I got from the Blockchain: 

$ openssl ec -in pub.pem -pubin -text -noout
read EC key
Private-Key: (256 bit)
pub:
    04:b1:9f:fb:77:b6:02:e4:ad:32:94:f7:70:13:0c:
    76:77:37:4b:84:a7:a1:64:fe:6a:80:c8:1f:13:83:
    3a:67:3d:bc:db:15:c2:98:57:ce:1a:23:fc:a1:c8:
    08:b9:c2:94:04:b8:4b:98:69:24:e6:ff:08:fb:35:
    17:f3:8b:c0:99
ASN1 OID: secp256k1

Step #4: I create a message file


What are we are going to do is sign a message. That could be a message you create, that you test if I can decrypt. Or I can simply create my own message file.

In this example, I'm going to use the file message.txt:

Robert Graham is Satoshi Nakamoto

Obviously, if I can sign this file with Satoshi's key, then I'm the real Satoshi.

There's a problem here, though. The message I choose can be too long (such as when choosing a large work of Sartre). Or, in this case, depending on how you copy/paste the text into a file, it may end with varying "line-feeds" and "carriage-returns". 

Therefore, at this stage, I may instead just choose to hash the message file into something smaller and more consistent. I'm not going to in my example, but that's what Craig Wright does in his fraudulent example. And it's important.

BTW, if you just echo from the command-line, or use 'vi' to create a file, it'll automatically append a single line-feed. That's what I assume for my message. In hex you should get:

$ xxd -i message.txt
unsigned char message_txt[] = {
  0x52, 0x6f, 0x62, 0x65, 0x72, 0x74, 0x20, 0x47, 0x72, 0x61, 0x68, 0x61,
  0x6d, 0x20, 0x69, 0x73, 0x20, 0x53, 0x61, 0x74, 0x6f, 0x73, 0x68, 0x69,
  0x20, 0x4e, 0x61, 0x6b, 0x61, 0x6d, 0x6f, 0x74, 0x6f, 0x0a
};
unsigned int message_txt_len = 34;


Step #5: I grab my private-key from my wallet


To prove my identity, I extract my private-key from my wallet file, and convert it into an OpenSSL file in a method similar to that above, creating the file priv.pem (the sister of the pub.pem that you create). I'm skipping the steps, because I'm not actually going to show you my private key, but they are roughly the same as above. Bitcoin-qt has a little "dumprivkey" command that'll dump the private key, which I then wrap in OpenSSL ASN.1. If you want to do this, I used the following node.js code, with the "base-58" and "key-encoder" dependencies.

Base58 = require("base-58");
KeyEncoder = require('key-encoder');
sec = new KeyEncoder('secp256k1');
var args = process.argv.slice(2);
var x = Base58.decode(args[0]);
x = x.slice(1);
if (x.length == 36)
    x = x.slice(0, 32);
pemPrivateKey = sec.encodePrivate(x, 'raw', 'pem');
console.log(pemPrivateKey)

Step #6: I sign the message.txt with priv.pem


I then sign the file message.txt with my private-key priv.pem, and save the base64 encoded results in sig.b64.

openssl dgst -sign priv.pem message.txt | base64 >sig.b64

This produces the following file sig.b64 that hash the following contents:

MEUCIQDoy6K0xQ1cAPg7fXbQcmfbtK4VJ5wlMTzG4DaUV3zF9gIgLNbJw0oqj3lQf7lhe7TtPzse
PXf8GB3q4IhCiWVxTJ8=

How signing works is that it first creates a SHA256 hash of the file message.txt, then it encrypts it with the secp256k1 public-key algorithm. It wraps the result in a ASN.1 DER binary file. Sadly, there's no native BASE64 file format, so I have to encode it in BASE64 myself in order to post on this page, and you'll have to BASE64 decode it before you use it.

Step #6: You verify the signature


Okay, at this point you have three files. You have my public-key pub.pem, my messagemessage.txt, and the signature sig.b64.

First, you need to convert the signature back into binary:

base64 -d sig.b64 > sig.der

Now you run the verify command:

openssl dgst -verify pub.pem -signature sig.der message.txt

If I'm really who I say I am, and then you'll see the result:

Verified OK

If something has gone wrong, you'll get the error:

Verification Failure


How we know the Craig Wright post was a scam


This post is similarly structure to Craig Wright's post, and in the differences we'll figure out how he did his scam.

As I point out in Step #4 above, a large file (like a work from Sartre) would be difficult to work with, so I could just hash it, and put the binary hash into a file. It's really all the same, because I'm creating some arbitrary un-signed bytes, then signing them.

But here's the clever bit. If you've been paying attention, you'll notice that the Sartre file has been hashed twice by SHA256, before the hash has been encrypted. In other words, it looks like the function:

secp256k1(sha256(sha256(message)))

Now let's go back to Bitcoin transactions. Transactions are signed by first hashing twice::

secp256k1(sha256(sha256(transaction)))

Notice that the algorithms are the same. That's how how Craig Write tried to fool us. Unknown to us, he grabbed a transaction from the real Satoshi, and grabbed the initial hash (see Update below for contents ). He then claimed that his "Sartre" file had that same hash:

479f9dff0155c045da78402177855fdb4f0f396dc0d2c24f7376dd56e2e68b05

Which signed (hashed again, then encrypted), becomes:

3045022100c12a7d54972f26d14cb311339b5122f8c187417dde1e8efb6841f55c34220ae0022066632c5cd4161efa3a2837764eee9eb84975dd54c2de2865e9752585c53e7cce

That's a lie. How are we supposed to know? After all, we aren't going to type in a bunch of hex digits then go search the blockchain for those bytes. We didn't have a copy of the Sartre file to calculate the hash ourselves.

Now, when hashed an signed, the results from openssl exactly match the results from that old Bitcoin transaction. Craig Wright magically appears to have proven he knows Satoshi's private-key, when in fact he's copied the inputs/outputs and made us think we calculcated them.

It would've worked, too, but there's too many damn experts in the blockchain who immediately pick up on the subtle details. There's too many people willing to type in all those characters. Once typed in, it's a simple matter of googling them to find them in the blockchain.

Also, it looks as suspicious as all hell. He explains the trivial bits, like "what is hashing", with odd references to old publications, but then leaves out important bits. I had to write code in order to extract my own private-key from my wallet in order to make it into something that OpenSSL would accept -- I step he didn't actually have to go through, and thus, didn't have to document.


Conclusion


Both Bitcoin and OpenSSL are just straightforward applications of basic crypto. It's that they share the basics that made this crossover work. It's by applying our basic crypto knowledge to the problem that catches him in the lie.

I write this post not really to catch Craig Wright in a scam, but to help teach basic crypto. Working backwards from this blogpost, learning the bits you didn't understand, will teach you the important basics of crypto.


Appendix


To verify that I have that Bitcoin address, you'll need the three files:

pub.pem

-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEsZ/7d7YC5K0ylPdwEwx2dzdLhKehZP5q
gMgfE4M6Zz282xXCmFfOGiP8ocgIucKUBLhLmGkk5v8I+zUX84vAmQ==
-----END PUBLIC KEY-----

message.txt

Robert Graham is Satoshi Nakamoto

sig.b64

MEUCIQDoy6K0xQ1cAPg7fXbQcmfbtK4VJ5wlMTzG4DaUV3zF9gIgLNbJw0oqj3lQf7lhe7TtPzsePXf8GB3q4IhCiWVxTJ8=

Now run the following command, and verify it matches the hex value for the public-key that you found in the transaction in the blockchain:

openssl ec -in pub.pem -pubin -text -noout

Now verify the message:

base64 -d sig.b64 > sig.der
openssl dgst -verify pub.pem -signature sig.der message.txt




Update:

The lie can be condensed into two images. In the first is excerpts from his post, where he claims the file "Sartre" has the specific sha256sum and contains the shown text:


But, we know that this checksum matches instead an intermediate step in the 2009 Bitcoin transaction, which if put in a file, would have the following contents:


The sha256sum result is the same in both cases, so either I'm lying or Craig Wright is. You can verify for yourself which one is lying by creating your own Sartre file from this base64 encoded data (copy/paste into file, then base64 -d > Sartre to create binary file).
AQAAAAG6kcHV5VqeL6tOQfVbhipzskcZqtE6Un0WnB+tO2O1EgEAAABDQQQR25Ph3NuKAWtJhA+MU7wetoo4LpexSC7K17FIppCaXLLg6t37hMz5dERk+C4WC/qbi2T51MA/mZuGQ/ZWtBKjrP////8CAMqaOwAAAABDQQS+2CfTdHS+/7N+/lM3AawffGAJV6RIe+izcTRvAWgm7m9XujDYikcqDk7NLwdZmnlfHwHeeNeRs4LmXuHFi0UIrADSSWsAAAAAQ0EEEduT4dzbigFrSYQPjFO8HraKOC6XsUguytexSKaQmlyy4Ord+4TM+XREZPguFgv6m4tk+dTAP5mbhkP2VrQSo6wAAAAAAQAAAA==
I got this file from https://rya.nc/sartre.html, after spending an hour looking for the right tool. Transactions are verified using a script within the transactions itself. At some intermediate step, it transmogrifies the transaction into something else, then verifies it. It's this transmogrified form of the transaction that we need to grab for the contents of the "Sartre" file.

Monday, May 02, 2016

Satoshi: That's not how any of this works

In this WIRED article, Gaven Andresen says why he believes Craig Wright's claim to be Satoshi Nakamoto:
“It’s certainly possible I was bamboozled,” Andresen says. “I could spin stories of how they hacked the hotel Wi-fi so that the insecure connection gave us a bad version of the software. But that just seems incredibly unlikely. It seems the simpler explanation is that this person is Satoshi.”
That's not how this works. That's not how any of this works.

The entire point of Bitcoin is that it's decentralized. We don't need to take Andresen's word for it. We don't need to take anybody's word for it. Nobody needs to fly to London and check it out on a private computer. Instead, you can just send somebody the signature, and they can verify it themselves. That the story was embargoed means nothing -- either way, Andresen was constrained by an NDA. Since they didn't do it the correct way, and were doing it the roundabout way, the simpler explanation is that he was being bamboozled.

Below is an example of this, using the Electrum Bitcoin wallet software:


This proves that the owner of the Bitcoin Address has signed the Message, producing the Signature. I typed the first two fields, hit the "Sign" button. The wallet looked up the address in my wallet (which can have many addresses), found the matching private key that only I posess, then signed the message by filling in the bottom window.

If you had reason to believe that this address belonged to Satoshi Nakamoto, such as if it had been the first blocks, then I would have just proven to you that I am indeed Satoshi. You wouldn't need to take anybody's word for it. You'd simply type in the fields (or copy/paste), hit "verify", and verify for yourself.

So you can verify me, here are the strings you can copy/paste:

Robert Graham is Satoshi Nakamoto
15fszyyM95UANiEeVa4H5L6va7Z7UFZCYP 
GyMgaHVszLSej/VuCdeXnMmiB/d6rBrghQ3qR6XvabZtBrzF8vOA1IW4MnhNfcLny1N15pSZw16JlmQWss7y3zM=
You should get either a "Signature verified" or "Wrong signature" message when you click the "Verify" button.


There may be a little strangeness since my original message is ASCII, but if you copy out of this webpage, it'll go in as Unicode, but it appears that this formatting information is ignored in the verification process, so it'll still work.

Summary

Occam's Razor is that Andresen was tricked. There was no reason to fly him to London otherwise. They could've just sent him an email with a message, a signature, and an address, and Andresen could've verified it himself.

Sunday, May 01, 2016

Touch Wipe: a question for you lawyers

Whether the police can force you to unlock your iPhone depends upon technicalities. They can't ask you for your passcode, because that would violate the 5th Amendment right against "self incrimination". On the other hand, they can force you to press your finger on the TouchID button, or (as it has been demonstrated) unlock the phone themselves using only your fingerprint.

So I propose adding a new technicality into the mix: "Touch Wipe". In addition to recording fingerprints to unlock the phone, Apple/Android should add the feature where users record fingerprints to wipe (erase) the phone. For example, I may choose my thumb to unlock, and my forefinger to wipe.

Indeed, I may record only one digit to unlock, and all nine remaining digits to wipe. Or even, I may decide to record all 10 digits on both hands to wipe, and not use Touch ID at all to unlock (relying solely on the passcode).

This now presents the problem for the police. They can't force me to unlock the phone. They can't get around that by using my fingerprints, because they might inadvertently destroy evidence.

The legal system is resilient against legal trickery such as this. If think you've figured out a way to beat the system, then it's usually because you just don't understand the system well enough. But I think I've figured out how to beat this system, so I write this up so that lawyers can explain why I'm wrong.


Wednesday, April 27, 2016

Who's your lawyer. Insights & Wisdom via HBO's Silicon Valley (S.3, E. 1)

The company's attorney may be your friend, but they're not your lawyer.  In this guest post, friend of Errata Elizabeth Wharton (@lawyerliz) looks at the common misconception highlighted in this week's Silicon Valley episode.

 
by Elizabeth Wharton


Amidst the usual startup shenanigans and inside-valley-jokes, HBO's Silicon Valley Season 3, Episode 1 contained a sharp reminder: lawyer loyalty runs with the "client," know whether you are the client.   A lawyer hired by a company has an entity as its client, not the individuals or officers of that company.  If you want an attorney then hire your own. 

Silicon Valley Season 3, Episode 1- Setting the Scene (without too many spoilers, I promise)
Upon learning of a board room ouster from the CEO to the CTO role, the startup company's founder Richard storms into the meeting with two board "friends" in tow (one, Ron, is the company's counsel).  As Richard burns the bridges of the offered CTO position and prepares for his dramatic exit, he turns to Ron and asks if he's ready to leave the meeting.  To the Richard's surprise, Ron calmly reminds Richard that he hired Ron to serve as corporate counsel on behalf of the company.  Ron goes further, explaining that their (the company's and Richard's) interests became adverse as soon as Richard included threats of litigation and payback against the board and the company  in his epic "From CEO to CTO? I Quit!" rant only a few moments before.   After letting this news sink in, Richard storms off to continue his rant elsewhere.

Insights from Richard's Gaffe (Don't be Richard)
While harsh, Ron's response highlights a common overlooked issue in startup companies:  a company and each of its founders and officers are treated as separate and distinct from the other.  This distinction, that a company is a separate entity from its individual co-founders, provides the basis for the liability protections and tax benefits with forming the company in the first place.  The layer of insulation between the company and the individuals extends both ways. Once a founder's idea or concept becomes a company, the idea's creator (the founder) and the company no longer share the same interests.  What benefits the individual founder may not be in the best interest of the company and vice-versa. As Richard discovered during the board room exchange, a board of directors must put the interests of the company above personal friendships with one of the company's founders.

Similarly, an attorney hired to form a company or provide corporate counsel for the company represents the company's interests and not those of the individuals who make up the company.  If the parties intend for the attorney to represent an individual co-founder instead of the company then the documents and engagement letter must reflect this distinction.  Understanding the attorney-client relationship and duties of loyalty is key when reviewing a term sheet, operating agreement, or any other agreement between individuals and/or a company.  Perspective and point of view in preparing and interpreting agreed upon terms revolve around the bias of the drafter.  The company's lawyer does not have a duty to point out to an individual founder, officer, or investor if the deal terms that benefit the company overall would in turn diminish an individual's personal interests.  If they're not your lawyer, then you're not the client that they're protecting.

Silicon Valley's Wisdom Takeaway: A lawyer's professional loyalty runs with their client. Even if they called you "Richie" only moments before, when you're not the client then counsel won't join your dramatic exit or  advise you on your next move. 


Elizabeth is a business and policy attorney specializing in information security and unmanned systems.  While Elizabeth is an attorney, nothing in this post is intended as legal advice.  If you need legal advice, get your own lawyer.  (An earlier version of Elizabeth's post first appeared via LinkedIn Pulse but has since been updated and expanded.)

Tuesday, April 26, 2016

My next scan

So starting next week, running for a week, I plan on scanning for ports 0-65535 (TCP). Each probe will be completely random selection of IP+port. The purpose is to answer the question about the most common open ports.

This would take a couple years to scan for all ports, so I'm not going to do that. But, scanning for a week should give me a good statistical sampling of 1% of the total possible combinations.

Specifically, the scan will open a connection and wait a few seconds for a banner. Protocols like FTP, SSH, and VNC reply first with data, before you send requests. Doing this should find such things lurking at odd ports. We know that port 22 is the most common for SSH, but what is the second most common?

Then, if I get no banner in response, I'll send an SSL "Hello" message. We know that port 443 is the most common SSL port, but what is the second most common?

In other words, by waiting for SSH, then sending SSL, I'll find SSH even it's on the (wrong) port of 443, and I'll find SSL even if it's on port 22. And all other ports, too.

Anyway, I point this out because people will start to see a lot of strange things in their logs. Also, I'm hoping that people will have suggestions before I start the scan for additional things to do during the scan.

Update: I'll be scanning from addresses between 209.126.230.70 and 209.126.230.78.



BTW, yes '0' is a valid port.

BTW, numbers larger than 65535 or smaller than 0 (negative numbers) aren't valid -- but they'll work in most applications because they simply use the lower 16-bits of any numbers that are given. Thus, port number -1 is just 65535, and port number 65536 is the same as 0.