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

QUESTION: use with webcrypto #61

Closed
brave-dev opened this issue Dec 5, 2015 · 13 comments
Closed

QUESTION: use with webcrypto #61

brave-dev opened this issue Dec 5, 2015 · 13 comments

Comments

@brave-dev
Copy link

let's say i'm using webcryptography in the browser and have some code like this:

    var payload = {}
    var combo = JSON.stringify({ ... })

    var ab2b = function (ab) {
        var buffer = []
        var view = new Uint8Array(ab)

        for (var i = 0; i < ab.byteLength; i++) buffer[i] = view[i]
        return buffer
    }

    var s2ab = function (s) {
        var buffer = new Uint8Array(s.length)

        for (var i = 0; i < s.length; i++) buffer[i] = s.charCodeAt(i)
        return buffer
    }

    var to_hex = function (bs) {
        var encoded = []

        for (var i = 0; i < bs.length; i++) {
            encoded.push('0123456789abcdef'[(bs[i] >> 4) & 15])
            encoded.push('0123456789abcdef'[bs[i] & 15])
        }
        return encoded.join('')
    }

    window.crypto.subtle.generateKey({ name: 'ECDSA', namedCurve: 'P-256' },
                                     true, [ 'sign', 'verify' ]).then(function (pair) {
        window.crypto.subtle.exportKey('raw', pair.publicKey).then(function (publicKey) {
            window.crypto.subtle.sign({ name: 'ECDSA', hash: { name: 'SHA-256' } },
                                      pair.privateKey, s2ab(combo)).then(function(signature) {
                payload.publicKey = to_hex(ab2b(publickKey)
                payload.signature = to_hex(ab2b(signature)
            })
        })
    })

what i am trying to figure out is how to take the two values in payload that contain hex-encoded strings and invoke key.verify() appropriately:

    var elliptic = require('elliptic').ec
    var ec = new elliptic('secp256k1')
    var options = { r: payload.signature.substr(0, 64), s: payload.signature.substr(64, 64) }

    var key = ec.keyFromPublic(payload.publicKey, 'hex')
    console.log(key.verify(combo, options, key, 'hex')

can you advise me as to how i should be calling KeyFromPublic and verify?

thanks!

/mtr

cc: @diracdeltas

@indutny
Copy link
Owner

indutny commented Dec 5, 2015

I think you may want to do key.verify(combo, options). There is no need to pass any other options to it.

Thanks!

@brave-dev
Copy link
Author

many thanks for the reply, but key.verify() still returns false.

if we are convinced that the signature produced by window.crypto.subtyle.sign is equal parts r & s, then i think the substr above would work.

any ideas?

@indutny
Copy link
Owner

indutny commented Dec 5, 2015

Aaah, I think you may want to try reverting the order of bytes in r and s. It looks like you made them little-endian, while elliptic expects them to be big-endian.

@brave-dev
Copy link
Author

hi. maybe that's still an issue, but i'm still seeing false with:

    var elliptic = require('elliptic').ec
    var ec = new elliptic('secp256k1')

    var reverse = function(s) {
      var array = []

      for (var i = s.length - 2; i >= 0; i -= 2) array.push(s.substr(i, 2))

      return array.join('')
    }

    var userId     = 'D023AB09-6435-4596-97F9-F3A032ED2F09'
     , message = 
    {
      "header": {
        "signature": "6b564408299a3860a8eb26cf022fb54979fcba9767777fbb6dbd25e9b516999d7147ae87e5ac4050ac57e8f9d5907a813db8d3ce3e3b06d5901f868697d5032d",
        "nonce": "1449272866.887"
      },
      "payload": {
        "version": 1,
        "publicKey": "04e9fd78f1d17c1c085f3928f4c1f421410889d8a7c07da4dc573797e6d96eedb5fe055f8d942aa25da07d0d85d2a042bdfbbdd14b98a9ad89bfe932442d163bac"
      }
    }
      , key        = ec.keyFromPublic(message.payload.publicKey, 'hex')
      , combo      = JSON.stringify({ userId: userId, nonce: message.header.nonce, payload: message.payload })
      , options    =
    { r: reverse(message.header.signature.substr(0, 64))
    , s: reverse(message.header.signature.substr(64, 64))
    }
    console.log(options)

    console.log(key.verify(combo, options))

@Kagami
Copy link
Contributor

Kagami commented Dec 5, 2015

This one works:

var createHash = require("crypto").createHash;
var EC = require("elliptic").ec;
var ec = new EC("p256");
var msg = Buffer("test");
var hash = createHash("sha256").update(msg).digest();
var alg = {name: "ECDSA", namedCurve: "P-256", hash: {name: "SHA-256"}};
function u8(a) { return new Uint8Array(a); }

crypto.subtle.generateKey(alg, true, ["sign"]).then(function(pair) {
  crypto.subtle.exportKey("raw", pair.publicKey).then(function (publicKey) {
    crypto.subtle.sign(alg, pair.privateKey, msg).then(function(sig) {
      var r = sig.slice(0, 32);
      var s = sig.slice(32);
      console.log(ec.verify(hash, {r: u8(r), s: u8(s)}, u8(publicKey)));
    });
  });
});

@brave-dev
Copy link
Author

many thanks. i am AFK right now, but will try this out ASAP!

@indutny
Copy link
Owner

indutny commented Dec 5, 2015

@Kagami this is very strange. May I ask you to provide me examples of hash, and sig?

@indutny
Copy link
Owner

indutny commented Dec 5, 2015

and publicKey for sure too.

@dconnolly
Copy link

@brave-dev: in your samples you generate a P-256 (aka secp256r1) keypair with webcrypto, then try to use it with secp256k1 (koblitz curve) with elliptic.js. AFAIK webcrypto api does not include the koblitz curves, so make sure you use p256 with elliptic.js.

@indutny
Copy link
Owner

indutny commented Dec 5, 2015

@dconnolly gosh, I totally missed it. You are right!

@dconnolly
Copy link

👍

@Kagami
Copy link
Contributor

Kagami commented Dec 5, 2015

@indutny

var createHash = require("crypto").createHash;
var EC = require("elliptic").ec;
var ec = new EC("p256");
var msg = Buffer("test");
var hash = createHash("sha256").update(msg).digest();
var alg = {name: "ECDSA", namedCurve: "P-256", hash: {name: "SHA-256"}};
function u8(a) { return new Uint8Array(a); }

crypto.subtle.generateKey(alg, true, ["sign"]).then(function(pair) {
  crypto.subtle.exportKey("raw", pair.publicKey).then(function (publicKey) {
    crypto.subtle.sign(alg, pair.privateKey, msg).then(function(sig) {
      var r = sig.slice(0, 32);
      var s = sig.slice(32);
      console.log(ec.verify(hash, {r: u8(r), s: u8(s)}, u8(publicKey)));
      console.log("HASH: " + hash.toString("hex"));
      console.log("SIG: " + Buffer(sig).toString("hex"));
      console.log("PKEY: " + Buffer(publicKey).toString("hex"));
    });
  });
});
true
HASH: 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
SIG: 9752408b0ddc7ff86c3654fff48f9f825cf7e32c1c22a728d44c685895892f4b02a853fb7e42465abfa7b8a6a2d46382f23adbaa58967116a80ec5fa063db293
PKEY: 0451c87f7b875959c7100e438d8530c202ece8f2a8164777b3d578f9ecf47d6cba4102e460f14b58aa282b396dbace037559517af90c4ea847d5841a56fc902e41

@brave-dev
Copy link
Author

@Kagami - thanks very much: that's a winner!

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