@microsoft/dev-tunnels-ssh
Version:
SSH library for Dev Tunnels
110 lines • 5.2 kB
JavaScript
"use strict";
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebECDiffieHellman = exports.WebDiffieHellman = void 0;
const buffer_1 = require("buffer");
const diffie_hellman_1 = require("diffie-hellman");
const keyExchangeAlgorithm_1 = require("../keyExchangeAlgorithm");
const webHmac_1 = require("./webHmac");
const bigInt_1 = require("../../io/bigInt");
const jsonWebKeyFormatter_1 = require("./jsonWebKeyFormatter");
class WebDiffieHellman extends keyExchangeAlgorithm_1.KeyExchangeAlgorithm {
constructor(name, keySizeInBits, hashAlgorithmName) {
super(name, keySizeInBits, hashAlgorithmName, webHmac_1.WebHmac.getHashDigestLength(hashAlgorithmName));
}
createKeyExchange() {
return new WebDiffieHellmanKex(this.keySizeInBits, webHmac_1.WebHmac.getWebHashAlgorithmName(this.hashAlgorithmName), this.hashDigestLength);
}
}
exports.WebDiffieHellman = WebDiffieHellman;
class WebDiffieHellmanKex {
constructor(bitLength, hashAlgorithmName, digestLength) {
this.hashAlgorithmName = hashAlgorithmName;
this.digestLength = digestLength;
switch (bitLength) {
case 1024:
this.dh = (0, diffie_hellman_1.getDiffieHellman)('modp2');
break;
case 2048:
this.dh = (0, diffie_hellman_1.getDiffieHellman)('modp14');
break;
case 4096:
this.dh = (0, diffie_hellman_1.getDiffieHellman)('modp16');
break;
default:
throw new Error('Invalid DH bit length.');
}
}
startKeyExchange() {
const exchangeValueKeys = this.dh.generateKeys();
const exchangeValue = bigInt_1.BigInt.fromBytes(exchangeValueKeys, { unsigned: true }).toBytes();
return Promise.resolve(exchangeValue);
}
decryptKeyExchange(exchangeValue) {
const key = this.dh.computeSecret(exchangeValue);
const sharedSecret = bigInt_1.BigInt.fromBytes(key, { unsigned: true }).toBytes();
return Promise.resolve(sharedSecret);
}
async sign(data) {
const hashBuffer = await crypto.subtle.digest(this.hashAlgorithmName, data);
return buffer_1.Buffer.from(hashBuffer);
}
dispose() { }
}
class WebECDiffieHellman extends keyExchangeAlgorithm_1.KeyExchangeAlgorithm {
constructor(name, keySizeInBits, hashAlgorithmName) {
super(name, keySizeInBits, hashAlgorithmName, webHmac_1.WebHmac.getHashDigestLength(hashAlgorithmName));
}
createKeyExchange() {
return new WebECDiffieHellmanKex(this.keySizeInBits, webHmac_1.WebHmac.getWebHashAlgorithmName(this.hashAlgorithmName), this.hashDigestLength);
}
}
exports.WebECDiffieHellman = WebECDiffieHellman;
class WebECDiffieHellmanKex {
constructor(bitLength, hashAlgorithmName, digestLength) {
this.bitLength = bitLength;
this.hashAlgorithmName = hashAlgorithmName;
this.digestLength = digestLength;
this.algorithm = {
name: 'ECDH',
namedCurve: 'P-' + bitLength,
};
}
async startKeyExchange() {
if (!this.keyPair) {
this.keyPair = await crypto.subtle.generateKey(this.algorithm, true, // exportable
['deriveBits']);
}
const jwk = await crypto.subtle.exportKey('jwk', this.keyPair.publicKey);
const ec = jsonWebKeyFormatter_1.JsonWebKeyFormatter.parseEC(jwk);
const length = Math.ceil(this.bitLength / 8);
const publicKeyBytes = buffer_1.Buffer.alloc(1 + length * 2);
publicKeyBytes[0] = 4;
ec.x.toBytes({ unsigned: true, length }).copy(publicKeyBytes, 1);
ec.y.toBytes({ unsigned: true, length }).copy(publicKeyBytes, 1 + length);
return buffer_1.Buffer.from(publicKeyBytes);
}
async decryptKeyExchange(exchangeValue) {
if (!this.keyPair) {
throw new Error('Key exchange not started.');
}
const xy = exchangeValue;
const jwk = jsonWebKeyFormatter_1.JsonWebKeyFormatter.formatEC({
curve: { name: this.algorithm.namedCurve },
x: bigInt_1.BigInt.fromBytes(xy.slice(1, 1 + (xy.length - 1) / 2), { unsigned: true }),
y: bigInt_1.BigInt.fromBytes(xy.slice(1 + (xy.length - 1) / 2), { unsigned: true }),
});
const otherPublicKey = await crypto.subtle.importKey('jwk', jwk, this.algorithm, false, []);
const sharedSecretBytes = buffer_1.Buffer.from(await crypto.subtle.deriveBits(Object.assign(Object.assign({}, this.algorithm), { public: otherPublicKey }), this.keyPair.privateKey, Math.ceil(this.bitLength / 8) * 8));
const sharedSecret = bigInt_1.BigInt.fromBytes(sharedSecretBytes, { unsigned: true }).toBytes();
return sharedSecret;
}
async sign(data) {
const hashBuffer = await crypto.subtle.digest(this.hashAlgorithmName, data);
return buffer_1.Buffer.from(hashBuffer);
}
dispose() { }
}
//# sourceMappingURL=webKeyExchange.js.map