lightning / bolts

BOLT: Basis of Lightning Technology (Lightning Network Specifications)
2.06k stars 490 forks source link

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

Open TACIXAT opened 5 years ago

TACIXAT commented 5 years ago

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 commented 5 years ago

@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 commented 5 years ago

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. U2F has a very different security model from lightning/Bitcoin in that regard. Bending over backwards to support generic U2F just to get more competition in hardware wallets where they will generally never be as good as Bitcoin-targeted ones seems to be significantly more effort than it's worth.

On Dec 15, 2018, at 23:52, Mycrypto notifications@github.com wrote:

@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.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub, or mute the thread.

TACIXAT commented 5 years ago

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 commented 5 years ago

MyGoldWallet Card_ver 3.5 20180920.pdf

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