ecdsa: adhere strictly to RFC6979
The previous impl. was in breach of the following section: > Please note that when k is generated from T, the result of bits2int is > compared to q, not reduced modulo q. If the value is not between 1 and > q-1, the process loops. > Performing a simple modular reduction would induce biases that would be > detrimental to signature security.
This commit is contained in:
parent
d93623e2b1
commit
776656df8b
2 changed files with 27 additions and 8 deletions
33
src/ecdsa.js
33
src/ecdsa.js
|
@ -5,6 +5,7 @@ var BigInteger = require('bigi')
|
||||||
var ECSignature = require('./ecsignature')
|
var ECSignature = require('./ecsignature')
|
||||||
var Point = require('ecurve').Point
|
var Point = require('ecurve').Point
|
||||||
|
|
||||||
|
// https://tools.ietf.org/html/rfc6979#section-3.2
|
||||||
function deterministicGenerateK(curve, hash, d) {
|
function deterministicGenerateK(curve, hash, d) {
|
||||||
assert(Buffer.isBuffer(hash), 'Hash must be a Buffer, not ' + hash)
|
assert(Buffer.isBuffer(hash), 'Hash must be a Buffer, not ' + hash)
|
||||||
assert.equal(hash.length, 32, 'Hash must be 256 bit')
|
assert.equal(hash.length, 32, 'Hash must be 256 bit')
|
||||||
|
@ -13,22 +14,40 @@ function deterministicGenerateK(curve, hash, d) {
|
||||||
var x = d.toBuffer(32)
|
var x = d.toBuffer(32)
|
||||||
var k = new Buffer(32)
|
var k = new Buffer(32)
|
||||||
var v = new Buffer(32)
|
var v = new Buffer(32)
|
||||||
k.fill(0)
|
|
||||||
|
// Step B
|
||||||
v.fill(1)
|
v.fill(1)
|
||||||
|
|
||||||
|
// Step C
|
||||||
|
k.fill(0)
|
||||||
|
|
||||||
|
// Step D
|
||||||
k = crypto.HmacSHA256(Buffer.concat([v, new Buffer([0]), x, hash]), k)
|
k = crypto.HmacSHA256(Buffer.concat([v, new Buffer([0]), x, hash]), k)
|
||||||
|
|
||||||
|
// Step E
|
||||||
v = crypto.HmacSHA256(v, k)
|
v = crypto.HmacSHA256(v, k)
|
||||||
|
|
||||||
|
// Step F
|
||||||
k = crypto.HmacSHA256(Buffer.concat([v, new Buffer([1]), x, hash]), k)
|
k = crypto.HmacSHA256(Buffer.concat([v, new Buffer([1]), x, hash]), k)
|
||||||
v = crypto.HmacSHA256(v, k)
|
|
||||||
|
// Step G
|
||||||
v = crypto.HmacSHA256(v, k)
|
v = crypto.HmacSHA256(v, k)
|
||||||
|
|
||||||
var n = curve.n
|
// Step H1/H2a, ignored as tlen === qlen (256 bit)
|
||||||
var kB = BigInteger.fromBuffer(v).mod(n)
|
// Step H2b
|
||||||
assert(kB.compareTo(BigInteger.ONE) > 0, 'Invalid k value')
|
v = crypto.HmacSHA256(v, k)
|
||||||
assert(kB.compareTo(n) < 0, 'Invalid k value')
|
|
||||||
|
|
||||||
return kB
|
var T = BigInteger.fromBuffer(v)
|
||||||
|
|
||||||
|
// Step H3, repeat until T is within the interval [0, n - 1]
|
||||||
|
while ((T.signum() <= 0) || (T.compareTo(curve.n) >= 0)) {
|
||||||
|
k = crypto.HmacSHA256(Buffer.concat([v, new Buffer([0])]), k)
|
||||||
|
v = crypto.HmacSHA256(v, k)
|
||||||
|
|
||||||
|
T = BigInteger.fromBuffer(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return T
|
||||||
}
|
}
|
||||||
|
|
||||||
function sign(curve, hash, d) {
|
function sign(curve, hash, d) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ var fixtures = require('./fixtures/ecdsa.json')
|
||||||
describe('ecdsa', function() {
|
describe('ecdsa', function() {
|
||||||
describe('deterministicGenerateK', function() {
|
describe('deterministicGenerateK', function() {
|
||||||
fixtures.valid.forEach(function(f) {
|
fixtures.valid.forEach(function(f) {
|
||||||
it('determines k for \"' + f.message + '\"', function() {
|
it('for \"' + f.message + '\"', function() {
|
||||||
var d = BigInteger.fromHex(f.d)
|
var d = BigInteger.fromHex(f.d)
|
||||||
var h1 = crypto.sha256(f.message)
|
var h1 = crypto.sha256(f.message)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue