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/public_key
* @requires crypto/random
* @requires type/ecdh_symkey
* @requires type/mpi
* @module crypto/crypto
*/
@ -30,8 +31,19 @@
import random from './random.js';
import cipher from './cipher';
import publicKey from './public_key';
import type_ecdh_symkey from '../type/ecdh_symkey.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 {
/**
* 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;
* 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 m;
switch (algo) {
@ -52,7 +64,7 @@ export default {
var n = publicMPIs[0].toBigInteger();
var e = publicMPIs[1].toBigInteger();
m = data.toBigInteger();
return [rsa.encrypt(m, e, n)];
return mapResult([rsa.encrypt(m, e, n)]);
case 'elgamal':
var elgamal = new publicKey.elgamal();
@ -60,18 +72,22 @@ export default {
var g = publicMPIs[1].toBigInteger();
var y = publicMPIs[2].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:
return [];
}
})();
return result.map(function(bn) {
var mpi = new type_mpi();
mpi.fromBigInteger(bn);
return mpi;
});
return result;
},
/**
@ -86,7 +102,7 @@ export default {
* @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 bn = (function() {
@ -111,6 +127,16 @@ export default {
var c2 = dataIntegers[1].toBigInteger();
p = keyIntegers[0].toBigInteger();
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:
return null;
}
@ -144,8 +170,9 @@ export default {
// Algorithm-Specific Fields for DSA secret keys:
// - MPI of DSA secret exponent x.
return 1;
case 'ecdh':
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.
return 1;
default:
@ -185,6 +212,13 @@ export default {
case 'ecdsa':
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:
throw new Error('Unknown algorithm.');
}
@ -210,14 +244,6 @@ export default {
default:
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.
* @requires crypto
* @requires enums
* @requires type/kdf_params
* @requires type/keyid
* @requires type/mpi
* @requires type/oid
@ -35,6 +36,7 @@
import util from '../util.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_oid from '../type/oid.js';
import enums from '../enums.js';
@ -102,8 +104,10 @@ PublicKey.prototype.read = function (bytes) {
var p = 0;
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();
} else if (this.algorithm === 'ecdh' && i === 2) {
this.mpi[i] = new type_kdf_params();
} else {
this.mpi[i] = new type_mpi();
}

View File

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