Expands truncated little-endian parameters in EdDSA
This commit is contained in:
parent
9cbfbf453b
commit
3370eaa2aa
|
@ -95,7 +95,8 @@ const curves = {
|
||||||
ed25519: {
|
ed25519: {
|
||||||
oid: util.bin2str([0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01]),
|
oid: util.bin2str([0x2B, 0x06, 0x01, 0x04, 0x01, 0xDA, 0x47, 0x0F, 0x01]),
|
||||||
keyType: enums.publicKey.eddsa,
|
keyType: enums.publicKey.eddsa,
|
||||||
hash: enums.hash.sha512
|
hash: enums.hash.sha512,
|
||||||
|
payloadSize: 32
|
||||||
},
|
},
|
||||||
curve25519: {
|
curve25519: {
|
||||||
oid: util.bin2str([0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01]),
|
oid: util.bin2str([0x2B, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01]),
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
// Key encryption and decryption for RFC 6637 ECDH
|
// 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/elliptic/curves
|
||||||
* @requires crypto/public_key/jsbn
|
* @requires crypto/public_key/jsbn
|
||||||
|
* @requires crypto/cipher
|
||||||
|
* @requires crypto/hash
|
||||||
|
* @requires crypto/aes_kw
|
||||||
* @requires type/oid
|
* @requires type/oid
|
||||||
* @requires type/kdf_params
|
* @requires type/kdf_params
|
||||||
* @requires enums
|
* @requires enums
|
||||||
|
@ -32,15 +32,15 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import BigInteger from '../jsbn.js';
|
import curves from './curves';
|
||||||
import curves from './curves.js';
|
import BigInteger from '../jsbn';
|
||||||
import cipher from '../../cipher';
|
import cipher from '../../cipher';
|
||||||
import hash from '../../hash';
|
import hash from '../../hash';
|
||||||
import aes_kw from '../../aes_kw.js';
|
import aes_kw from '../../aes_kw';
|
||||||
import enums from '../../../enums.js';
|
import type_kdf_params from '../../../type/kdf_params';
|
||||||
import util from '../../../util.js';
|
import type_oid from '../../../type/oid';
|
||||||
import type_kdf_params from '../../../type/kdf_params.js';
|
import enums from '../../../enums';
|
||||||
import type_oid from '../../../type/oid.js';
|
import util from '../../../util';
|
||||||
|
|
||||||
|
|
||||||
// Build Param for ECDH algorithm (RFC 6637)
|
// Build Param for ECDH algorithm (RFC 6637)
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import hash from '../../hash';
|
import hash from '../../hash';
|
||||||
import curves from './curves.js';
|
import curves from './curves';
|
||||||
import BigInteger from '../jsbn.js';
|
import BigInteger from '../jsbn';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign a message using the provided key
|
* Sign a message using the provided key
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import hash from '../../hash';
|
import hash from '../../hash';
|
||||||
import curves from './curves.js';
|
import curves from './curves';
|
||||||
import BigInteger from '../jsbn.js';
|
import BigInteger from '../jsbn';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign a message using the provided key
|
* 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) {
|
async function verify(oid, hash_algo, signature, m, Q) {
|
||||||
const curve = curves.get(oid);
|
const curve = curves.get(oid);
|
||||||
const key = curve.keyFromPublic(Q.toByteArray());
|
const key = curve.keyFromPublic(Q.toByteArray());
|
||||||
|
const R = signature.r.toByteArray(), S = signature.s.toByteArray();
|
||||||
return key.verify(
|
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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,21 +18,22 @@
|
||||||
// Wrapper for a KeyPair of an Elliptic Curve
|
// 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/elliptic/curves
|
||||||
|
* @requires crypto/public_key/jsbn
|
||||||
* @requires crypto/hash
|
* @requires crypto/hash
|
||||||
* @requires util
|
* @requires util
|
||||||
* @requires enums
|
* @requires enums
|
||||||
* @requires config
|
* @requires config
|
||||||
* @requires encoding/base64
|
* @requires encoding/base64
|
||||||
|
* @requires jwk-to-pem
|
||||||
|
* @requires asn1.js
|
||||||
* @module crypto/public_key/elliptic/key
|
* @module crypto/public_key/elliptic/key
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import curves from './curves';
|
import curves from './curves';
|
||||||
|
import BigInteger from '../jsbn';
|
||||||
import hash from '../../hash';
|
import hash from '../../hash';
|
||||||
import util from '../../../util';
|
import util from '../../../util';
|
||||||
import enums from '../../../enums';
|
import enums from '../../../enums';
|
||||||
|
@ -44,7 +45,6 @@ const webCurves = curves.webCurves;
|
||||||
const nodeCrypto = util.getNodeCrypto();
|
const nodeCrypto = util.getNodeCrypto();
|
||||||
const nodeCurves = curves.nodeCurves;
|
const nodeCurves = curves.nodeCurves;
|
||||||
|
|
||||||
const BN = nodeCrypto ? require('bn.js') : undefined;
|
|
||||||
const jwkToPem = nodeCrypto ? require('jwk-to-pem') : undefined;
|
const jwkToPem = nodeCrypto ? require('jwk-to-pem') : undefined;
|
||||||
const ECDSASignature = nodeCrypto ?
|
const ECDSASignature = nodeCrypto ?
|
||||||
require('asn1.js').define('ECDSASignature', function() {
|
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) {
|
async function webVerify(curve, hash_algo, {r, s}, message, publicKey) {
|
||||||
var l = curve.payloadSize;
|
var l = curve.payloadSize;
|
||||||
r = (r.length === l) ? r : [0].concat(r);
|
r = Array(l - r.length).fill(0).concat(r);
|
||||||
s = (s.length === l) ? s : [0].concat(s);
|
s = Array(l - s.length).fill(0).concat(s);
|
||||||
var signature = new Uint8Array(r.concat(s)).buffer;
|
var signature = new Uint8Array(r.concat(s)).buffer;
|
||||||
const key = await webCrypto.importKey(
|
const key = await webCrypto.importKey(
|
||||||
"jwk",
|
"jwk",
|
||||||
|
@ -227,7 +227,7 @@ async function nodeSign(curve, hash_algo, message, keyPair) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function nodeVerify(curve, hash_algo, {r, s}, message, publicKey) {
|
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(
|
const key = jwkToPem(
|
||||||
{
|
{
|
||||||
"kty": "EC",
|
"kty": "EC",
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
* @module crypto/public_key/jsbn
|
* @module crypto/public_key/jsbn
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import util from '../../util.js';
|
import util from '../../util';
|
||||||
|
|
||||||
// Basic JavaScript BN library - subset useful for RSA encryption.
|
// 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) {
|
export default function BigInteger(a, b, c) {
|
||||||
if (a != null)
|
if (a != null)
|
||||||
if ("number" == typeof a) this.fromNumber(a, b, c);
|
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);
|
else this.fromString(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
it('should encrypt and decrypt with two passwords', function() {
|
||||||
var encOpt = {
|
var encOpt = {
|
||||||
data: plaintext,
|
data: plaintext,
|
||||||
|
|
|
@ -107,6 +107,7 @@ describe('X25519 Cryptography', function () {
|
||||||
'-----END PGP MESSAGE-----'].join('\n')
|
'-----END PGP MESSAGE-----'].join('\n')
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function load_pub_key(name) {
|
function load_pub_key(name) {
|
||||||
if (data[name].pub_key) {
|
if (data[name].pub_key) {
|
||||||
return data[name].pub_key;
|
return data[name].pub_key;
|
||||||
|
@ -269,7 +270,6 @@ describe('X25519 Cryptography', function () {
|
||||||
var msg = openpgp.cleartext.readArmored(signed.data);
|
var msg = openpgp.cleartext.readArmored(signed.data);
|
||||||
// Verifying signed message
|
// Verifying signed message
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
// FIXME this test sporadically fails
|
|
||||||
openpgp.verify(
|
openpgp.verify(
|
||||||
{ message: msg, publicKeys: hi.toPublic() }
|
{ message: msg, publicKeys: hi.toPublic() }
|
||||||
).then(output => expect(output.signatures[0].valid).to.be.true),
|
).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);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user