Parse and create ECDH packets

This commit is contained in:
Ismael Bejarano 2016-08-12 00:25:21 -03:00 committed by Sanjana Rajan
parent 585a2bd69d
commit 38a53c1bb1
3 changed files with 82 additions and 29 deletions

View File

@ -21,6 +21,7 @@
* @requires crypto/cipher * @requires crypto/cipher
* @requires crypto/public_key * @requires crypto/public_key
* @requires crypto/random * @requires crypto/random
* @requires type/ecdh_symkey
* @requires type/mpi * @requires type/mpi
* @module crypto/crypto * @module crypto/crypto
*/ */
@ -30,8 +31,19 @@
import random from './random.js'; import random from './random.js';
import cipher from './cipher'; import cipher from './cipher';
import publicKey from './public_key'; import publicKey from './public_key';
import type_ecdh_symkey from '../type/ecdh_symkey.js';
import type_mpi from '../type/mpi.js'; import type_mpi from '../type/mpi.js';
function BigInteger2mpi(bn) {
var mpi = new type_mpi();
mpi.fromBigInteger(bn);
return mpi;
}
function mapResult(result) {
return result.map(BigInteger2mpi);
}
export default { export default {
/** /**
* Encrypts data using the specified public key multiprecision integers * Encrypts data using the specified public key multiprecision integers
@ -42,7 +54,7 @@ export default {
* @return {Array<module:type/mpi>} if RSA an module:type/mpi; * @return {Array<module:type/mpi>} if RSA an module:type/mpi;
* if elgamal encryption an array of two module:type/mpi is returned; otherwise null * if elgamal encryption an array of two module:type/mpi is returned; otherwise null
*/ */
publicKeyEncrypt: function(algo, publicMPIs, data) { publicKeyEncrypt: function(algo, publicMPIs, data, fingerprint) {
var result = (function() { var result = (function() {
var m; var m;
switch (algo) { switch (algo) {
@ -52,7 +64,7 @@ export default {
var n = publicMPIs[0].toBigInteger(); var n = publicMPIs[0].toBigInteger();
var e = publicMPIs[1].toBigInteger(); var e = publicMPIs[1].toBigInteger();
m = data.toBigInteger(); m = data.toBigInteger();
return [rsa.encrypt(m, e, n)]; return mapResult([rsa.encrypt(m, e, n)]);
case 'elgamal': case 'elgamal':
var elgamal = new publicKey.elgamal(); var elgamal = new publicKey.elgamal();
@ -60,18 +72,22 @@ export default {
var g = publicMPIs[1].toBigInteger(); var g = publicMPIs[1].toBigInteger();
var y = publicMPIs[2].toBigInteger(); var y = publicMPIs[2].toBigInteger();
m = data.toBigInteger(); m = data.toBigInteger();
return elgamal.encrypt(m, g, p, y); return mapResult(elgamal.encrypt(m, g, p, y));
case 'ecdh':
var ecdh = publicKey.elliptic.ecdh;
var curve = publicMPIs[0];
var kdf_params = publicMPIs[2];
var R = publicMPIs[1].toBigInteger();
var res = ecdh.encrypt(curve.oid, kdf_params.cipher, kdf_params.hash, data, R, fingerprint);
return [BigInteger2mpi(res.V), new type_ecdh_symkey(res.C)];
default: default:
return []; return [];
} }
})(); })();
return result.map(function(bn) { return result;
var mpi = new type_mpi();
mpi.fromBigInteger(bn);
return mpi;
});
}, },
/** /**
@ -86,7 +102,7 @@ export default {
* @return {module:type/mpi} returns a big integer containing the decrypted data; otherwise null * @return {module:type/mpi} returns a big integer containing the decrypted data; otherwise null
*/ */
publicKeyDecrypt: function(algo, keyIntegers, dataIntegers) { publicKeyDecrypt: function(algo, keyIntegers, dataIntegers, fingerprint) {
var p; var p;
var bn = (function() { var bn = (function() {
@ -111,6 +127,16 @@ export default {
var c2 = dataIntegers[1].toBigInteger(); var c2 = dataIntegers[1].toBigInteger();
p = keyIntegers[0].toBigInteger(); p = keyIntegers[0].toBigInteger();
return elgamal.decrypt(c1, c2, p, x); return elgamal.decrypt(c1, c2, p, x);
case 'ecdh':
var ecdh = publicKey.elliptic.ecdh;
var curve = keyIntegers[0];
var kdf_params = keyIntegers[2];
var V = dataIntegers[0].toBigInteger();
var C = dataIntegers[1].data;
var r = keyIntegers[3].toBigInteger();
return ecdh.decrypt(curve.oid, kdf_params.cipher, kdf_params.hash, V, C, r, fingerprint);
default: default:
return null; return null;
} }
@ -144,8 +170,9 @@ export default {
// Algorithm-Specific Fields for DSA secret keys: // Algorithm-Specific Fields for DSA secret keys:
// - MPI of DSA secret exponent x. // - MPI of DSA secret exponent x.
return 1; return 1;
case 'ecdh':
case 'ecdsa': case 'ecdsa':
// Algorithm-Specific Fields for ECDSA secret keys: // Algorithm-Specific Fields for ECDSA or ECDH secret keys:
// - MPI of an integer representing the secret key. // - MPI of an integer representing the secret key.
return 1; return 1;
default: default:
@ -185,6 +212,13 @@ export default {
case 'ecdsa': case 'ecdsa':
return 2; return 2;
// Algorithm-Specific Fields for ECDH public keys:
// - OID of curve;
// - MPI of EC point representing public key.
// - variable-length field containing KDF parameters.
case 'ecdh':
return 3;
default: default:
throw new Error('Unknown algorithm.'); throw new Error('Unknown algorithm.');
} }
@ -210,14 +244,6 @@ export default {
default: default:
throw new Error('Unsupported algorithm for key generation.'); throw new Error('Unsupported algorithm for key generation.');
} }
function mapResult(result) {
return result.map(function(bn) {
var mpi = new type_mpi();
mpi.fromBigInteger(bn);
return mpi;
});
}
}, },

View File

@ -24,6 +24,7 @@
* major versions. Consequently, this section is complex. * major versions. Consequently, this section is complex.
* @requires crypto * @requires crypto
* @requires enums * @requires enums
* @requires type/kdf_params
* @requires type/keyid * @requires type/keyid
* @requires type/mpi * @requires type/mpi
* @requires type/oid * @requires type/oid
@ -35,6 +36,7 @@
import util from '../util.js'; import util from '../util.js';
import type_mpi from '../type/mpi.js'; import type_mpi from '../type/mpi.js';
import type_kdf_params from '../type/kdf_params.js';
import type_keyid from '../type/keyid.js'; import type_keyid from '../type/keyid.js';
import type_oid from '../type/oid.js'; import type_oid from '../type/oid.js';
import enums from '../enums.js'; import enums from '../enums.js';
@ -102,8 +104,10 @@ PublicKey.prototype.read = function (bytes) {
var p = 0; var p = 0;
for (var i = 0; i < mpicount && p < bmpi.length; i++) { for (var i = 0; i < mpicount && p < bmpi.length; i++) {
if (this.algorithm === 'ecdsa' && i === 0) { if ((this.algorithm === 'ecdsa' || this.algorithm === 'ecdh') && i === 0) {
this.mpi[i] = new type_oid(); this.mpi[i] = new type_oid();
} else if (this.algorithm === 'ecdh' && i === 2) {
this.mpi[i] = new type_kdf_params();
} else { } else {
this.mpi[i] = new type_mpi(); this.mpi[i] = new type_mpi();
} }

View File

@ -31,6 +31,7 @@
* decrypt the message. * decrypt the message.
* @requires crypto * @requires crypto
* @requires enums * @requires enums
* @requires type/ecdh_symkey
* @requires type/keyid * @requires type/keyid
* @requires type/mpi * @requires type/mpi
* @requires util * @requires util
@ -41,6 +42,7 @@
import type_keyid from '../type/keyid.js'; import type_keyid from '../type/keyid.js';
import util from '../util.js'; import util from '../util.js';
import type_ecdh_symkey from '../type/ecdh_symkey.js';
import type_mpi from '../type/mpi.js'; import type_mpi from '../type/mpi.js';
import enums from '../enums.js'; import enums from '../enums.js';
import crypto from '../crypto'; import crypto from '../crypto';
@ -88,6 +90,9 @@ PublicKeyEncryptedSessionKey.prototype.read = function (bytes) {
case 'elgamal': case 'elgamal':
return 2; return 2;
case 'ecdh':
return 2;
default: default:
throw new Error("Invalid algorithm."); throw new Error("Invalid algorithm.");
} }
@ -96,7 +101,12 @@ PublicKeyEncryptedSessionKey.prototype.read = function (bytes) {
this.encrypted = []; this.encrypted = [];
for (var j = 0; j < integerCount; j++) { for (var j = 0; j < integerCount; j++) {
var mpi = new type_mpi(); var mpi;
if (this.publicKeyAlgorithm === 'ecdh' && j === 1) {
mpi = new type_ecdh_symkey();
} else {
mpi = new type_mpi();
}
i += mpi.read(bytes.subarray(i, bytes.length)); i += mpi.read(bytes.subarray(i, bytes.length));
this.encrypted.push(mpi); this.encrypted.push(mpi);
} }
@ -126,15 +136,21 @@ PublicKeyEncryptedSessionKey.prototype.encrypt = function (key) {
var checksum = util.calc_checksum(this.sessionKey); var checksum = util.calc_checksum(this.sessionKey);
data += util.Uint8Array2str(util.writeNumber(checksum, 2)); data += util.Uint8Array2str(util.writeNumber(checksum, 2));
var mpi = new type_mpi(); var mpi;
if (this.publicKeyAlgorithm === 'ecdh') {
mpi = util.str2Uint8Array(crypto.pkcs5.addPadding(data));
} else {
mpi = new type_mpi();
mpi.fromBytes(crypto.pkcs1.eme.encode( mpi.fromBytes(crypto.pkcs1.eme.encode(
data, data,
key.mpi[0].byteLength())); key.mpi[0].byteLength()));
}
this.encrypted = crypto.publicKeyEncrypt( this.encrypted = crypto.publicKeyEncrypt(
this.publicKeyAlgorithm, this.publicKeyAlgorithm,
key.mpi, key.mpi,
mpi); mpi,
key.fingerprint);
}; };
/** /**
@ -149,11 +165,18 @@ PublicKeyEncryptedSessionKey.prototype.decrypt = function (key) {
var result = crypto.publicKeyDecrypt( var result = crypto.publicKeyDecrypt(
this.publicKeyAlgorithm, this.publicKeyAlgorithm,
key.mpi, key.mpi,
this.encrypted).toBytes(); this.encrypted,
key.fingerprint).toBytes();
var checksum = util.readNumber(util.str2Uint8Array(result.substr(result.length - 2))); var checksum;
var decoded;
var decoded = crypto.pkcs1.eme.decode(result); if (this.publicKeyAlgorithm === 'ecdh') {
decoded = crypto.pkcs5.removePadding(result);
checksum = util.readNumber(util.str2Uint8Array(decoded.substr(decoded.length - 2)));
} else {
decoded = crypto.pkcs1.eme.decode(result);
checksum = util.readNumber(util.str2Uint8Array(result.substr(result.length - 2)));
}
key = util.str2Uint8Array(decoded.substring(1, decoded.length - 2)); key = util.str2Uint8Array(decoded.substring(1, decoded.length - 2));