Compare commits

..

No commits in common. "a9f3348a01d2cda347ab7ea1a082e66d7c196bfb" and "b1189bd23732fac8ef20a3f86a5375d5734a50cd" have entirely different histories.

21 changed files with 39 additions and 46339 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,59 +0,0 @@
rendezvous-service-descriptor 4frkg4jpbmbjhlsrbyjpbmu3slphz7ts
version 2
permanent-key
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALdj5MFZtlrjI54ousrBzA3fSyfn0NC32OBhl61BLgO67vPBiIiFFzo9
YIqa4h3jZQrxdI3MeK4xTLQ6HhnQXvcM+ZR57o5zTR7fpqra89i75rwUjW5wqc9O
3roxzt1UWbJBtbzOT9FYxGSIczsYdG6MQRg9BK/2v391Oz9NbDb1AgMBAAE=
-----END RSA PUBLIC KEY-----
secret-id-part 7mnzxwe2gg2eoxp2hek4dzkv2chupfxy
publication-time 2016-07-20 08:00:00
protocol-versions 2,3
introduction-points
-----BEGIN MESSAGE-----
aW50cm9kdWN0aW9uLXBvaW50IHBkY3B6eWVmZHNtMmp5Y3ZtcGRwa2lnZ3I0dWwz
ZWxvCmlwLWFkZHJlc3MgMjEzLjEzNi43MS4yMQpvbmlvbi1wb3J0IDkwMDEKb25p
b24ta2V5Ci0tLS0tQkVHSU4gUlNBIFBVQkxJQyBLRVktLS0tLQpNSUdKQW9HQkFM
VXJuT0tqTjZIR0tPa3IwUFFhSWhHNDJQRkd2S0ZpVmJ3QlEwTjhEVk1LLzRWNlZ1
T3JEZkhOCjFXemVzTUpVRWx3OWhPWko4MmdjcVZXYUFvYm9sODdJMDgwVU9SNC9a
ZTV5cFhtaS9Jd2tFN3RMN08wTW9vaXMKTmliV2Y1Z00vUlh5bzh0czdnaDUrV2wr
UnZPcjBoc2pTVHBtdUgxeHlJYVJhem9qWG4zSEFnTUJBQUU9Ci0tLS0tRU5EIFJT
QSBQVUJMSUMgS0VZLS0tLS0Kc2VydmljZS1rZXkKLS0tLS1CRUdJTiBSU0EgUFVC
TElDIEtFWS0tLS0tCk1JR0pBb0dCQU0wQjM0eE5rWVdxcDdOeE9jMzJSNkh3TXM3
T2phODYyWStFZmU5bVhEdUpmL2FGOWFIWVN3NW0KeHB6NVU4bVAxa0d1OU5ZK2FX
K1E0YU42YTJNam5LMDJFeWcyYXphVkt6MFp2SVdkQWdCRVdNMUx6TlQ5c3pMTgpn
SzR2VEZSOGVOTXY4cUF5aEp2S0liTW5TMFdmR3QzZkphd3RwUmFoVDdwRnd5ZnR1
bzBwQWdNQkFBRT0KLS0tLS1FTkQgUlNBIFBVQkxJQyBLRVktLS0tLQppbnRyb2R1
Y3Rpb24tcG9pbnQgY3ZnaHZkM3I0ZjNxenpwaXd0aHk0bm9kaW11M2FuZ2IKaXAt
YWRkcmVzcyAxNjMuMTcyLjIxNC43NQpvbmlvbi1wb3J0IDkwMDEKb25pb24ta2V5
Ci0tLS0tQkVHSU4gUlNBIFBVQkxJQyBLRVktLS0tLQpNSUdKQW9HQkFMWXRlRmt3
K1BrcWRPZWprUE1qdjk4djYzS3YzU2xzTmxzS2ZaUkhTSy8ybWZTRVVPMmdxSE43
CjRKLzBveGhsV1NTQVBQTis5YmRPejFlbWc2SUVMMk9WZEtKZmdvaWJsSE1oditY
eDErak1YS0YwMTZKNjB6azMKV0xBNFMwL0hqZjk0YUhWUmsza1JLNlNTVmlER05K
MWZ0ZUVQaTV4cDlDRFFaeUZaMStqVkFnTUJBQUU9Ci0tLS0tRU5EIFJTQSBQVUJM
SUMgS0VZLS0tLS0Kc2VydmljZS1rZXkKLS0tLS1CRUdJTiBSU0EgUFVCTElDIEtF
WS0tLS0tCk1JR0pBb0dCQUxBQVNWK1FxRlhGdDd5a3JtdlRMeG1Kai82QkNWRWwx
eVZ3MFJvcGJWSUxRNWNmaGFPQWVENTcKS0NDbGVXZHR0aE0yUlZKaytvTG9jK0RN
VXhvZUVRbUo5cktBbi9ic2Rxa01EU3U1QTJjcFV3ajhXbnpieHdKcApKNzlqTGJZ
ZTNIV3NDRXcySkxDWGgvQmRObTFOOVFsN3FXNDJsbnJFQzVMemRKaUYwbklKQWdN
QkFBRT0KLS0tLS1FTkQgUlNBIFBVQkxJQyBLRVktLS0tLQppbnRyb2R1Y3Rpb24t
cG9pbnQgeHZnZ2k1aWljeXh2dHMyZTR0cDRkcXZzeGN1dHE3Z2sKaXAtYWRkcmVz
cyAxNjMuMTcyLjM1LjExNQpvbmlvbi1wb3J0IDkwMDEKb25pb24ta2V5Ci0tLS0t
QkVHSU4gUlNBIFBVQkxJQyBLRVktLS0tLQpNSUdKQW9HQkFMUmVBUFpmK0sxeWQ3
Q0RxQ2dMV2RzdjdqdzhBZXpzYXRxbnJQN3RvakY0dXcyZkxITEpFSk12ClZwZ0Zn
SEhSQzNic3owS3ZUcXZIdEVXMFhHWkpXZmhWU1czSkFHaHovWXF1NTNTRUM5WkdN
c2xIZnIyeGxSSXIKN2RCRWlDQkFHOGRQa1VMZkM2RWN5SFB6QXBIMWk5d3V6Y2x0
dUowekZRbUpFbEIvalNOUEFnTUJBQUU9Ci0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZ
LS0tLS0Kc2VydmljZS1rZXkKLS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0t
Ck1JR0pBb0dCQUxOTVc1SG9sZmFTM3NqWk5od3ZUd2pUOStPc1kyYU1XWjVieXZy
Q1pzMG5xQ21FaXZFTlNBbVoKZjlvbFQ0em14TUhZNEtJYVVGcW5ZdzV5NTlvSGo4
eGx1bDRLMURrTU15dWRRaTNhcHBuaWtBWGZhUkptRXNKRgozbk9Neld6UmN4MG1r
MFhRYTh4OWF0R2E1UnMvV2l2aVlYUEVTYklKMGlOZmFScWMyS0hYQWdNQkFBRT0K
LS0tLS1FTkQgUlNBIFBVQkxJQyBLRVktLS0tLQoK
-----END MESSAGE-----
signature
-----BEGIN SIGNATURE-----
aDxMNhtGWBV7lMJPTfamvHNXVFD7wFTTRz68JEhmmfLVuuZ+erUfjDHsUa3bF3zR
tNvPBYbQdWj2vl8WzdzwlchXS56iqgQ672y19/hx4THiuPyjGUj/dtc7L4qINl1V
cgBWo0Lezfnyc+5laQboMsEsjQa4SqJyQNamjmS2soo=
-----END SIGNATURE-----

View File

@ -1,45 +0,0 @@
introduction-point pdcpzyefdsm2jycvmpdpkiggr4ul3elo
ip-address 213.136.71.21
onion-port 9001
onion-key
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALUrnOKjN6HGKOkr0PQaIhG42PFGvKFiVbwBQ0N8DVMK/4V6VuOrDfHN
1WzesMJUElw9hOZJ82gcqVWaAobol87I080UOR4/Ze5ypXmi/IwkE7tL7O0Moois
NibWf5gM/RXyo8ts7gh5+Wl+RvOr0hsjSTpmuH1xyIaRazojXn3HAgMBAAE=
-----END RSA PUBLIC KEY-----
service-key
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAM0B34xNkYWqp7NxOc32R6HwMs7Oja862Y+Efe9mXDuJf/aF9aHYSw5m
xpz5U8mP1kGu9NY+aW+Q4aN6a2MjnK02Eyg2azaVKz0ZvIWdAgBEWM1LzNT9szLN
gK4vTFR8eNMv8qAyhJvKIbMnS0WfGt3fJawtpRahT7pFwyftuo0pAgMBAAE=
-----END RSA PUBLIC KEY-----
introduction-point cvghvd3r4f3qzzpiwthy4nodimu3angb
ip-address 163.172.214.75
onion-port 9001
onion-key
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALYteFkw+PkqdOejkPMjv98v63Kv3SlsNlsKfZRHSK/2mfSEUO2gqHN7
4J/0oxhlWSSAPPN+9bdOz1emg6IEL2OVdKJfgoiblHMhv+Xx1+jMXKF016J60zk3
WLA4S0/Hjf94aHVRk3kRK6SSViDGNJ1fteEPi5xp9CDQZyFZ1+jVAgMBAAE=
-----END RSA PUBLIC KEY-----
service-key
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALAASV+QqFXFt7ykrmvTLxmJj/6BCVEl1yVw0RopbVILQ5cfhaOAeD57
KCCleWdtthM2RVJk+oLoc+DMUxoeEQmJ9rKAn/bsdqkMDSu5A2cpUwj8WnzbxwJp
J79jLbYe3HWsCEw2JLCXh/BdNm1N9Ql7qW42lnrEC5LzdJiF0nIJAgMBAAE=
-----END RSA PUBLIC KEY-----
introduction-point xvggi5iicyxvts2e4tp4dqvsxcutq7gk
ip-address 163.172.35.115
onion-port 9001
onion-key
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALReAPZf+K1yd7CDqCgLWdsv7jw8AezsatqnrP7tojF4uw2fLHLJEJMv
VpgFgHHRC3bsz0KvTqvHtEW0XGZJWfhVSW3JAGhz/Yqu53SEC9ZGMslHfr2xlRIr
7dBEiCBAG8dPkULfC6EcyHPzApH1i9wuzcltuJ0zFQmJElB/jSNPAgMBAAE=
-----END RSA PUBLIC KEY-----
service-key
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBALNMW5HolfaS3sjZNhwvTwjT9+OsY2aMWZ5byvrCZs0nqCmEivENSAmZ
f9olT4zmxMHY4KIaUFqnYw5y59oHj8xlul4K1DkMMyudQi3appnikAXfaRJmEsJF
3nOMzWzRcx0mk0XQa8x9atGa5Rs/WiviYXPESbIJ0iNfaRqc2KHXAgMBAAE=
-----END RSA PUBLIC KEY-----

View File

@ -1,54 +0,0 @@
router tor26 86.59.21.38 443 0 80
identity-ed25519
-----BEGIN ED25519 CERT-----
AQQABkOxASTqCHFXm3umN0NYOlIfUHpu0elZrvvdJQIKiwEytEVIAQAgBACRd0Dl
2YiFduUCq4zHQzQClYkngkZAYuyNRKfzpxshpVAWZQcho/HH9PTCjkntnqfCVBlp
Qz0azrqvzrm+ORY6lLoL3SwF6e83iwhXDz3Xl1eQNttdM0py0SgM1guAews=
-----END ED25519 CERT-----
master-key-ed25519 kXdA5dmIhXblAquMx0M0ApWJJ4JGQGLsjUSn86cbIaU
or-address [2001:858:2:2:aabb:0:563b:1526]:443
platform Tor 0.2.8.5-rc on Linux
protocols Link 1 2 Circuit 1
published 2016-07-20 06:17:03
fingerprint 847B 1F85 0344 D787 6491 A548 92F9 0493 4E4E B85D
uptime 657305
bandwidth 76800 1073741824 2436786
extra-info-digest 4823F98D08CD81FF18BDFC7539D2117023F4A2BF gh1tclm7Gfwhhus3My4od7NpzOVddwLP9vl2SJEbkkM
caches-extra-info
onion-key
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMMbFxRKUYujEKnXEORyrA1bokmMJ64p6uJn0r9LdKRgOPMnaLFGNLwV
VNXWW22XZh/+B/e5SWUZDrrVpDuPc2b+jS91czHC6j4zErP9GljhV2QEi9Y31/ib
ilYaEcZh/fgXFUEUCQunw3Hcy1IiCd1ZCCkt644SvJqpPE3SYRUBAgMBAAE=
-----END RSA PUBLIC KEY-----
signing-key
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMQgV2gXLbXgesWgeAsj8P1Uvm/zibrFXqwDq27lLKNgWGYGX2ax3LyT
3nzI1Y5oLs4kPKTsMM5ft9aokwf417lKoCRlZc9ptfRbgxDx90c9GtWVmkrmDvCK
ae59TMoXIiGfZiwWT6KKq5Zm9/Fu2Il3B2vHGkKJYKixmiBJRKp/AgMBAAE=
-----END RSA PUBLIC KEY-----
onion-key-crosscert
-----BEGIN CROSSCERT-----
B6uutyCOCqEzoxldF4jOvWdSinCbmd2vWiRix5qYV8OVxhGlwGvby0cyYzCOuxDW
FdKzl+8idwUokJnVrfmIAQT4UvDJrlPYsVrH+OJ/WHV01A7cy4SH7Od8QRIBDhFy
AlzCLMWjUS2U6Os2qfLAALIQS5IJXGZFNaKK2KPQuco=
-----END CROSSCERT-----
ntor-onion-key-crosscert 1
-----BEGIN ED25519 CERT-----
AQoABjqfAZF3QOXZiIV25QKrjMdDNAKViSeCRkBi7I1Ep/OnGyGlAFFzHPrLfNnI
PSczV2yNoywGUwc4P5YLxYXhuzJCcvBuWcJJsqj7OOOqAnZqDwdQoTKoo4XsJW8B
Masq4RFHrgo=
-----END ED25519 CERT-----
family $01C5B10C5C6B1DEB47612E66EBF315B7C64DE803 $03FF94D9E5001DD2290BC3B19FA7F59CE1E30279 $6BD2FF175484CD7925A81DC42D89B3953252DBAD $995D0FE5A89563D79A383CCC2444D0E26C6BE625 $CA1DDA678A477BD2F19714F88A3C0613C7AD3C10
hidden-service-dir
contact Peter Palfrader
ntor-onion-key Bo7lvTWfIi+Wo8zLi7rTU1VTbfUPde/l1xep/YnrHWY=
reject *:*
tunnelled-dir-server
router-sig-ed25519 PPdfXRuQBWE94/ApWcxAg5auci7xpHgfnp6AHQDxGQH0YVag7cEFba4ubJEw+2RNYIFEPXzAE3vTFZUZItRWBQ
router-signature
-----BEGIN SIGNATURE-----
aF7kwzH6UHfviZkAd8Ga/UFmMZqNJt4rXRcCOUG7+cnyVnzJ2c6Y6uuHIfINuarc
+rEsE4+OBswnBTQbxi/YpEijZkzambmeLPtY3okyy4PqLA1rPmh9pirp/zB3n6Co
kCou0AEO5POcpT1D+yJnYny7qKjkxnvNuGvuRzE7OkE=
-----END SIGNATURE-----

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

4236
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,6 @@
"base32": "0.0.6", "base32": "0.0.6",
"curve25519-js": "0.0.4", "curve25519-js": "0.0.4",
"futoin-hkdf": "^1.3.2", "futoin-hkdf": "^1.3.2",
"jest": "^26.6.3",
"tweetnacl": "^1.0.3" "tweetnacl": "^1.0.3"
} }
} }

View File

@ -281,34 +281,8 @@ class Circuit {
} }
_on_relay_extended_cell(cell) { _on_relay_extended_cell(cell) {
// //TODO
// The payload of an EXTENDED cell is the same as the payload of a throw new Error('Not implemented')
// CREATED cell.
//
//
// finish the handshake.
//
const handshake_data = cell.relay_payload;
this._extend_node.compute_shared_secret(handshake_data);
if (this._extend_node.has_valid_crypto_state())
{
this._node_list.push(this._extend_node);
//
// we're ready here.
//
this._extend_node = null;
this.state = States.ready;
}
else
{
this._logger.error("Circuit.handle_relay_extended_cell() extend node [ %s ] has invalid crypto state", this._extend_node.onion_router.name);
this.destroy();
}
} }
_on_relay_extended2(cell) { _on_relay_extended2(cell) {
@ -778,7 +752,7 @@ class Circuit {
//mini_assert(rendezvous_cookie.get_size() == 20); //mini_assert(rendezvous_cookie.get_size() == 20);
const introduction_point = this.get_final_circuit_node().onion_router; const introduction_point = this.get_final_circuit_node().onion_router;
const introducee = rendezvous_circuit.get_final_circuit_node().onion_router; const introducee = rendezvous_circuit.get_final_circuit_node.onion_router;
this._logger.debug("Circuit.rendezvous_introduce() [or: %s, state: introducing]", introduction_point.name); this._logger.debug("Circuit.rendezvous_introduce() [or: %s, state: introducing]", introduction_point.name);
this.state = States.rendezvous_introducing; this.state = States.rendezvous_introducing;
@ -816,7 +790,7 @@ class Circuit {
2 + // port 2 + // port
20 + // identity_fingerprint 20 + // identity_fingerprint
2 + // onion key size 2 + // onion key size
introducee.onion_key.length + // onion key 32 + // onion key
20 + // rendezvous cookie 20 + // rendezvous cookie
128); // DH 128); // DH
@ -834,14 +808,7 @@ class Circuit {
rendezvous_cookie.copy(handshake_bytes, 29 + introducee.onion_key.length); rendezvous_cookie.copy(handshake_bytes, 29 + introducee.onion_key.length);
rendezvous_circuit._extend_node.key_agreement.public_key.copy(handshake_bytes, 29 + introducee.onion_key.length + rendezvous_cookie.length); rendezvous_circuit._extend_node.key_agreement.public_key.copy(handshake_bytes, 29 + introducee.onion_key.length + rendezvous_cookie.length);
const b64 = introduction_point.service_key.toString('base64'); const handshake_encrypted = hybrid_encrypt(handshake_bytes, introduction_point.service_key);
const parts = ['-----BEGIN RSA PUBLIC KEY-----'];
for (let i = 0; i < b64.length; i += 64) {
parts.push(b64.slice(i, i + 64));
}
parts.push('-----END RSA PUBLIC KEY-----');
const service_key = parts.join('\n')
const handshake_encrypted = hybrid_encrypt(handshake_bytes, service_key);
// //
// compose the final payload. // compose the final payload.
@ -874,7 +841,7 @@ class Circuit {
return; return;
} }
if (await rendezvous_circuit.wait_for_state(States.rendezvous_completed, 90000)) if (await rendezvous_circuit.wait_for_state(States.rendezvous_completed))
{ {
this._logger.debug("Circuit.rendezvous_introduce() [or: %s, state: completed]", introduction_point.name); this._logger.debug("Circuit.rendezvous_introduce() [or: %s, state: completed]", introduction_point.name);
} }

View File

@ -1,5 +1,4 @@
const KeyAgreementNtor = require('./KeyAgreementNtor'); const KeyAgreementNtor = require('./KeyAgreementNtor');
const KeyAgreementTap = require('./KeyAgreementTap');
const CircuitNodeCryptoState = require('./CircuitNodeCryptoState'); const CircuitNodeCryptoState = require('./CircuitNodeCryptoState');
class CircuitNode { class CircuitNode {
@ -7,7 +6,7 @@ class CircuitNode {
/** @type OnionRouter */ /** @type OnionRouter */
_onion_router = null; _onion_router = null;
_type = 'normal'; _type = 'normal';
/** @type {KeyAgreementNtor|KeyAgreementTap} */ /** @type KeyAgreementNtor */
_handshake = null; _handshake = null;
/** @type CircuitNodeCryptoState */ /** @type CircuitNodeCryptoState */
_crypto_state = null; _crypto_state = null;
@ -23,9 +22,6 @@ class CircuitNode {
this._circuit = circuit; this._circuit = circuit;
this._onion_router = or; this._onion_router = or;
this._type = type; this._type = type;
if (type === 'introductionpoint') {
this._handshake = new KeyAgreementTap(or);
}
} }
create_onion_skin_ntor() { create_onion_skin_ntor() {

View File

@ -193,7 +193,7 @@ class Consensus {
* @return {Promise<string>} * @return {Promise<string>}
* @private * @private
*/ */
async _download_from_random_router_impl(path, only_authorities) { _download_from_random_router_impl(path, only_authorities) {
let ip; let ip;
let port; let port;
@ -222,11 +222,7 @@ class Consensus {
this._logger.debug(`Consensus._download_from_random_router_impl() [path: http://${ip}:${port}${path}]`); this._logger.debug(`Consensus._download_from_random_router_impl() [path: http://${ip}:${port}${path}]`);
try { return get('http:', ip, port, path);
return await get('http:', ip, port, path);
} catch (err) {
return '';
}
} }
_parse_consensus(content) { _parse_consensus(content) {

View File

@ -1,5 +1,5 @@
const crypto = require('crypto'); const crypto = require('crypto');
const base32 = require('../utils/base32') const base32 = require('base32')
const OnionRouter = require('./OnionRouter') const OnionRouter = require('./OnionRouter')
const {get} = require('../utils/http') const {get} = require('../utils/http')
const {time} = require('../utils/time') const {time} = require('../utils/time')
@ -18,16 +18,15 @@ class HiddenServiceConnector {
constructor (rendezvous_circuit, onion, logger) { constructor (rendezvous_circuit, onion, logger) {
this._rendezvous_circuit = rendezvous_circuit; this._rendezvous_circuit = rendezvous_circuit;
this._socket = rendezvous_circuit?.tor_socket; this._socket = rendezvous_circuit.tor_socket;
this._consensus = rendezvous_circuit?.tor_socket.onion_router.consensus; this._consensus = rendezvous_circuit.tor_socket.onion_router.consensus;
this._onion = onion; this._onion = onion;
this._permanent_id = Buffer.from(base32.decode(onion)); this._permanent_id = Buffer.from(base32.decode(onion));
this._logger = logger; this._logger = logger;
this._time = time;
} }
async connect() { async connect() {
this._find_responsible_directories(); this.find_responsible_directories();
if (this._responsible_directory_list.length) if (this._responsible_directory_list.length)
{ {
@ -44,7 +43,7 @@ class HiddenServiceConnector {
if (this._rendezvous_circuit.is_rendezvous_established()) if (this._rendezvous_circuit.is_rendezvous_established())
{ {
let responsible_directory_index = 0; let responsible_directory_index = 0;
while ((responsible_directory_index = await this._fetch_hidden_service_descriptor(responsible_directory_index)) !== -1) while ((responsible_directory_index = await this.fetch_hidden_service_descriptor(responsible_directory_index)) !== -1)
{ {
await this.introduce(); await this.introduce();
@ -59,7 +58,7 @@ class HiddenServiceConnector {
return false; return false;
} }
_find_responsible_directories() { find_responsible_directories() {
// //
// rend-spec.txt // rend-spec.txt
// 1.4. // 1.4.
@ -89,7 +88,7 @@ class HiddenServiceConnector {
{ {
const descriptor_id = this.get_descriptor_id(replica); const descriptor_id = this.get_descriptor_id(replica);
const index = directory_list.findIndex(x => Buffer.compare(x.identity_fingerprint, descriptor_id) > 0); const index = directory_list.findIndex(x => Buffer.compare(x.identity_fingerprint, descriptor_id) < 0);
for (let i = 0; i < 3; i++) for (let i = 0; i < 3; i++)
{ {
@ -112,10 +111,10 @@ class HiddenServiceConnector {
// time-period = (current-time + permanent-id-byte * 86400 / 256) // time-period = (current-time + permanent-id-byte * 86400 / 256)
// / 86400 // / 86400
// //
const time_period = Math.floor((this._time() + (permanent_id_byte * 86400 / 256)) / 86400); const time_period = (time() + (permanent_id_byte * 86400 / 256)) / 86400;
const secret_bytes = Buffer.alloc(5); const secret_bytes = Buffer.alloc(5);
secret_bytes.writeUInt32BE(time_period, 0); secret_bytes.writeInt32BE(time_period, 0);
secret_bytes.writeUInt8(replica, 4); secret_bytes.writeUInt8(replica, 4);
return sha1(secret_bytes); return sha1(secret_bytes);
@ -136,7 +135,7 @@ class HiddenServiceConnector {
return sha1(descriptor_id_bytes); return sha1(descriptor_id_bytes);
} }
async _fetch_hidden_service_descriptor(responsible_directory_index) { async fetch_hidden_service_descriptor(responsible_directory_index) {
for (let i = responsible_directory_index; i < this._responsible_directory_list.length; i++) for (let i = responsible_directory_index; i < this._responsible_directory_list.length; i++)
{ {
const responsible_directory = this._responsible_directory_list[i]; const responsible_directory = this._responsible_directory_list[i];
@ -150,6 +149,7 @@ class HiddenServiceConnector {
this._socket.onion_router.name, this._socket.onion_router.name,
this._socket.onion_router.ip, this._socket.onion_router.ip,
this._socket.onion_router.or_port); this._socket.onion_router.or_port);
this._logger.info("\tConnected...");
/** @type Circuit */ /** @type Circuit */
const directory_circuit = await this._socket.create_circuit(); const directory_circuit = await this._socket.create_circuit();
@ -164,10 +164,9 @@ class HiddenServiceConnector {
// //
continue; continue;
} }
this._logger.info("\tConnected...");
this._logger.info( this._logger.info(
"\tExtending circuit for hidden service, connecting to responsible directory '%s' (%s:%i)", "\tExtending circuit for hidden service, connecting to responsible directory '%s' (%s:%u)",
responsible_directory.name, responsible_directory.name,
responsible_directory.ip, responsible_directory.ip,
responsible_directory.or_port); responsible_directory.or_port);
@ -206,10 +205,10 @@ class HiddenServiceConnector {
const descriptor_path = "/tor/rendezvous2/" + base32.encode(this.get_descriptor_id(replica)); const descriptor_path = "/tor/rendezvous2/" + base32.encode(this.get_descriptor_id(replica));
this._logger.debug( this._logger.debug(
"hidden_service::_fetch_hidden_service_descriptor() [path: %s]", "hidden_service::fetch_hidden_service_descriptor() [path: %s]",
descriptor_path); descriptor_path);
this._logger.info("\tSending request for hidden service descriptor... %s:%i", responsible_directory.ip, responsible_directory.dir_port); this._logger.info("\tSending request for hidden service descriptor...");
const hidden_service_descriptor = await get( const hidden_service_descriptor = await get(
'http:', 'http:',
@ -223,7 +222,7 @@ class HiddenServiceConnector {
// //
// parse hidden service descriptor. // parse hidden service descriptor.
// //
if (hidden_service_descriptor && if (!hidden_service_descriptor &&
!hidden_service_descriptor.includes("404 Not found")) !hidden_service_descriptor.includes("404 Not found"))
{ {
this._logger.info("\tHidden service descriptor is valid..."); this._logger.info("\tHidden service descriptor is valid...");
@ -247,14 +246,14 @@ class HiddenServiceConnector {
for (const line of lines) { for (const line of lines) {
const parts = line.split(' '); const parts = line.split(' ');
if (parts[0] === 'introduction-point') { if (parts[0] === 'introduction-point') {
const identity_fingerprint = base32.decode(parts[1]); const identity_fingerprint = Buffer.from(base32.decode(parts[1]));
current_router = this._consensus.get_onion_router_by_identity_fingerprint(identity_fingerprint); current_router = this._consensus.get_onion_router_by_identity_fingerprint(identity_fingerprint);
} else if (parts[0] === 'service-key') { } else if (parts[0] === 'service-key') {
serviceKey = ''; serviceKey = '';
} else if (line === '-----BEGIN RSA PUBLIC KEY-----' && serviceKey !== null) { } else if (parts[0] === '-----BEGIN RSA PUBLIC KEY-----' && serviceKey !== null) {
capture = true; capture = true;
} else if (line === '-----END RSA PUBLIC KEY-----' && serviceKey !== null) { } else if (parts[0] === '-----END RSA PUBLIC KEY-----' && serviceKey !== null) {
current_router.service_key = Buffer.from(serviceKey, 'base64'); current_router.service_key = serviceKey;
introduction_point_list.push(current_router); introduction_point_list.push(current_router);
capture = false; capture = false;
serviceKey = null; serviceKey = null;
@ -337,7 +336,7 @@ class HiddenServiceConnector {
if (introduce_circuit.is_rendezvous_introduced()) if (introduce_circuit.is_rendezvous_introduced())
{ {
this._logger.info("\tIntroduced successfully..."); this._logger.info("\tIntroduced successfully...");
return; break;
} }
else else
{ {

View File

@ -1,22 +0,0 @@
const HiddenServiceConnector = require('./HiddenServiceConnector');
const base32 = require('../utils/base32');
test('base32 decode', function() {
const decoded = base32.decode('duskgytldkxiuqc6');
//const decoded_buf = Array.prototype.map.call(decoded, (_, i) => decoded.charCodeAt(i))
expect(decoded).toEqual(Buffer.from([0x1d,0x24,0xa3,0x62,0x6b,0x1a,0xae,0x8a,0x40,0x5e]));
})
test('base32 encode', function() {
const encoded = base32.encode(Buffer.from([0x1d,0x24,0xa3,0x62,0x6b,0x1a,0xae,0x8a,0x40,0x5e]));
//const decoded_buf = Array.prototype.map.call(decoded, (_, i) => decoded.charCodeAt(i))
expect(encoded).toEqual('duskgytldkxiuqc6');
})
test('test descriptor', function() {
const time = 1611534264;
const onion = 'duskgytldkxiuqc6';
const sut = new HiddenServiceConnector(null, onion, null);
sut._time = () => time;
const descriptor = sut.get_descriptor_id(0);
const descriptor_base32 = base32.encode(descriptor);
expect(descriptor_base32).toBe('ek7vymlparcwqimmmfixlbars4xjz5jl');
})

View File

@ -1,123 +0,0 @@
const crypto = require('crypto')
const dh1024 = require('../utils/dh1024')
const {sha1} = require('../utils/crypto')
const DH_P = new Buffer([
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34,
0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74,
0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd,
0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37,
0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6,
0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed,
0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6,
0x49, 0x28, 0x66, 0x51, 0xec, 0xe6, 0x53, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
]);
class KeyAgreementTap {
constructor (or) {
this._router = or;
this._dh = crypto.createDiffieHellman(DH_P);
this._dh.generateKeys();
}
get public_key() {
return this._dh.getPublicKey();
}
get private_key() {
return this._dh.getPrivateKey();
}
compute_shared_secret(handshake_data) {
return this._compute_shared_secret(
handshake_data.slice(0, dh1024.key_size_in_bytes),
handshake_data.slice(dh1024.key_size_in_bytes, dh1024.key_size_in_bytes + 20));
}
_compute_shared_secret(other_public_key, verification_data) {
//
// 5.1.3. The "TAP" handshake
//
// This handshake uses Diffie-Hellman in Z_p and RSA to compute a set of
// shared keys which the client knows are shared only with a particular
// server, and the server knows are shared with whomever sent the
// original handshake (or with nobody at all). It's not very fast and
// not very good. (See Goldberg's "On the Security of the Tor
// Authentication Protocol".)
//
// Define TAP_C_HANDSHAKE_LEN as DH_LEN+KEY_LEN+PK_PAD_LEN.
// Define TAP_S_HANDSHAKE_LEN as DH_LEN+HASH_LEN.
//
// The payload for a CREATE cell is an 'onion skin', which consists of
// the first step of the DH handshake data (also known as g^x). This
// value is hybrid-encrypted (see 0.3) to the server's onion key, giving
// a client handshake of:
//
// PK-encrypted:
// Padding [PK_PAD_LEN bytes]
// Symmetric key [KEY_LEN bytes]
// First part of g^x [PK_ENC_LEN-PK_PAD_LEN-KEY_LEN bytes]
// Symmetrically encrypted:
// Second part of g^x [DH_LEN-(PK_ENC_LEN-PK_PAD_LEN-KEY_LEN)
// bytes]
//
// The payload for a CREATED cell, or the relay payload for an
// EXTENDED cell, contains:
// DH data (g^y) [DH_LEN bytes]
// Derivative key data (KH) [HASH_LEN bytes] <see 5.2 below>
//
// Once the handshake between the OP and an OR is completed, both can
// now calculate g^xy with ordinary DH. Before computing g^xy, both parties
// MUST verify that the received g^x or g^y value is not degenerate;
// that is, it must be strictly greater than 1 and strictly less than p-1
// where p is the DH modulus. Implementations MUST NOT complete a handshake
// with degenerate keys. Implementations MUST NOT discard other "weak"
// g^x values.
//
// (Discarding degenerate keys is critical for security; if bad keys
// are not discarded, an attacker can substitute the OR's CREATED
// cell's g^y with 0 or 1, thus creating a known g^xy and impersonating
// the OR. Discarding other keys may allow attacks to learn bits of
// the private key.)
//
// Once both parties have g^xy, they derive their shared circuit keys
// and 'derivative key data' value via the KDF-TOR function in 5.2.1.
//
//mini_assert(verification_data.get_size() == crypto::sha1::hash_size_in_bytes);
const shared_secret = this._dh.computeSecret(other_public_key);
const derived = this._derive_keys(shared_secret);
//
// first 20 bytes of the derived key is the verification checksum.
// rest of it is the key material.
//
const computed_verification_data = derived.slice(0, 20);
const key_material = derived.slice(20);
if (computed_verification_data.equals(verification_data))
{
return key_material;
}
return Buffer.alloc(0);
}
_derive_keys(secret) {
const key_material = Buffer.alloc(100);
const hashdata = Buffer.alloc(secret.length + 1);
secret.copy(hashdata, 0);
for (let i = 0; i < 5; i++)
{
hashdata[secret.length] = i;
sha1(hashdata).copy(key_material, i * 20);
}
return key_material;
}
}
module.exports = KeyAgreementTap;

View File

@ -59,26 +59,12 @@ class OnionRouter {
const descriptor = await this._consensus.get_onion_router_descriptor(this._identity_fingerprint); const descriptor = await this._consensus.get_onion_router_descriptor(this._identity_fingerprint);
// parse // parse
const lines = descriptor.split('\n'); const lines = descriptor.split('\n');
let capture = '', onion_key = '';
for (const line of lines){ for (const line of lines){
const parts = line.split(' '); const parts = line.split(' ');
if (parts[0] === 'onion-key') { if (parts[0] === 'ntor-onion-key') {
capture = 'onion-key';
}
else if (parts[0] === 'ntor-onion-key') {
this._ntor_onion_key = Buffer.from(parts[1], 'base64'); this._ntor_onion_key = Buffer.from(parts[1], 'base64');
break; break;
} }
else if (capture === 'onion-key' && line === '-----BEGIN RSA PUBLIC KEY-----') {
onion_key = '';
}
else if (capture === 'onion-key' && line === '-----END RSA PUBLIC KEY-----') {
this._onion_key = Buffer.from(onion_key, 'base64')
capture = '';
}
else if (capture === 'onion-key') {
onion_key += line;
}
} }
this._descriptor_fetched = true; this._descriptor_fetched = true;
} }

View File

@ -40,11 +40,6 @@ class TorStream extends Duplex {
set state(state) { set state(state) {
this._state = state; this._state = state;
if (state === States.destroyed) { if (state === States.destroyed) {
if (this._buffer) {
this.push(this._buffer);
this._buffer = null;
}
this.push(null);
for (const k in this._waits) { for (const k in this._waits) {
for (const wait of this._waits[k]) { for (const wait of this._waits[k]) {
wait.resolve(false); wait.resolve(false);
@ -62,12 +57,12 @@ class TorStream extends Duplex {
} }
append_to_recv_buffer(data) { append_to_recv_buffer(data) {
this._buffer = this._buffer
? Buffer.concat([this._buffer, data], this._buffer.length + data.length)
: data;
if (this._canRead) { if (this._canRead) {
this._canRead = this.push(this._buffer); this._canRead = this.push(data);
this._buffer = null; } else {
this._buffer = this._buffer
? Buffer.concat([this._buffer, data], this._buffer.length + data.length)
: data;
} }
} }

View File

@ -1,51 +0,0 @@
const alphabet = 'abcdefghijklmnopqrstuvwxyz234567'
function decode_chunk(input, in_offset, output, out_offset) {
let b = BigInt(0);
for (let i = 0; i < 8; i++) {
b = (b << 5n) | BigInt(alphabet.indexOf(input[in_offset + i]));
}
for (let j = 4; j >= 0; j--) {
output[out_offset + 4 - j] = Number(b >> BigInt(j * 8));
}
}
function decode(input) {
const out_len = Math.ceil((input.length / 8) * 5);
const output = Buffer.alloc(out_len);
const q = Math.floor(input.length / 8);
for (let i = 0; i < q; i++) {
decode_chunk(input, i * 8, output, i * 5);
}
return output;
}
exports.decode = decode;
function encode_chunk(input, in_offset, output, out_offset) {
let b = BigInt(0);
for (let i = 0; i < 5; i++) {
b = (b << 8n) | BigInt(input[in_offset + i]);
}
for (let i = 7; i >= 0; i--) {
b = b << BigInt(24 + (7 - i) * 5);
b = b >> BigInt(24 + (7 - i) * 5);
const c = Number(b >> BigInt(i * 5)) % 32;
output[out_offset + 7 - i] = alphabet.charCodeAt(c);
}
}
function encode(input) {
const out_len = Math.ceil(input.length / 5 * 8);
const output = Buffer.alloc(out_len);
const q = Math.floor(input.length / 5);
for (let i = 0; i < q; i++) {
encode_chunk(input, i * 5, output, i * 8);
}
return output.toString('ascii');
}
exports.encode = encode;

View File

@ -44,13 +44,13 @@ const PK_DATA_LEN_WITH_KEY = PK_DATA_LEN - KEY_LEN;
/** /**
* @param {Buffer} data * @param {Buffer} data
* @param {string} public_key * @param {Buffer} public_key
* @returns {Buffer} * @returns {Buffer}
*/ */
function hybrid_encrypt(data, public_key) { function hybrid_encrypt(data, public_key) {
if (data.length < PK_DATA_LEN) if (data.length < PK_DATA_LEN)
{ {
return crypto.publicEncrypt(public_key, data); return rsa_1024(public_key).encrypt(data);
} }
const random_key = crypto.randomBytes(KEY_LEN); const random_key = crypto.randomBytes(KEY_LEN);
@ -62,7 +62,7 @@ function hybrid_encrypt(data, public_key) {
random_key, data.slice(0, PK_DATA_LEN_WITH_KEY) random_key, data.slice(0, PK_DATA_LEN_WITH_KEY)
], random_key.length + PK_DATA_LEN_WITH_KEY); ], random_key.length + PK_DATA_LEN_WITH_KEY);
const c1 = crypto.publicEncrypt(public_key, k_and_m1); const c1 = rsa_1024(public_key).encrypt(k_and_m1);
// //
// AES_CTR(M2) --> C2 // AES_CTR(M2) --> C2

View File

@ -1 +0,0 @@
exports.key_size_in_bytes = (1024/8);

View File

@ -28,7 +28,7 @@ async function get(protocol, ip, port, path, stream) {
res.on('data', chunk => data += chunk.toString()); res.on('data', chunk => data += chunk.toString());
res.on('end', () => resolve(data)); res.on('end', () => resolve(data));
res.on('error', (err) => reject(err)); res.on('error', (err) => reject(err));
}).on('error', err => reject(err)); });
}); });
} }