1
0
mirror of https://github.com/Ylianst/MeshCommander synced 2025-12-05 21:53:19 +00:00
Files
MeshCommander/forge.js/ecdh.js
EstiFeit e56b9c0ece TLS: implement ECDHE/DHE key exchange and cipher suites
- Updated cipher suites to include modern algorithms with SHA-256 and SHA-384 support.
- Implemented Diffie-Hellman Ephemeral (DHE) and Elliptic Curve Diffie-Hellman (ECDH) key exchange methods.
- Added HMAC-SHA256 and HMAC-SHA384 for message authentication.
- Improved TLS handshake process to accommodate new key exchange algorithms.

This update strengthens the security of the TLS implementation and aligns with current best practices.
2025-09-09 22:30:39 +03:00

217 lines
7.3 KiB
JavaScript

/**
* ECDH (Elliptic Curve Diffie-Hellman) implementation for Forge TLS.
*/
(function() {
/* ########## Begin module implementation ########## */
function initModule(forge) {
var tls = forge.tls;
// Basic ECDH implementation for secp256r1 (P-256) and secp384r1
tls.ecdh = {};
tls.ecdh.curves = {
'secp256r1': {
p: new forge.jsbn.BigInteger('FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF', 16),
a: new forge.jsbn.BigInteger('FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC', 16),
b: new forge.jsbn.BigInteger('5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B', 16),
gx: new forge.jsbn.BigInteger('6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296', 16),
gy: new forge.jsbn.BigInteger('4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5', 16),
n: new forge.jsbn.BigInteger('FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551', 16),
fieldSize: 32
},
'secp384r1': {
p: new forge.jsbn.BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF', 16),
a: new forge.jsbn.BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC', 16),
b: new forge.jsbn.BigInteger('B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF', 16),
gx: new forge.jsbn.BigInteger('AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7', 16),
gy: new forge.jsbn.BigInteger('3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F', 16),
n: new forge.jsbn.BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973', 16),
fieldSize: 48
}
};
// Simple elliptic curve point implementation
tls.ecdh.ECPoint = function(curve, x, y) {
this.curve = curve;
this.x = x;
this.y = y;
this.isInfinity = (x === null && y === null);
};
tls.ecdh.ECPoint.prototype.add = function(other) {
if(this.isInfinity) return other;
if(other.isInfinity) return this;
var p = this.curve.p;
if(this.x.equals(other.x)) {
if(this.y.equals(other.y)) {
// Point doubling
var s = this.x.multiply(this.x).multiply(new forge.jsbn.BigInteger('3')).add(this.curve.a)
.multiply(this.y.multiply(new forge.jsbn.BigInteger('2')).modInverse(p)).mod(p);
var x3 = s.multiply(s).subtract(this.x.multiply(new forge.jsbn.BigInteger('2'))).mod(p);
var y3 = s.multiply(this.x.subtract(x3)).subtract(this.y).mod(p);
return new tls.ecdh.ECPoint(this.curve, x3, y3);
} else {
// Points are inverses
return new tls.ecdh.ECPoint(this.curve, null, null); // Point at infinity
}
} else {
// Point addition
var s = other.y.subtract(this.y).multiply(other.x.subtract(this.x).modInverse(p)).mod(p);
var x3 = s.multiply(s).subtract(this.x).subtract(other.x).mod(p);
var y3 = s.multiply(this.x.subtract(x3)).subtract(this.y).mod(p);
return new tls.ecdh.ECPoint(this.curve, x3, y3);
}
};
tls.ecdh.ECPoint.prototype.multiply = function(k) {
if(k.equals(forge.jsbn.BigInteger.ZERO)) {
return new tls.ecdh.ECPoint(this.curve, null, null); // Point at infinity
}
var result = new tls.ecdh.ECPoint(this.curve, null, null); // Start with point at infinity
var addend = this;
while(k.compareTo(forge.jsbn.BigInteger.ZERO) > 0) {
if(k.testBit(0)) {
result = result.add(addend);
}
addend = addend.add(addend); // Double
k = k.shiftRight(1);
}
return result;
};
// ECDH key generation and shared secret computation
tls.ecdh.generateKeyPair = function(curveName) {
var curve = tls.ecdh.curves[curveName];
if(!curve) {
throw new Error('Unsupported curve: ' + curveName);
}
// Generate random private key
var privateKey;
do {
var privateKeyBytes = forge.random.getBytes(curve.fieldSize);
privateKey = new forge.jsbn.BigInteger(forge.util.bytesToHex(privateKeyBytes), 16);
} while(privateKey.compareTo(curve.n) >= 0 || privateKey.equals(forge.jsbn.BigInteger.ZERO));
// Compute public key = private * G
var G = new tls.ecdh.ECPoint(curve, curve.gx, curve.gy);
var publicPoint = G.multiply(privateKey);
return {
privateKey: privateKey,
publicKey: publicPoint
};
};
tls.ecdh.computeSharedSecret = function(privateKey, publicPoint) {
var sharedPoint = publicPoint.multiply(privateKey);
// Convert x-coordinate to bytes (shared secret is the x-coordinate)
var sharedSecret = forge.util.hexToBytes(sharedPoint.x.toString(16));
// Pad to field size
var fieldSize = publicPoint.curve.fieldSize;
while(sharedSecret.length < fieldSize) {
sharedSecret = '\x00' + sharedSecret;
}
return sharedSecret;
};
tls.ecdh.encodePoint = function(point) {
if(point.isInfinity) {
return String.fromCharCode(0x00);
}
// Uncompressed point format: 0x04 || x || y
var x = forge.util.hexToBytes(point.x.toString(16));
var y = forge.util.hexToBytes(point.y.toString(16));
// Pad to field size
var fieldSize = point.curve.fieldSize;
while(x.length < fieldSize) x = '\x00' + x;
while(y.length < fieldSize) y = '\x00' + y;
return String.fromCharCode(0x04) + x + y;
};
tls.ecdh.decodePoint = function(curve, pointBytes) {
if(pointBytes.length === 0 || pointBytes.charCodeAt(0) === 0x00) {
return new tls.ecdh.ECPoint(curve, null, null); // Point at infinity
}
if(pointBytes.charCodeAt(0) !== 0x04) {
throw new Error('Only uncompressed points are supported');
}
var fieldSize = curve.fieldSize;
if(pointBytes.length !== 1 + 2 * fieldSize) {
throw new Error('Invalid point encoding length');
}
var x = new forge.jsbn.BigInteger(forge.util.bytesToHex(pointBytes.substr(1, fieldSize)), 16);
var y = new forge.jsbn.BigInteger(forge.util.bytesToHex(pointBytes.substr(1 + fieldSize, fieldSize)), 16);
return new tls.ecdh.ECPoint(curve, x, y);
};
} // end module implementation
/* ########## Begin module wrapper ########## */
var name = 'ecdh';
if(typeof define !== 'function') {
// NodeJS -> AMD
if(typeof module === 'object' && module.exports) {
var nodeJS = true;
define = function(ids, factory) {
factory(require, module);
};
} else {
// <script>
if(typeof forge === 'undefined') {
forge = {};
}
return initModule(forge);
}
}
// AMD
var deps;
var defineFunc = function(require, module) {
module.exports = function(forge) {
var mods = deps.map(function(dep) {
return require(dep);
}).concat(initModule);
// handle circular dependencies
forge = forge || {};
forge.defined = forge.defined || {};
if(forge.defined[name]) {
return forge[name];
}
forge.defined[name] = true;
for(var i = 0; i < mods.length; ++i) {
mods[i](forge);
}
return forge[name];
};
};
var tmpDefine = define;
define = function(ids, factory) {
deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
if(nodeJS) {
delete define;
return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
}
define = tmpDefine;
return define.apply(null, Array.prototype.slice.call(arguments, 0));
};
define(['require', 'module', './util', './jsbn', './random', './tls'], function() {
defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
});
})();