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

Enable U2F tokens as hardware wallets / Support curve secp256r1 (p256) #535

Open
TACIXAT opened this issue Dec 15, 2018 · 4 comments
Open

Comments

@TACIXAT
Copy link

TACIXAT commented Dec 15, 2018

What are U2F tokens?

U2F stands for universal second factor. They are small USB / NFC / BT devices that confirm the presence of a user. If passwords are something you know, U2F tokens are something you have. They add a second layer of security to accounts.

https://en.wikipedia.org/wiki/Universal_2nd_Factor

The FIDO specification was created to allow untrusted parties (websites that want to track you) to store a public key and key handle that correspond to a U2F token. A single U2F token can create infinite (? this doesn't sound right to me, but let's just say effectively many) public keys and key handles. When a website needs to authenticate, they send down the public key and key handle associated with that account. The U2F tokens will sign a challenge with the corresponding private key.

Why is this fucking awesome?

Alright, we have a device that can have info stored in a public place (likeamotherfuckingblockchain!) and can sign challenges (likeamotherfuckingtransaction!). All that and the user doesn't have the private key. That means you could hand someone a U2F token and you would be effectively transferring them your wallet, much like a cash transaction.

Why is this gonna be controversial?

The secp256r1 curve is a NIST curve. They chose some parameters that cause people to speculate that NASA might have a backdoor in it. This is unconfirmed, but I get why people are suspicious. Let's look at the issue though. Is the US govvie gonna burn a serious crypto flaw to steal your magical internet money? Maybe, but I think they have bigger priorities.

Hell, if we're speculating I'd like to throw an idea out there, maybe BTC was a CIA black budget project, or maybe they wanted other countries to adopt it to control a piece of their economy, or even destabilize their primary currency. Much like Universal Basic Income, if they were against it, we'd probably be seeing some different action.

You also never know if that speculation is disinfo, maybe they have a backdoor in the simplified k curve and rumor the r curve to be fucked up so we adopt the k curve.

The point of this rant is we don't know. We can be aware of the risks and the users can take that risk upon themselves. This will give us a way to hand people money in off chain transactions and that will be fucking sick.

How do we do this?

Support the elliptic curve secp256r1. Bitcoin and just about every other crypto currency uses secp256k1 (k is for koblitz). Make it possible to store the public key and key handle in the network (or on the BTC blockchain), you could either let it be associated with a wallet name or just have users keep track of the pubby keys.

When browsers use U2F tokens they send down the "app name" which is usually their web address. This enforces same origin and prevents phishing. This kinda fucks it up but not really, cause we can just make a desktop client and send whichever app name we want. I'll post some sample Go code to make it clear.

We need compatibility with normal ECDSA signatures, but the U2F tokens sign some extra data (app name, human presence, usage counter), so we need to store that too. The App is the sha256 of an application name. Extra is 5 bytes, for normal signatures it can be whatever. In the case of U2F tokens, it's a user presence byte and then 4 bytes of counter for how many times the token has been used. This data can be parsed out of the response from the token. R and S are normal crypto signature shit. Same same for PublicKey.

type Signature struct {
	App       []byte `json:"app"`
	Extra     []byte `json:"extra"`
	R         []byte `json:"r"`
	S         []byte `json:"s"`
	PublicKey []byte `json:"public_key"`
}

So a U2F token signature function would look something like this.

func U2FSign(ks KeyStore, challenge []byte) Signature {
	keyHandle := ks.KeyHandle

	// get physical device
	t, dev := U2FGetToken()

	// create a request with the challenge (hash of your transaction or w/e)
	req := u2ftoken.AuthenticateRequest{
		Challenge:   challenge,
		Application: app,
		KeyHandle:   keyHandle,
	}

	// make sure the key handle belongs to this device
	err := t.CheckAuthenticate(req)
	if err != nil {
		log.Fatal(err)
	}

	// sign the challenge
	log.Println("signing, provide user presence")
	var res *u2ftoken.AuthenticateResponse
	for {
		res, err = t.Authenticate(req)
		if err == u2ftoken.ErrPresenceRequired {
			time.Sleep(200 * time.Millisecond)
			continue
		} else if err != nil {
			log.Fatal(err)
		}
		log.Printf("counter = %d, signature = %x", res.Counter, res.Signature)
		break
	}

	dev.Close()

	// get our cryptoshit
	r, s := ExtractRS(res.Signature)

	// create our signature object
	sig := Signature{}
	sig.App = app
	sig.Extra = res.RawResponse[:5]
	sig.R = r.Bytes()
	sig.S = s.Bytes()
	sig.PublicKey = ks.PublicKey

	return sig
}

The equivalent with soft ECDSA to show what the U2F token is doing with the app and extra params.

func ECDSASign(ks KeyStore, challenge []byte) Signature {
	// just use null bytes for extra, this can be w/e tho
	extra := []byte{0, 0, 0, 0, 0}

	// mimic the u2f challenge with app, extra, and the challenge
	hash := sha256.New()
	hash.Write(app)
	hash.Write(extra)
	hash.Write(challenge)
	check := hash.Sum(nil)

	// use our nasa backdoor'd curve
	p256 := elliptic.P256()

	// create soft ecdsa key from asn1 pubkey
	x, y := elliptic.Unmarshal(p256, ks.PublicKey)
	pub := ecdsa.PublicKey{
		Curve: p256,
		X:     x,
		Y:     y,
	}

	// create soft private key from our pubkey and d bytes
	d := new(big.Int)
	d.SetBytes(ks.PrivateKey)
	prv := &ecdsa.PrivateKey{
		PublicKey: pub,
		D:         d,
	}

	// sign that shit
	r, s, err := ecdsa.Sign(rand.Reader, prv, check[:])
	if err != nil {
		log.Fatal(err)
	}

	// store it in our siggie
	sig := Signature{}
	sig.App = app
	sig.Extra = extra
	sig.R = r.Bytes()
	sig.S = s.Bytes()
	sig.PublicKey = ks.PublicKey

	return sig
}

Verification to tie things together.

func VerifySignature(challenge []byte, sig Signature) bool {
	// nasa backdoor lol
	p256 := elliptic.P256()

	// pub to pubkey
	x, y := elliptic.Unmarshal(p256, sig.PublicKey)
	pubKey := &ecdsa.PublicKey{Curve: p256, X: x, Y: y}


	// buffer 
	data := make([]byte, 0)

	// stuff we sha256
	data = append(data, sig.App...)
	data = append(data, sig.Extra...)
	data = append(data, challenge...)

	// our hash
	hash := sha256.Sum256(data)

	// get r and s
	r := big.Int{}
	r.SetBytes(sig.R)
	s := big.Int{}
	s.SetBytes(sig.S)

	return ecdsa.Verify(pubKey, hash[:], &r, &s)
}

What would a user transaction flow look like?

I imagine this like a sick cybepunk scene where two super hackers pull out their laptops and plug in their tokens to do some shady ass deal.

Payer: Send a small amount of money to a burn address to prove a token owns a wallet.
Payee: Verify that wallet does not have any other keys associated with it.
Payer: Hand over U2F token.
Payee: Verify U2F token handed to them authenticates with the corresponding key handle and public key.
Payee: Exchange warez or deeds.

Why are you releasing this idea rather than being a greedy fuck and filing a patent and making gorillians?

I started working on my own cryptocurrency. I wanted it to be fast so I was using DPoS. I was gonna support the right curves. I was gonna have voting so users could burn or quench per transactions as a means of monetary policy. But yea, there are a lot of cryptocurrencies. There are a lot of politics around consensus algorithms. It just felt like I would be pissing in a sea of piss so I'm working on some other shit instead.

So yea, BTC is a pretty cool guy. Lightning network could be cool. I really fucking hate the high transaction fees I see online (2.9% + 30 cents). I think if we can enable low fee microtransactions we can move away from the surveillance capitalism and adtech psychological warfare and into an age where we can get digital media for a reasonable fucking price. I'd rather see this world come to fruition than horde an idea.

As an alternative, if anyone wants to get sued by Yubico, we should clone their U2F tokens but swap out the curves. I know there are a bunch of Chinese motherfuckers in this space and you guys know a thing or two about manufacturing (你好网友!). I'd happily work on the firmware layer for this as long as we can make some fucking bank $$$.

Wow, you're so brilliant

Hell yea, I like monies.

BTC tips: 358seJQbXFEqWD6fXprhi4ZpHR36KAK7ga
ETH tips: 0x3D12CEE7C63DC1e488bE0e5B4A0a42D89f70bC0a

(I'm a peasant that uses coinbase, so I can't receive BCH or ETC to those addies, noburnplz)

@Mycrypto
Copy link

@TACIXAT So in regards to this - "if anyone wants to get sued by Yubico, we should clone their U2F tokens but swap out the curves" have you heard of OnlyKey? It already supports both U2F and secp256k1 plus it's open source *full disclosure I work on the project. If your interested in building this feature it would definitely be doable. Also you would not have to use a desktop app. We built a web app that can use the U2F protocol to send really any data, right now it's used for OpenPGP but could be used in the same way for transactions.

@TheBlueMatt
Copy link
Collaborator

TheBlueMatt commented Dec 16, 2018 via email

@TACIXAT
Copy link
Author

TACIXAT commented Dec 16, 2018

Hardware wallets which are not able to display any information about where your money is going or even how money is being sent are generally considered very bad ideas.

Having a hardware wallet that makes the keys inaccessible allows for transferring that device between users. For transactions, yea, you don't want to use a terminal in a super market (same threat model as debit cards getting skimmed), but you could absolutely use your phone or laptop for the transaction and trust the software and hardware that's running on it. At the same time, it being transferable (and relatively cheap) will allow the devices to become a form of physical currency.

@brianbkkim
Copy link

MyGoldWallet Card_ver 3.5 20180920.pdf

See if you can work with us, the fingerprint authenticated credit card H/W wallet
ssen wallet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants