Expands truncated little-endian parameters in EdDSA

This commit is contained in:
Mahrud Sayrafi 2018-02-02 05:42:54 -08:00
parent 9cbfbf453b
commit 3370eaa2aa
No known key found for this signature in database
GPG Key ID: C24071B956C3245F
8 changed files with 60 additions and 26 deletions

View File

@ -95,7 +95,8 @@ const curves = {
ed25519: {
oid: util.bin2str([0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01]),
keyType: enums.publicKey.eddsa,
hash: enums.hash.sha512
hash: enums.hash.sha512,
payloadSize: 32
},
curve25519: {
oid: util.bin2str([0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01]),

View File

@ -18,11 +18,11 @@
// Key encryption and decryption for RFC 6637 ECDH
/**
* @requires crypto/hash
* @requires crypto/cipher
* @requires crypto/aes_kw
* @requires crypto/public_key/elliptic/curves
* @requires crypto/public_key/jsbn
* @requires crypto/cipher
* @requires crypto/hash
* @requires crypto/aes_kw
* @requires type/oid
* @requires type/kdf_params
* @requires enums
@ -32,15 +32,15 @@
'use strict';
import BigInteger from '../jsbn.js';
import curves from './curves.js';
import curves from './curves';
import BigInteger from '../jsbn';
import cipher from '../../cipher';
import hash from '../../hash';
import aes_kw from '../../aes_kw.js';
import enums from '../../../enums.js';
import util from '../../../util.js';
import type_kdf_params from '../../../type/kdf_params.js';
import type_oid from '../../../type/oid.js';
import aes_kw from '../../aes_kw';
import type_kdf_params from '../../../type/kdf_params';
import type_oid from '../../../type/oid';
import enums from '../../../enums';
import util from '../../../util';
// Build Param for ECDH algorithm (RFC 6637)

View File

@ -27,8 +27,8 @@
'use strict';
import hash from '../../hash';
import curves from './curves.js';
import BigInteger from '../jsbn.js';
import curves from './curves';
import BigInteger from '../jsbn';
/**
* Sign a message using the provided key

View File

@ -27,8 +27,8 @@
'use strict';
import hash from '../../hash';
import curves from './curves.js';
import BigInteger from '../jsbn.js';
import curves from './curves';
import BigInteger from '../jsbn';
/**
* Sign a message using the provided key
@ -60,8 +60,10 @@ async function sign(oid, hash_algo, m, d) {
async function verify(oid, hash_algo, signature, m, Q) {
const curve = curves.get(oid);
const key = curve.keyFromPublic(Q.toByteArray());
const R = signature.r.toByteArray(), S = signature.s.toByteArray();
return key.verify(
m, { R: signature.r.toByteArray(), S: signature.s.toByteArray() }, hash_algo
m, { R: Array(curve.payloadSize - R.length).fill(0).concat(R),
S: Array(curve.payloadSize - S.length).fill(0).concat(S) }, hash_algo
);
}

View File

@ -18,21 +18,22 @@
// Wrapper for a KeyPair of an Elliptic Curve
/**
* @requires bn.js
* @requires asn1.js
* @requires jwk-to-pem
* @requires crypto/public_key/elliptic/curves
* @requires crypto/public_key/jsbn
* @requires crypto/hash
* @requires util
* @requires enums
* @requires config
* @requires encoding/base64
* @requires jwk-to-pem
* @requires asn1.js
* @module crypto/public_key/elliptic/key
*/
'use strict';
import curves from './curves';
import BigInteger from '../jsbn';
import hash from '../../hash';
import util from '../../../util';
import enums from '../../../enums';
@ -44,7 +45,6 @@ const webCurves = curves.webCurves;
const nodeCrypto = util.getNodeCrypto();
const nodeCurves = curves.nodeCurves;
const BN = nodeCrypto ? require('bn.js') : undefined;
const jwkToPem = nodeCrypto ? require('jwk-to-pem') : undefined;
const ECDSASignature = nodeCrypto ?
require('asn1.js').define('ECDSASignature', function() {
@ -167,8 +167,8 @@ async function webSign(curve, hash_algo, message, keyPair) {
async function webVerify(curve, hash_algo, {r, s}, message, publicKey) {
var l = curve.payloadSize;
r = (r.length === l) ? r : [0].concat(r);
s = (s.length === l) ? s : [0].concat(s);
r = Array(l - r.length).fill(0).concat(r);
s = Array(l - s.length).fill(0).concat(s);
var signature = new Uint8Array(r.concat(s)).buffer;
const key = await webCrypto.importKey(
"jwk",
@ -227,7 +227,7 @@ async function nodeSign(curve, hash_algo, message, keyPair) {
}
async function nodeVerify(curve, hash_algo, {r, s}, message, publicKey) {
var signature = ECDSASignature.encode({ r: new BN(r), s: new BN(s) }, 'der');
var signature = ECDSASignature.encode({ r: new BigInteger(r), s: new BigInteger(s) }, 'der');
const key = jwkToPem(
{
"kty": "EC",

View File

@ -37,7 +37,7 @@
* @module crypto/public_key/jsbn
*/
import util from '../../util.js';
import util from '../../util';
// Basic JavaScript BN library - subset useful for RSA encryption.
@ -53,7 +53,7 @@ var j_lm = ((canary & 0xffffff) == 0xefcafe);
export default function BigInteger(a, b, c) {
if (a != null)
if ("number" == typeof a) this.fromNumber(a, b, c);
else if (b == null && "string" != typeof a) this.fromString(a, 256);
else if (b == null && !util.isString(a)) this.fromString(a, 256);
else this.fromString(a, b);
}

View File

@ -1224,6 +1224,7 @@ describe('OpenPGP.js public api tests', function() {
});
});
// FIXME this test sporadically fails
it('should encrypt and decrypt with two passwords', function() {
var encOpt = {
data: plaintext,

View File

@ -107,6 +107,7 @@ describe('X25519 Cryptography', function () {
'-----END PGP MESSAGE-----'].join('\n')
}
};
function load_pub_key(name) {
if (data[name].pub_key) {
return data[name].pub_key;
@ -269,7 +270,6 @@ describe('X25519 Cryptography', function () {
var msg = openpgp.cleartext.readArmored(signed.data);
// Verifying signed message
return Promise.all([
// FIXME this test sporadically fails
openpgp.verify(
{ message: msg, publicKeys: hi.toPublic() }
).then(output => expect(output.signatures[0].valid).to.be.true),
@ -302,4 +302,34 @@ describe('X25519 Cryptography', function () {
});
});
});
it('Should handle little-endian parameters in EdDSA', function () {
var pubKey = [
'-----BEGIN PGP PUBLIC KEY BLOCK-----',
'Version: OpenPGP.js VERSION',
'Comment: https://openpgpjs.org',
'',
'xjMEWnRgnxYJKwYBBAHaRw8BAQdAZ8gxxCdUxIv4tBwhfUMW2uoEb1KvOfP8',
'D+0ObBtsLnfNDkhpIDxoaUBoZWwubG8+wnYEEBYKACkFAlp0YJ8GCwkHCAMC',
'CRDAYsFlymHCFQQVCAoCAxYCAQIZAQIbAwIeAQAAswsA/3qNZnwBn/ef4twv',
'uvmFicYK//DDX1jIkpDiQ+/okLUEAPdAr3J/Z2WA7OD0d36trHNB06WLXJUu',
'aCVm1TwoJHcNzjgEWnRgnxIKKwYBBAGXVQEFAQEHQPBVH+skap0NHMBw2HMe',
'xWYUQ67I9Did3KoJuuEJ/ctQAwEIB8JhBBgWCAATBQJadGCfCRDAYsFlymHC',
'FQIbDAAAhNQBAKmy4gPorjbwTwy5usylHttP28XnTdaGkZ1E7Rc3G9luAQCs',
'Gbm1oe83ZB+0aSp5m34YkpHQNb80y8PGFy7nIexiAA==',
'=xeG/',
'-----END PGP PUBLIC KEY BLOCK-----'].join('\n');
var hi = openpgp.key.readArmored(pubKey).keys[0];
return hi.verifyPrimaryUser().then(() => {
var results = hi.getPrimaryUser();
expect(results.user).to.exist;
var user = results.user;
expect(user.selfCertifications[0].verify(
hi.primaryKey, {userid: user.userId, key: hi.primaryKey}
)).to.eventually.be.true;
expect(user.verifyCertificate(
hi.primaryKey, user.selfCertifications[0], [hi]
)).to.eventually.equal(openpgp.enums.keyStatus.valid);
});
});
});