Compare commits
	
		
			2 Commits
		
	
	
		
			b1189bd237
			...
			a9f3348a01
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a9f3348a01 | |||
| 542e31cd96 | 
							
								
								
									
										3625
									
								
								doc/dir-spec.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3625
									
								
								doc/dir-spec.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										35335
									
								
								doc/example-descriptors/consensus.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35335
									
								
								doc/example-descriptors/consensus.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
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-----
 | 
			
		||||
							
								
								
									
										45
									
								
								doc/example-descriptors/introduction-point.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								doc/example-descriptors/introduction-point.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
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-----
 | 
			
		||||
@@ -0,0 +1,54 @@
 | 
			
		||||
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-----
 | 
			
		||||
							
								
								
									
										1075
									
								
								doc/rend-spec.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1075
									
								
								doc/rend-spec.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1612
									
								
								doc/tor-spec.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1612
									
								
								doc/tor-spec.txt
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										4236
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4236
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -3,6 +3,7 @@
 | 
			
		||||
    "base32": "0.0.6",
 | 
			
		||||
    "curve25519-js": "0.0.4",
 | 
			
		||||
    "futoin-hkdf": "^1.3.2",
 | 
			
		||||
    "jest": "^26.6.3",
 | 
			
		||||
    "tweetnacl": "^1.0.3"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -281,8 +281,34 @@ class Circuit {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _on_relay_extended_cell(cell) {
 | 
			
		||||
    //TODO
 | 
			
		||||
    throw new Error('Not implemented')
 | 
			
		||||
    //
 | 
			
		||||
    // The payload of an EXTENDED cell is the same as the payload of a
 | 
			
		||||
    // 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) {
 | 
			
		||||
@@ -752,7 +778,7 @@ class Circuit {
 | 
			
		||||
    //mini_assert(rendezvous_cookie.get_size() == 20);
 | 
			
		||||
 | 
			
		||||
    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.state = States.rendezvous_introducing;
 | 
			
		||||
@@ -790,7 +816,7 @@ class Circuit {
 | 
			
		||||
      2  +  // port
 | 
			
		||||
      20 +  // identity_fingerprint
 | 
			
		||||
      2  +  // onion key size
 | 
			
		||||
      32 +  // onion key
 | 
			
		||||
      introducee.onion_key.length +  // onion key
 | 
			
		||||
      20 +  // rendezvous cookie
 | 
			
		||||
      128); // DH
 | 
			
		||||
 | 
			
		||||
@@ -808,7 +834,14 @@ class Circuit {
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    const handshake_encrypted = hybrid_encrypt(handshake_bytes, introduction_point.service_key);
 | 
			
		||||
    const b64 = introduction_point.service_key.toString('base64');
 | 
			
		||||
    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.
 | 
			
		||||
@@ -841,7 +874,7 @@ class Circuit {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (await rendezvous_circuit.wait_for_state(States.rendezvous_completed))
 | 
			
		||||
    if (await rendezvous_circuit.wait_for_state(States.rendezvous_completed, 90000))
 | 
			
		||||
    {
 | 
			
		||||
      this._logger.debug("Circuit.rendezvous_introduce() [or: %s, state: completed]", introduction_point.name);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
const KeyAgreementNtor = require('./KeyAgreementNtor');
 | 
			
		||||
const KeyAgreementTap = require('./KeyAgreementTap');
 | 
			
		||||
const CircuitNodeCryptoState = require('./CircuitNodeCryptoState');
 | 
			
		||||
 | 
			
		||||
class CircuitNode {
 | 
			
		||||
@@ -6,7 +7,7 @@ class CircuitNode {
 | 
			
		||||
  /** @type OnionRouter */
 | 
			
		||||
  _onion_router = null;
 | 
			
		||||
  _type = 'normal';
 | 
			
		||||
  /** @type KeyAgreementNtor */
 | 
			
		||||
  /** @type {KeyAgreementNtor|KeyAgreementTap} */
 | 
			
		||||
  _handshake = null;
 | 
			
		||||
  /** @type CircuitNodeCryptoState */
 | 
			
		||||
  _crypto_state = null;
 | 
			
		||||
@@ -22,6 +23,9 @@ class CircuitNode {
 | 
			
		||||
    this._circuit = circuit;
 | 
			
		||||
    this._onion_router = or;
 | 
			
		||||
    this._type = type;
 | 
			
		||||
    if (type === 'introductionpoint') {
 | 
			
		||||
      this._handshake = new KeyAgreementTap(or);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  create_onion_skin_ntor() {
 | 
			
		||||
 
 | 
			
		||||
@@ -193,7 +193,7 @@ class Consensus {
 | 
			
		||||
   * @return {Promise<string>}
 | 
			
		||||
   * @private
 | 
			
		||||
   */
 | 
			
		||||
  _download_from_random_router_impl(path, only_authorities) {
 | 
			
		||||
  async _download_from_random_router_impl(path, only_authorities) {
 | 
			
		||||
    let ip;
 | 
			
		||||
    let port;
 | 
			
		||||
 | 
			
		||||
@@ -222,7 +222,11 @@ class Consensus {
 | 
			
		||||
 | 
			
		||||
    this._logger.debug(`Consensus._download_from_random_router_impl() [path: http://${ip}:${port}${path}]`);
 | 
			
		||||
 | 
			
		||||
    return get('http:', ip, port, path);
 | 
			
		||||
    try {
 | 
			
		||||
      return await get('http:', ip, port, path);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      return '';
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _parse_consensus(content) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
const crypto = require('crypto');
 | 
			
		||||
const base32 = require('base32')
 | 
			
		||||
const base32 = require('../utils/base32')
 | 
			
		||||
const OnionRouter = require('./OnionRouter')
 | 
			
		||||
const {get} = require('../utils/http')
 | 
			
		||||
const {time} = require('../utils/time')
 | 
			
		||||
@@ -18,15 +18,16 @@ class HiddenServiceConnector {
 | 
			
		||||
 | 
			
		||||
  constructor (rendezvous_circuit, onion, logger) {
 | 
			
		||||
    this._rendezvous_circuit = rendezvous_circuit;
 | 
			
		||||
    this._socket = rendezvous_circuit.tor_socket;
 | 
			
		||||
    this._consensus = rendezvous_circuit.tor_socket.onion_router.consensus;
 | 
			
		||||
    this._socket = rendezvous_circuit?.tor_socket;
 | 
			
		||||
    this._consensus = rendezvous_circuit?.tor_socket.onion_router.consensus;
 | 
			
		||||
    this._onion = onion;
 | 
			
		||||
    this._permanent_id = Buffer.from(base32.decode(onion));
 | 
			
		||||
    this._logger = logger;
 | 
			
		||||
    this._time = time;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async connect() {
 | 
			
		||||
    this.find_responsible_directories();
 | 
			
		||||
    this._find_responsible_directories();
 | 
			
		||||
 | 
			
		||||
    if (this._responsible_directory_list.length)
 | 
			
		||||
    {
 | 
			
		||||
@@ -43,7 +44,7 @@ class HiddenServiceConnector {
 | 
			
		||||
      if (this._rendezvous_circuit.is_rendezvous_established())
 | 
			
		||||
      {
 | 
			
		||||
        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();
 | 
			
		||||
 | 
			
		||||
@@ -58,7 +59,7 @@ class HiddenServiceConnector {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  find_responsible_directories() {
 | 
			
		||||
  _find_responsible_directories() {
 | 
			
		||||
    //
 | 
			
		||||
    // rend-spec.txt
 | 
			
		||||
    // 1.4.
 | 
			
		||||
@@ -88,7 +89,7 @@ class HiddenServiceConnector {
 | 
			
		||||
    {
 | 
			
		||||
      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++)
 | 
			
		||||
      {
 | 
			
		||||
@@ -111,10 +112,10 @@ class HiddenServiceConnector {
 | 
			
		||||
    //   time-period = (current-time + permanent-id-byte * 86400 / 256)
 | 
			
		||||
    //                   / 86400
 | 
			
		||||
    //
 | 
			
		||||
    const time_period = (time() + (permanent_id_byte * 86400 / 256)) / 86400;
 | 
			
		||||
    const time_period = Math.floor((this._time() + (permanent_id_byte * 86400 / 256)) / 86400);
 | 
			
		||||
 | 
			
		||||
    const secret_bytes = Buffer.alloc(5);
 | 
			
		||||
    secret_bytes.writeInt32BE(time_period, 0);
 | 
			
		||||
    secret_bytes.writeUInt32BE(time_period, 0);
 | 
			
		||||
    secret_bytes.writeUInt8(replica, 4);
 | 
			
		||||
 | 
			
		||||
    return sha1(secret_bytes);
 | 
			
		||||
@@ -135,7 +136,7 @@ class HiddenServiceConnector {
 | 
			
		||||
    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++)
 | 
			
		||||
    {
 | 
			
		||||
      const responsible_directory = this._responsible_directory_list[i];
 | 
			
		||||
@@ -149,7 +150,6 @@ class HiddenServiceConnector {
 | 
			
		||||
        this._socket.onion_router.name,
 | 
			
		||||
        this._socket.onion_router.ip,
 | 
			
		||||
        this._socket.onion_router.or_port);
 | 
			
		||||
      this._logger.info("\tConnected...");
 | 
			
		||||
 | 
			
		||||
      /** @type Circuit */
 | 
			
		||||
      const directory_circuit = await this._socket.create_circuit();
 | 
			
		||||
@@ -164,9 +164,10 @@ class HiddenServiceConnector {
 | 
			
		||||
        //
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      this._logger.info("\tConnected...");
 | 
			
		||||
 | 
			
		||||
      this._logger.info(
 | 
			
		||||
        "\tExtending circuit for hidden service, connecting to responsible directory '%s' (%s:%u)",
 | 
			
		||||
        "\tExtending circuit for hidden service, connecting to responsible directory '%s' (%s:%i)",
 | 
			
		||||
        responsible_directory.name,
 | 
			
		||||
        responsible_directory.ip,
 | 
			
		||||
        responsible_directory.or_port);
 | 
			
		||||
@@ -205,10 +206,10 @@ class HiddenServiceConnector {
 | 
			
		||||
      const descriptor_path = "/tor/rendezvous2/" + base32.encode(this.get_descriptor_id(replica));
 | 
			
		||||
 | 
			
		||||
      this._logger.debug(
 | 
			
		||||
        "hidden_service::fetch_hidden_service_descriptor() [path: %s]",
 | 
			
		||||
        "hidden_service::_fetch_hidden_service_descriptor() [path: %s]",
 | 
			
		||||
        descriptor_path);
 | 
			
		||||
 | 
			
		||||
      this._logger.info("\tSending request for hidden service descriptor...");
 | 
			
		||||
      this._logger.info("\tSending request for hidden service descriptor... %s:%i", responsible_directory.ip, responsible_directory.dir_port);
 | 
			
		||||
 | 
			
		||||
      const hidden_service_descriptor = await get(
 | 
			
		||||
        'http:',
 | 
			
		||||
@@ -222,7 +223,7 @@ class HiddenServiceConnector {
 | 
			
		||||
      //
 | 
			
		||||
      // parse hidden service descriptor.
 | 
			
		||||
      //
 | 
			
		||||
      if (!hidden_service_descriptor &&
 | 
			
		||||
      if (hidden_service_descriptor &&
 | 
			
		||||
          !hidden_service_descriptor.includes("404 Not found"))
 | 
			
		||||
      {
 | 
			
		||||
        this._logger.info("\tHidden service descriptor is valid...");
 | 
			
		||||
@@ -246,14 +247,14 @@ class HiddenServiceConnector {
 | 
			
		||||
        for (const line of lines) {
 | 
			
		||||
          const parts = line.split(' ');
 | 
			
		||||
          if (parts[0] === 'introduction-point') {
 | 
			
		||||
            const identity_fingerprint = Buffer.from(base32.decode(parts[1]));
 | 
			
		||||
            const identity_fingerprint = base32.decode(parts[1]);
 | 
			
		||||
            current_router = this._consensus.get_onion_router_by_identity_fingerprint(identity_fingerprint);
 | 
			
		||||
          } else if (parts[0] === 'service-key') {
 | 
			
		||||
            serviceKey = '';
 | 
			
		||||
          } else if (parts[0] === '-----BEGIN RSA PUBLIC KEY-----' && serviceKey !== null) {
 | 
			
		||||
          } else if (line === '-----BEGIN RSA PUBLIC KEY-----' && serviceKey !== null) {
 | 
			
		||||
            capture = true;
 | 
			
		||||
          } else if (parts[0] === '-----END RSA PUBLIC KEY-----' && serviceKey !== null) {
 | 
			
		||||
            current_router.service_key = serviceKey;
 | 
			
		||||
          } else if (line === '-----END RSA PUBLIC KEY-----' && serviceKey !== null) {
 | 
			
		||||
            current_router.service_key = Buffer.from(serviceKey, 'base64');
 | 
			
		||||
            introduction_point_list.push(current_router);
 | 
			
		||||
            capture = false;
 | 
			
		||||
            serviceKey = null;
 | 
			
		||||
@@ -336,7 +337,7 @@ class HiddenServiceConnector {
 | 
			
		||||
      if (introduce_circuit.is_rendezvous_introduced())
 | 
			
		||||
      {
 | 
			
		||||
        this._logger.info("\tIntroduced successfully...");
 | 
			
		||||
        break;
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								src/tor/HiddenServiceConnector.test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/tor/HiddenServiceConnector.test.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
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');
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										123
									
								
								src/tor/KeyAgreementTap.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/tor/KeyAgreementTap.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,123 @@
 | 
			
		||||
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;
 | 
			
		||||
@@ -59,12 +59,26 @@ class OnionRouter {
 | 
			
		||||
    const descriptor = await this._consensus.get_onion_router_descriptor(this._identity_fingerprint);
 | 
			
		||||
    // parse
 | 
			
		||||
    const lines = descriptor.split('\n');
 | 
			
		||||
    let capture = '', onion_key = '';
 | 
			
		||||
    for (const line of lines){
 | 
			
		||||
      const parts = line.split(' ');
 | 
			
		||||
      if (parts[0] === 'ntor-onion-key') {
 | 
			
		||||
      if (parts[0] === 'onion-key') {
 | 
			
		||||
        capture = 'onion-key';
 | 
			
		||||
      }
 | 
			
		||||
      else if (parts[0] === 'ntor-onion-key') {
 | 
			
		||||
        this._ntor_onion_key = Buffer.from(parts[1], 'base64');
 | 
			
		||||
        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;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,11 @@ class TorStream extends Duplex {
 | 
			
		||||
  set state(state) {
 | 
			
		||||
    this._state = state;
 | 
			
		||||
    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 wait of this._waits[k]) {
 | 
			
		||||
          wait.resolve(false);
 | 
			
		||||
@@ -57,12 +62,12 @@ class TorStream extends Duplex {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  append_to_recv_buffer(data) {
 | 
			
		||||
    this._buffer = this._buffer
 | 
			
		||||
      ? Buffer.concat([this._buffer, data], this._buffer.length + data.length)
 | 
			
		||||
      : data;
 | 
			
		||||
    if (this._canRead) {
 | 
			
		||||
      this._canRead = this.push(data);
 | 
			
		||||
    } else {
 | 
			
		||||
      this._buffer = this._buffer
 | 
			
		||||
        ? Buffer.concat([this._buffer, data], this._buffer.length + data.length)
 | 
			
		||||
        : data;
 | 
			
		||||
      this._canRead = this.push(this._buffer);
 | 
			
		||||
      this._buffer = null;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										51
									
								
								src/utils/base32.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/utils/base32.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
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;
 | 
			
		||||
@@ -44,13 +44,13 @@ const PK_DATA_LEN_WITH_KEY = PK_DATA_LEN - KEY_LEN;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @param {Buffer} data
 | 
			
		||||
 * @param {Buffer} public_key
 | 
			
		||||
 * @param {string} public_key
 | 
			
		||||
 * @returns {Buffer}
 | 
			
		||||
 */
 | 
			
		||||
function hybrid_encrypt(data, public_key) {
 | 
			
		||||
  if (data.length < PK_DATA_LEN)
 | 
			
		||||
  {
 | 
			
		||||
    return rsa_1024(public_key).encrypt(data);
 | 
			
		||||
    return crypto.publicEncrypt(public_key, data);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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.length + PK_DATA_LEN_WITH_KEY);
 | 
			
		||||
 | 
			
		||||
  const c1 = rsa_1024(public_key).encrypt(k_and_m1);
 | 
			
		||||
  const c1 = crypto.publicEncrypt(public_key, k_and_m1);
 | 
			
		||||
 | 
			
		||||
  //
 | 
			
		||||
  // AES_CTR(M2)  --> C2
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								src/utils/dh1024.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/utils/dh1024.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
exports.key_size_in_bytes = (1024/8);
 | 
			
		||||
@@ -28,7 +28,7 @@ async function get(protocol, ip, port, path, stream) {
 | 
			
		||||
      res.on('data', chunk => data += chunk.toString());
 | 
			
		||||
      res.on('end', () => resolve(data));
 | 
			
		||||
      res.on('error', (err) => reject(err));
 | 
			
		||||
    });
 | 
			
		||||
    }).on('error', err => reject(err));
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user