Signature creation and verification
This commit is contained in:
parent
a8e8271185
commit
ba2f49234e
66
src/crypto/public_key/elliptic/ecdsa.js
Normal file
66
src/crypto/public_key/elliptic/ecdsa.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
// OpenPGP.js - An OpenPGP implementation in javascript
|
||||
// Copyright (C) 2015-2016 Decentral
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; either
|
||||
// version 3.0 of the License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
// Implementation of ECDSA following RFC6637 for Openpgpjs
|
||||
|
||||
/**
|
||||
* @requires crypto/public_key/jsbn
|
||||
* @requires crypto/public_key/elliptic/curves
|
||||
* @module crypto/public_key/elliptic/ecdsa
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import curves from './curves.js';
|
||||
import BigInteger from '../jsbn.js';
|
||||
|
||||
/**
|
||||
* Sign a message using the provided key
|
||||
* @param {String} oid Elliptic curve for the key
|
||||
* @param {enums.hash} hash_algo Hash algorithm used to sign
|
||||
* @param {Uint8Array} m Message to sign
|
||||
* @param {BigInteger} w Private key used to sign
|
||||
* @return {{r: BigInteger, s: BigInteger}} Signature of the message
|
||||
*/
|
||||
function sign(oid, hash_algo, m, w) {
|
||||
const curve = curves.get(oid);
|
||||
const key = curve.keyFromPrivate(w.toByteArray());
|
||||
const signature = key.sign(m, hash_algo);
|
||||
return {
|
||||
r: new BigInteger(signature.r),
|
||||
s: new BigInteger(signature.s)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if a signature is valid for a message
|
||||
* @param {String} oid Elliptic curve for the key
|
||||
* @param {enums.hash} hash_algo Hash algorithm used in the signature
|
||||
* @param {{r: BigInteger, s: BigInteger}} signature Signature to verify
|
||||
* @param {Uint8Array} m Message to verify
|
||||
* @param {BigInteger} gw Public key used to verify the message
|
||||
*/
|
||||
function verify(oid, hash_algo, signature, m, gw) {
|
||||
const curve = curves.get(oid);
|
||||
const key = curve.keyFromPublic(gw.toByteArray());
|
||||
return key.verify(m, {r: signature.r.toByteArray(), s: signature.s.toByteArray()}, hash_algo);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sign: sign,
|
||||
verify: verify
|
||||
};
|
|
@ -26,8 +26,10 @@
|
|||
'use strict';
|
||||
|
||||
import {get, generate} from './curves.js';
|
||||
import ecdsa from './ecdsa.js';
|
||||
|
||||
module.exports = {
|
||||
ecdsa: ecdsa,
|
||||
get: get,
|
||||
generate: generate
|
||||
};
|
||||
|
|
|
@ -4,6 +4,13 @@ var openpgp = typeof window !== 'undefined' && window.openpgp ? window.openpgp :
|
|||
|
||||
var expect = require('chai').expect;
|
||||
|
||||
var bin2bi = function (bytes) {
|
||||
var mpi = new openpgp.MPI();
|
||||
bytes = openpgp.util.bin2str(bytes);
|
||||
mpi.fromBytes(bytes);
|
||||
return mpi.toBigInteger();
|
||||
};
|
||||
|
||||
describe('Elliptic Curve Cryptography', function () {
|
||||
var elliptic_curves = openpgp.crypto.publicKey.elliptic;
|
||||
var key_data = {
|
||||
|
@ -193,4 +200,95 @@ describe('Elliptic Curve Cryptography', function () {
|
|||
done();
|
||||
});
|
||||
});
|
||||
describe('ECDSA signature', function () {
|
||||
var verify_signature = function (oid, hash, r, s, pub, message) {
|
||||
if (openpgp.util.isString(message)) {
|
||||
message = openpgp.util.str2Uint8Array(message);
|
||||
} else if (!openpgp.util.isUint8Array(message)) {
|
||||
message = new Uint8Array(message);
|
||||
}
|
||||
return function () {
|
||||
var ecdsa = elliptic_curves.ecdsa;
|
||||
return ecdsa.verify(oid,
|
||||
hash,
|
||||
{r: bin2bi(r), s: bin2bi(s)},
|
||||
message,
|
||||
bin2bi(pub)
|
||||
);
|
||||
};
|
||||
};
|
||||
var secp256k1_dummy_value = new Uint8Array([
|
||||
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||
var secp256k1_dummy_point = new Uint8Array([0x04,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||
var secp256k1_invalid_point = new Uint8Array([0x04,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||
it('Invalid curve oid', function (done) {
|
||||
var res = verify_signature('invalid oid', 8, [], [], [], []);
|
||||
expect(res).to.throw(Error, /Not valid curve/);
|
||||
res = verify_signature("\x00", 8, [], [], [], []);
|
||||
expect(res).to.throw(Error, /Not valid curve/);
|
||||
done();
|
||||
});
|
||||
it('Invalid public key', function (done) {
|
||||
var res = verify_signature('secp256k1', 8, [], [], [], []);
|
||||
expect(res).to.throw(Error, /Unknown point format/);
|
||||
res = verify_signature('secp256k1', 8, [], [], secp256k1_invalid_point, []);
|
||||
expect(res).to.throw(Error, /Unknown point format/);
|
||||
done();
|
||||
});
|
||||
it('Invalid signature', function (done) {
|
||||
var res = verify_signature('secp256k1', 8, [], [], secp256k1_dummy_point, []);
|
||||
expect(res()).to.be.false;
|
||||
done();
|
||||
});
|
||||
|
||||
var p384_message = new Uint8Array([
|
||||
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]);
|
||||
var p384_r = new Uint8Array([
|
||||
0x9D, 0x07, 0xCA, 0xA5, 0x9F, 0xBE, 0xB8, 0x76,
|
||||
0xA9, 0xB9, 0x66, 0x0F, 0xA0, 0x64, 0x70, 0x5D,
|
||||
0xE6, 0x37, 0x40, 0x43, 0xD0, 0x8E, 0x40, 0xA8,
|
||||
0x8B, 0x37, 0x83, 0xE7, 0xBC, 0x1C, 0x4C, 0x86,
|
||||
0xCB, 0x3C, 0xD5, 0x9B, 0x68, 0xF0, 0x65, 0xEB,
|
||||
0x3A, 0xB6, 0xD6, 0xA6, 0xCF, 0x85, 0x3D, 0xA9]);
|
||||
var p384_s = new Uint8Array([
|
||||
0x32, 0x85, 0x78, 0xCC, 0xEA, 0xC5, 0x22, 0x83,
|
||||
0x10, 0x73, 0x1C, 0xCF, 0x10, 0x8A, 0x52, 0x11,
|
||||
0x8E, 0x49, 0x9E, 0xCF, 0x7E, 0x17, 0x18, 0xC3,
|
||||
0x11, 0x11, 0xBC, 0x0F, 0x6D, 0x98, 0xE2, 0x16,
|
||||
0x68, 0x58, 0x23, 0x1D, 0x11, 0xEF, 0x3D, 0x21,
|
||||
0x30, 0x75, 0x24, 0x39, 0x48, 0x89, 0x03, 0xDC]);
|
||||
it('Valid signature', function (done) {
|
||||
var res = verify_signature('p384', 8, p384_r, p384_s, key_data.p384.pub, p384_message);
|
||||
expect(res()).to.be.true;
|
||||
done();
|
||||
});
|
||||
it('Sign and verify message', function (done) {
|
||||
var curve = elliptic_curves.get('p521');
|
||||
var keyPair = curve.genKeyPair();
|
||||
var keyPublic = bin2bi(keyPair.getPublic());
|
||||
var keyPrivate = bin2bi(keyPair.getPrivate());
|
||||
var oid = curve.oid;
|
||||
var message = p384_message;
|
||||
var signature = elliptic_curves.ecdsa.sign(oid, 10, message, keyPrivate);
|
||||
var verified = elliptic_curves.ecdsa.verify(oid, 10, signature, message, keyPublic);
|
||||
expect(verified).to.be.true;
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user