Plots, fixes
This commit is contained in:
parent
29b3119720
commit
fb5adf26f1
4 changed files with 293 additions and 89 deletions
114
README.md
114
README.md
|
|
@ -107,10 +107,6 @@ Most of the implementations can be used through RusTLS.
|
||||||
|
|
||||||
However RusTLS clients won't enable to force TLS1.2 if 1.3 is available.
|
However RusTLS clients won't enable to force TLS1.2 if 1.3 is available.
|
||||||
|
|
||||||
### rpxy
|
|
||||||
|
|
||||||
Reverse-proxy utilisant RusTLS.
|
|
||||||
|
|
||||||
### WolfSSL
|
### WolfSSL
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -122,31 +118,6 @@ make
|
||||||
sudo make install
|
sudo make install
|
||||||
```
|
```
|
||||||
|
|
||||||
### self-signed cert
|
|
||||||
|
|
||||||
```bash
|
|
||||||
openssl req -x509 -newkey rsa:2048 -keyout /tmp/foo.home.key -subj "/CN=foo.home/C=AT/ST=Lyon/L=Lyon/O=MyOrg" -out /tmp/foo.home.crt -nodes -sha256 -addext "subjectAltName=DNS:foo.home"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Client
|
|
||||||
|
|
||||||
Automatize experiments using [Selenium](https://www.selenium.dev/documentation/webdriver/getting_started/)
|
|
||||||
|
|
||||||
#### Experiment management
|
|
||||||
|
|
||||||
* Manager tells P2 what shared libs and rpxy binary to load.
|
|
||||||
* Tell P1, P2, P3 what rpxy config to load.
|
|
||||||
* Start measures.
|
|
||||||
* Start Yocto (USB).
|
|
||||||
* Start
|
|
||||||
|
|
||||||
#### Ad-hoc proxy?
|
|
||||||
|
|
||||||
Features:
|
|
||||||
* Use RusTLS and any backend easily
|
|
||||||
* Listen to plain HTTP or TLS (1.2 or 1.3)
|
|
||||||
*
|
|
||||||
|
|
||||||
## State of the art
|
## State of the art
|
||||||
|
|
||||||
* https://pub.h-brs.de/frontdoor/deliver/index/docId/4771/file/2019-ESP32-TLS-Power.pdf
|
* https://pub.h-brs.de/frontdoor/deliver/index/docId/4771/file/2019-ESP32-TLS-Power.pdf
|
||||||
|
|
@ -175,13 +146,68 @@ Features:
|
||||||
* https://github.com/MarcT0K/privacy-carbon-experiments
|
* https://github.com/MarcT0K/privacy-carbon-experiments
|
||||||
* https://davidtnaylor.com/CostOfTheS.pdf
|
* https://davidtnaylor.com/CostOfTheS.pdf
|
||||||
* 2014
|
* 2014
|
||||||
*
|
|
||||||
|
|
||||||
## Sources
|
## Sources
|
||||||
|
|
||||||
* [RFC8446 (TLS 1.3)](https://datatracker.ietf.org/doc/html/rfc8446)
|
* [RFC8446 (TLS 1.3)](https://datatracker.ietf.org/doc/html/rfc8446)
|
||||||
|
|
||||||
## Notes
|
## Reproduce
|
||||||
|
|
||||||
|
### Record
|
||||||
|
|
||||||
|
Authorize rpxy and netreplay to bind to ports 80 and 443:
|
||||||
|
```bash
|
||||||
|
sudo setcap CAP_NET_BIND_SERVICE=+eip netreplay
|
||||||
|
```
|
||||||
|
|
||||||
|
Open Firefox with a dedicated profile: (create the profile using the GUI if it doesn't exist)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
firefox -P tlsbench
|
||||||
|
```
|
||||||
|
|
||||||
|
In settings, disable DNS security.
|
||||||
|
|
||||||
|
In `about:config`, set `devtools.chrome.enabled` to `true`.
|
||||||
|
|
||||||
|
In the `about:config` tab, open the console, execute this script to override DNS for the selected names, and redirect them to localhost:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const gOverride = Cc["@mozilla.org/network/native-dns-override;1"].getService(Ci.nsINativeDNSResolverOverride);
|
||||||
|
gOverride.clearOverrides();
|
||||||
|
var names = [
|
||||||
|
"apple.com", "www.apple.com",
|
||||||
|
"yt3.ggpht.com",
|
||||||
|
"accounts.google.com", "www.google.com",
|
||||||
|
"fonts.gstatic.com", "www.gstatic.com",
|
||||||
|
"mzstatic.com",
|
||||||
|
"wikimedia.org", "intake-analytics.wikimedia.org", "meta.wikimedia.org", "upload.wikimedia.org",
|
||||||
|
"wikipedia.org", "fr.wikipedia.org",
|
||||||
|
"youtube.com", "www.youtube.com",
|
||||||
|
"i.ytimg.com"
|
||||||
|
];
|
||||||
|
for(var i in names) {
|
||||||
|
gOverride.addIPOverride(names[i], "127.0.0.1");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Stop anything running on ports 80 or 443.
|
||||||
|
|
||||||
|
Start the record proxy:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./netreplay records/mynewrecord record
|
||||||
|
```
|
||||||
|
|
||||||
|
Just browse. Any traffic to and from the selected names will be recorded. Terminate netplayer with CTRL+C when finished.
|
||||||
|
|
||||||
|
### Measure
|
||||||
|
|
||||||
|
Add p2 the `/etc/hosts`:
|
||||||
|
|
||||||
|
```
|
||||||
|
192.168.3.14 p2
|
||||||
|
```
|
||||||
|
|
||||||
Install sa on p2:
|
Install sa on p2:
|
||||||
|
|
||||||
|
|
@ -190,35 +216,11 @@ sudo apt install acct
|
||||||
sudo chmod +s /sbin/sa
|
sudo chmod +s /sbin/sa
|
||||||
```
|
```
|
||||||
|
|
||||||
Override DNS in browser:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
firefox -P tlsbench
|
|
||||||
```
|
|
||||||
|
|
||||||
In `about:config`, set `devtools.chrome.enabled` to `true`.
|
|
||||||
Set default DNS in settings.
|
|
||||||
In console:
|
|
||||||
|
|
||||||
```js
|
|
||||||
const gOverride = Cc["@mozilla.org/network/native-dns-override;1"].getService(Ci.nsINativeDNSResolverOverride);
|
|
||||||
gOverride.clearOverrides();
|
|
||||||
var names = ["apple.com", "www.apple.com", "mzstatic.com", "youtube.com", "www.youtube.com", "i.ytimg.com", "fonts.gstatic.com", "www.google.com", "accounts.google.com", "yt3.ggpht.com", "www.gstatic.com"];
|
|
||||||
for(var i in names) {
|
|
||||||
gOverride.addIPOverride(names[i], "127.0.0.1");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Authorize rpxy to bind to ports 80 and 443:
|
|
||||||
```bash
|
|
||||||
sudo setcap CAP_NET_BIND_SERVICE=+eip netreplay
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python exp.py make -c
|
python exp.py make -c
|
||||||
python exp.py send
|
python exp.py send
|
||||||
python exp.py update-certs # also do this command on p2
|
python exp.py update-certs # also do this command on p2
|
||||||
python exp.py run
|
python exp.py run --idle
|
||||||
```
|
```
|
||||||
|
|
||||||
On Debian, update-certs says 0 certs added even if it has actually updated some certs. This step is still needed.
|
On Debian, update-certs says 0 certs added even if it has actually updated some certs. This step is still needed.
|
||||||
|
|
|
||||||
120
exp.py
120
exp.py
|
|
@ -6,6 +6,7 @@ P2_SSH = "exp@p2"
|
||||||
P2_PSW = "exp"
|
P2_PSW = "exp"
|
||||||
P2_REPODIR = "/home/exp/exp"
|
P2_REPODIR = "/home/exp/exp"
|
||||||
EXPDIR = "/dev/shm/exp"
|
EXPDIR = "/dev/shm/exp"
|
||||||
|
LOG_BACKUP_DIR = "/home/tuxmain"
|
||||||
P2_ADDR = "192.168.3.14"
|
P2_ADDR = "192.168.3.14"
|
||||||
DOMAINS_ = [
|
DOMAINS_ = [
|
||||||
# Apple
|
# Apple
|
||||||
|
|
@ -33,11 +34,11 @@ DOMAINS_ = [
|
||||||
WATTMETER = True
|
WATTMETER = True
|
||||||
|
|
||||||
RECORDS = [
|
RECORDS = [
|
||||||
#{ "filename": "youtube", "repeat": 1 },
|
#{ "filename": "youtube", "repeat": 1000 },
|
||||||
#{ "filename": "peertube", "repeat": 10 },
|
#{ "filename": "peertube", "repeat": 10 },
|
||||||
#{ "filename": "wikipedia", "repeat": 10 },
|
{ "filename": "wikipedia", "repeat": 100 },
|
||||||
{ "filename": "apple", "repeat": 100 },
|
#{ "filename": "apple", "repeat": 1000 },
|
||||||
#{ "filename": "google", "repeat": 10 },
|
#{ "filename": "google", "repeat": 1000 },
|
||||||
]
|
]
|
||||||
CERT_SIGN_ALGS = [
|
CERT_SIGN_ALGS = [
|
||||||
"prime256v1", # widely used
|
"prime256v1", # widely used
|
||||||
|
|
@ -46,8 +47,8 @@ CERT_SIGN_ALGS = [
|
||||||
"rsa2048", "rsa3072", "rsa4096", # widely used
|
"rsa2048", "rsa3072", "rsa4096", # widely used
|
||||||
]
|
]
|
||||||
IMPLS = [
|
IMPLS = [
|
||||||
#"aws_lc_rs", # Amazon's Rust crypto widely used in Rust stuff
|
"aws_lc_rs", # Amazon's Rust crypto widely used in Rust stuff
|
||||||
#"boring", # Google's fork of OpenSSL used in Chrome and Android
|
"boring", # Google's fork of OpenSSL used in Chrome and Android
|
||||||
"openssl", # widely used
|
"openssl", # widely used
|
||||||
#"ring", # used in most Rust stuff
|
#"ring", # used in most Rust stuff
|
||||||
#"symcrypt", # Microsoft's crypto
|
#"symcrypt", # Microsoft's crypto
|
||||||
|
|
@ -72,6 +73,7 @@ KEXES = [
|
||||||
"SECP256R1",
|
"SECP256R1",
|
||||||
"SECP384R1",
|
"SECP384R1",
|
||||||
]
|
]
|
||||||
|
IDLE = "idle - - - - - - 600.000081539154 0.0 896 4792 0.5399999999999991"
|
||||||
|
|
||||||
# Testing all combinations would be too much. Instead we isolate independent parts.
|
# Testing all combinations would be too much. Instead we isolate independent parts.
|
||||||
EXPERIMENTS = {
|
EXPERIMENTS = {
|
||||||
|
|
@ -83,36 +85,36 @@ EXPERIMENTS = {
|
||||||
"AES_128_GCM_SHA256",
|
"AES_128_GCM_SHA256",
|
||||||
"AES_256_GCM_SHA384",
|
"AES_256_GCM_SHA384",
|
||||||
"CHACHA20_POLY1305_SHA256",
|
"CHACHA20_POLY1305_SHA256",
|
||||||
"ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
#"ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
"ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
#"ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
"ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
#"ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
],
|
],
|
||||||
"kexes": ["X25519"],
|
"kexes": ["X25519"],
|
||||||
"cert": ["prime256v1"],
|
"cert": ["prime256v1"],
|
||||||
},
|
},
|
||||||
# # Compare signatures among implementations and TLS versions
|
## Compare signatures among implementations and TLS versions
|
||||||
"impl-cert-ver": {
|
"impl-cert-ver": {
|
||||||
"impls": IMPLS,
|
"impls": IMPLS,
|
||||||
"records": RECORDS,
|
"records": RECORDS,
|
||||||
"ciphers": [
|
"ciphers": [
|
||||||
"AES_128_GCM_SHA256",
|
"AES_128_GCM_SHA256",
|
||||||
"ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
#"ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
],
|
],
|
||||||
"kexes": ["X25519"],
|
"kexes": ["X25519"],
|
||||||
"cert": [
|
"cert": [
|
||||||
"prime256v1",
|
"prime256v1",
|
||||||
#"secp384r1",
|
#"secp384r1",
|
||||||
"rsa2048",
|
"rsa2048",
|
||||||
#"rsa3072", "rsa4096"
|
"rsa3072", "rsa4096"
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
# # Compare key exchange groups among implementations and TLS versions
|
## Compare key exchange groups among implementations and TLS versions
|
||||||
"impl-kex-ver": {
|
"impl-kex-ver": {
|
||||||
"impls": IMPLS,
|
"impls": IMPLS,
|
||||||
"records": RECORDS,
|
"records": RECORDS,
|
||||||
"ciphers": [
|
"ciphers": [
|
||||||
"AES_128_GCM_SHA256",
|
"AES_128_GCM_SHA256",
|
||||||
"ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
#"ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
],
|
],
|
||||||
"kexes": ["X25519", "SECP256R1", "SECP384R1"],
|
"kexes": ["X25519", "SECP256R1", "SECP384R1"],
|
||||||
"cert": ["prime256v1"],
|
"cert": ["prime256v1"],
|
||||||
|
|
@ -122,8 +124,9 @@ EXPERIMENTS = {
|
||||||
# "records": RECORDS,
|
# "records": RECORDS,
|
||||||
# "ciphers": [
|
# "ciphers": [
|
||||||
# "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
# "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
# "ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
# ],
|
# ],
|
||||||
# "kexes": ["SECP384R1"],
|
# "kexes": ["X25519"],
|
||||||
# "cert": ["prime256v1"],
|
# "cert": ["prime256v1"],
|
||||||
#},
|
#},
|
||||||
}
|
}
|
||||||
|
|
@ -286,24 +289,28 @@ SETUPS = {
|
||||||
"netreplay_tls_mode": "none",
|
"netreplay_tls_mode": "none",
|
||||||
"p2_port": 80,
|
"p2_port": 80,
|
||||||
"listen_port": 80,
|
"listen_port": 80,
|
||||||
|
"tls_invariant": True,
|
||||||
},
|
},
|
||||||
"client": {
|
"client": {
|
||||||
"rpxy_config": "tls",
|
"rpxy_config": "tls",
|
||||||
"netreplay_tls_mode": "server",
|
"netreplay_tls_mode": "server",
|
||||||
"p2_port": 80,
|
"p2_port": 80,
|
||||||
"listen_port": 443,
|
"listen_port": 443,
|
||||||
|
"tls_invariant": False,
|
||||||
},
|
},
|
||||||
"server": {
|
"server": {
|
||||||
"rpxy_config": "plain",
|
"rpxy_config": "plain",
|
||||||
"netreplay_tls_mode": "client",
|
"netreplay_tls_mode": "client",
|
||||||
"p2_port": 443,
|
"p2_port": 443,
|
||||||
"listen_port": 80,
|
"listen_port": 80,
|
||||||
|
"tls_invariant": False,
|
||||||
},
|
},
|
||||||
#"both": {
|
#"both": {
|
||||||
# "rpxy_config": "tls",
|
# "rpxy_config": "tls",
|
||||||
# "netreplay_tls_mode": "both",
|
# "netreplay_tls_mode": "both",
|
||||||
# "p2_port": 443,
|
# "p2_port": 443,
|
||||||
# "listen_port": 443,
|
# "listen_port": 443,
|
||||||
|
# "tls_invariant": False,
|
||||||
#},
|
#},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -357,22 +364,15 @@ def choose_impl(expdir, p, impl):
|
||||||
expdir += "/"
|
expdir += "/"
|
||||||
os.symlink(os.getcwd()+"/rpxy_rustls_"+impl, expdir+str(p)+"_rpxy", False)
|
os.symlink(os.getcwd()+"/rpxy_rustls_"+impl, expdir+str(p)+"_rpxy", False)
|
||||||
|
|
||||||
def run_rpxy(expdir, repodir, config_name, impl, ciphers=None, kexes=None):
|
def run_netreplay(expdir, repodir, record, p2_addr, p2_port, listen_port, tls_mode, only_record=None, ciphers=None, kexes=None):
|
||||||
if expdir[-1] != "/":
|
if expdir[-1] != "/":
|
||||||
expdir += "/"
|
expdir += "/"
|
||||||
repodir = repodir.removesuffix("/")
|
repodir = repodir.removesuffix("/")
|
||||||
env = {"RUST_LOG": "debug"}
|
env = {"RUST_LOG": "debug"}
|
||||||
if ciphers:
|
if ciphers:
|
||||||
env["CIPHERS"] = ",".join(ciphers)
|
env["CIPHERS"] = ciphers
|
||||||
if kexes:
|
if kexes:
|
||||||
env["KEXES"] = ",".join(KEXES)
|
env["KEXES"] = kexes
|
||||||
return subprocess.Popen([repodir+"/rpxy_rustls_"+impl, "--config", expdir+"configs/"+config_name+".toml"], env=env)
|
|
||||||
|
|
||||||
def run_netreplay(expdir, repodir, record, p2_addr, p2_port, listen_port, tls_mode, only_record=None):
|
|
||||||
if expdir[-1] != "/":
|
|
||||||
expdir += "/"
|
|
||||||
repodir = repodir.removesuffix("/")
|
|
||||||
env = {"RUST_LOG": "debug"}
|
|
||||||
cmd = [repodir+"/netreplay", repodir+"/records/"+record["filename"], "play", p2_addr, str(p2_port), str(listen_port), expdir+"current_certs", tls_mode, "-r", str(record["repeat"])]
|
cmd = [repodir+"/netreplay", repodir+"/records/"+record["filename"], "play", p2_addr, str(p2_port), str(listen_port), expdir+"current_certs", tls_mode, "-r", str(record["repeat"])]
|
||||||
if only_record != None:
|
if only_record != None:
|
||||||
cmd += ["--record", only_record]
|
cmd += ["--record", only_record]
|
||||||
|
|
@ -401,7 +401,7 @@ def get_net_stat(ssh):
|
||||||
bytes_out = int(items[8])
|
bytes_out = int(items[8])
|
||||||
return (bytes_in, bytes_out)
|
return (bytes_in, bytes_out)
|
||||||
|
|
||||||
def run_exp(ssh, expdir, p2_path, exps, only_record=None):
|
def run_exp(ssh, expdir, p2_path, exps, only_record=None, idle=False):
|
||||||
wattmeter = None
|
wattmeter = None
|
||||||
if WATTMETER:
|
if WATTMETER:
|
||||||
errmsg = YRefParam()
|
errmsg = YRefParam()
|
||||||
|
|
@ -420,13 +420,58 @@ def run_exp(ssh, expdir, p2_path, exps, only_record=None):
|
||||||
ssh.run(f"killall rpxy_rustls_{impl}")
|
ssh.run(f"killall rpxy_rustls_{impl}")
|
||||||
except invoke.exceptions.UnexpectedExit as e:
|
except invoke.exceptions.UnexpectedExit as e:
|
||||||
pass
|
pass
|
||||||
rpxy_cpu = get_cpu_stat(ssh)
|
logfile_name = "log-"+str(int(time.time()))
|
||||||
logfile_name = expdir+"/log-"+str(int(time.time()))
|
logfile_path = expdir+"/"+logfile_name
|
||||||
logfile = open(logfile_name, "w")
|
logfile = open(logfile_path, "w")
|
||||||
logfile.write("exp impl alg kex cipher setup record time cpu bytes_in bytes_out Wh\n")
|
logfile.write("exp impl alg kex cipher setup record time cpu bytes_in bytes_out Wh\n")
|
||||||
logfile.close()
|
logfile.close()
|
||||||
|
|
||||||
|
if idle:
|
||||||
|
print("Measuring idle...")
|
||||||
|
rpxy_cpu = get_cpu_stat(ssh)
|
||||||
|
p2_bytes_in, p2_bytes_out = get_net_stat(ssh)
|
||||||
|
energy = 0
|
||||||
|
if WATTMETER:
|
||||||
|
energy = wattmeter.get_meter()
|
||||||
|
start = time.time()
|
||||||
|
|
||||||
|
time.sleep(600)
|
||||||
|
|
||||||
|
end = time.time()
|
||||||
|
new_energy = 0
|
||||||
|
if WATTMETER:
|
||||||
|
new_energy = wattmeter.get_meter()
|
||||||
|
new_p2_bytes_in, new_p2_bytes_out = get_net_stat(ssh)
|
||||||
|
new_rpxy_cpu = get_cpu_stat(ssh)
|
||||||
|
rpxy_cpu_diff = new_rpxy_cpu - rpxy_cpu
|
||||||
|
p2_bytes_in_diff = new_p2_bytes_in - p2_bytes_in
|
||||||
|
p2_bytes_out_diff = new_p2_bytes_out - p2_bytes_out
|
||||||
|
energy_diff = new_energy - energy
|
||||||
|
time_diff = end - start
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
with open(logfile_path, "a") as logfile:
|
||||||
|
logfile.write(f"idle - - - - - - {time_diff} {rpxy_cpu_diff} {p2_bytes_in_diff} {p2_bytes_out_diff} {energy_diff}\n")
|
||||||
|
logfile.close()
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print("Can't open log file:", e)
|
||||||
|
time.sleep(1)
|
||||||
|
else:
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
with open(logfile_path, "a") as logfile:
|
||||||
|
logfile.write(IDLE+"\n")
|
||||||
|
logfile.close()
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print("Can't open log file:", e)
|
||||||
|
time.sleep(1)
|
||||||
|
sh(f"cp {logfile_path} {LOG_BACKUP_DIR}/{logfile_name}")
|
||||||
|
|
||||||
for expname in exps:
|
for expname in exps:
|
||||||
exp = exps[expname]
|
exp = exps[expname]
|
||||||
|
first_set = True
|
||||||
for impl in exp["impls"]:
|
for impl in exp["impls"]:
|
||||||
for alg in exp["cert"]:
|
for alg in exp["cert"]:
|
||||||
for kex in exp["kexes"]:
|
for kex in exp["kexes"]:
|
||||||
|
|
@ -434,6 +479,8 @@ def run_exp(ssh, expdir, p2_path, exps, only_record=None):
|
||||||
choose_cert_alg(expdir, alg)
|
choose_cert_alg(expdir, alg)
|
||||||
ssh.run(f"python {p2_path}/exp.py cert {alg}")
|
ssh.run(f"python {p2_path}/exp.py cert {alg}")
|
||||||
for setup in SETUPS:
|
for setup in SETUPS:
|
||||||
|
if SETUPS[setup]["tls_invariant"] and not first_set:
|
||||||
|
continue
|
||||||
setupdir = expdir+"setups/"+setup
|
setupdir = expdir+"setups/"+setup
|
||||||
for record in exp["records"]:
|
for record in exp["records"]:
|
||||||
print(f"EXPERIMENT {expname}: {impl} {alg} {kex} {cipher} {setup}")
|
print(f"EXPERIMENT {expname}: {impl} {alg} {kex} {cipher} {setup}")
|
||||||
|
|
@ -443,13 +490,14 @@ def run_exp(ssh, expdir, p2_path, exps, only_record=None):
|
||||||
runbg(ssh, f"{p2_path}/rpxy_rustls_{impl} --config {expdir}/configs/{p2_rpxy_config}.toml --log-dir /dev/shm", vars)
|
runbg(ssh, f"{p2_path}/rpxy_rustls_{impl} --config {expdir}/configs/{p2_rpxy_config}.toml --log-dir /dev/shm", vars)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
|
rpxy_cpu = get_cpu_stat(ssh)
|
||||||
p2_bytes_in, p2_bytes_out = get_net_stat(ssh)
|
p2_bytes_in, p2_bytes_out = get_net_stat(ssh)
|
||||||
energy = 0
|
energy = 0
|
||||||
if WATTMETER:
|
if WATTMETER:
|
||||||
energy = wattmeter.get_meter()
|
energy = wattmeter.get_meter()
|
||||||
|
|
||||||
start = time.time()
|
start = time.time()
|
||||||
netreplay = run_netreplay(expdir, REPODIR, record, P2_ADDR, SETUPS[setup]["p2_port"], SETUPS[setup]["listen_port"], SETUPS[setup]["netreplay_tls_mode"], only_record=only_record)
|
netreplay = run_netreplay(expdir, REPODIR, record, P2_ADDR, SETUPS[setup]["p2_port"], SETUPS[setup]["listen_port"], SETUPS[setup]["netreplay_tls_mode"], only_record=only_record, ciphers=cipher, kexes=kex)
|
||||||
|
|
||||||
# TODO detect when netreplay has finished
|
# TODO detect when netreplay has finished
|
||||||
try:
|
try:
|
||||||
|
|
@ -468,6 +516,10 @@ def run_exp(ssh, expdir, p2_path, exps, only_record=None):
|
||||||
|
|
||||||
#time.sleep(30)
|
#time.sleep(30)
|
||||||
#sh("killall netreplay")
|
#sh("killall netreplay")
|
||||||
|
try:
|
||||||
|
ssh.run(f"rm /dev/shm/access.log /dev/shm/rpxy.log")
|
||||||
|
except invoke.exceptions.UnexpectedExit as e:
|
||||||
|
pass
|
||||||
try:
|
try:
|
||||||
ssh.run(f"killall rpxy_rustls_{impl}")
|
ssh.run(f"killall rpxy_rustls_{impl}")
|
||||||
except invoke.exceptions.UnexpectedExit as e:
|
except invoke.exceptions.UnexpectedExit as e:
|
||||||
|
|
@ -488,17 +540,18 @@ def run_exp(ssh, expdir, p2_path, exps, only_record=None):
|
||||||
p2_bytes_in_diff = new_p2_bytes_in - p2_bytes_in
|
p2_bytes_in_diff = new_p2_bytes_in - p2_bytes_in
|
||||||
p2_bytes_out_diff = new_p2_bytes_out - p2_bytes_out
|
p2_bytes_out_diff = new_p2_bytes_out - p2_bytes_out
|
||||||
energy_diff = new_energy - energy
|
energy_diff = new_energy - energy
|
||||||
rpxy_cpu = new_rpxy_cpu
|
|
||||||
time_diff = end - start
|
time_diff = end - start
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
with open(logfile_name, "a") as logfile:
|
with open(logfile_path, "a") as logfile:
|
||||||
logfile.write(f"{expname} {impl} {alg} {kex} {cipher} {setup} {record_filename} {time_diff} {rpxy_cpu_diff} {p2_bytes_in_diff} {p2_bytes_out_diff} {energy_diff}\n")
|
logfile.write(f"{expname} {impl} {alg} {kex} {cipher} {setup} {record_filename} {time_diff} {rpxy_cpu_diff} {p2_bytes_in_diff} {p2_bytes_out_diff} {energy_diff}\n")
|
||||||
logfile.close()
|
logfile.close()
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Can't open log file:", e)
|
print("Can't open log file:", e)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
sh(f"cp {logfile_path} {LOG_BACKUP_DIR}/{logfile_name}")
|
||||||
|
first_set = False
|
||||||
if WATTMETER:
|
if WATTMETER:
|
||||||
YAPI.FreeAPI()
|
YAPI.FreeAPI()
|
||||||
|
|
||||||
|
|
@ -564,6 +617,7 @@ Run options:
|
||||||
--passphrase Prompt SSH key decryption passphrase (when using pubkey login)
|
--passphrase Prompt SSH key decryption passphrase (when using pubkey login)
|
||||||
--count Do not run experiments but display number of experiments
|
--count Do not run experiments but display number of experiments
|
||||||
--record <id> Only play this record
|
--record <id> Only play this record
|
||||||
|
--idle Also measure when idle
|
||||||
""".format(
|
""".format(
|
||||||
sig_algs=" ".join(CERT_SIGN_ALGS),
|
sig_algs=" ".join(CERT_SIGN_ALGS),
|
||||||
impls=" ".join(IMPLS),
|
impls=" ".join(IMPLS),
|
||||||
|
|
@ -607,7 +661,7 @@ Run options:
|
||||||
from yoctopuce.yocto_power import *
|
from yoctopuce.yocto_power import *
|
||||||
|
|
||||||
ssh = connect_ssh()
|
ssh = connect_ssh()
|
||||||
run_exp(ssh, EXPDIR, P2_REPODIR, EXPERIMENTS, only_record=getargv("--record", None))
|
run_exp(ssh, EXPDIR, P2_REPODIR, EXPERIMENTS, only_record=getargv("--record", None), idle="--idle" in sys.argv)
|
||||||
elif opt == "script":
|
elif opt == "script":
|
||||||
print(SCRIPT_FIREFOX_HOSTS)
|
print(SCRIPT_FIREFOX_HOSTS)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
148
plots.py
Normal file
148
plots.py
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
import os, sys
|
||||||
|
|
||||||
|
# Nice labels for algorithms of all kinds
|
||||||
|
ALG_LABEL = {
|
||||||
|
"AES_128_GCM_SHA256": "AES128",
|
||||||
|
"AES_256_GCM_SHA384": "AES256",
|
||||||
|
"CHACHA20_POLY1305_SHA256": "CHACHA20",
|
||||||
|
"ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256": "AES128",
|
||||||
|
"ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,ECDHE_RSA_WITH_AES_256_GCM_SHA384": "AES256",
|
||||||
|
"ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": "CHACHA20",
|
||||||
|
"prime256v1": "prime256v1",
|
||||||
|
"rsa2048": "rsa2048",
|
||||||
|
"rsa3072": "rsa3072",
|
||||||
|
"rsa4096": "rsa4096",
|
||||||
|
"X25519": "X25519",
|
||||||
|
"SECP256R1": "SECP256R1",
|
||||||
|
"SECP384R1": "SECP384R1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Nice labels for TLS versions using ciphers
|
||||||
|
VER_LABEL = {
|
||||||
|
"AES_128_GCM_SHA256": "1.3",
|
||||||
|
"AES_256_GCM_SHA384": "1.3",
|
||||||
|
"CHACHA20_POLY1305_SHA256": "1.3",
|
||||||
|
"ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,ECDHE_RSA_WITH_AES_128_GCM_SHA256": "1.2",
|
||||||
|
"ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,ECDHE_RSA_WITH_AES_256_GCM_SHA384": "1.2",
|
||||||
|
"ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256": "1.2"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Titles for measured quantities
|
||||||
|
OBJ_TITLE = {
|
||||||
|
"cpu": "CPU time",
|
||||||
|
"energy": "energy consumption"
|
||||||
|
}
|
||||||
|
# Logfile column names
|
||||||
|
COL = {
|
||||||
|
"cpu": "cpu",
|
||||||
|
"energy": "Wh",
|
||||||
|
"cipher": "cipher",
|
||||||
|
"cert": "alg",
|
||||||
|
"kex": "kex"
|
||||||
|
}
|
||||||
|
# Physical units by object
|
||||||
|
UNIT = {
|
||||||
|
"cpu": "s",
|
||||||
|
"energy": "W"
|
||||||
|
}
|
||||||
|
# Titles for criteria
|
||||||
|
CRITERION_TITLE = {
|
||||||
|
"cipher": "cipher",
|
||||||
|
"cert": "signature algorithm",
|
||||||
|
"kex": "key exchange"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Where gnuplot files, data files and images are output
|
||||||
|
PLOTS_DIR = "/dev/shm/plots"
|
||||||
|
|
||||||
|
def gnuplot_histogram(**kwargs):
|
||||||
|
cluster = ""
|
||||||
|
for i in range(kwargs["nb_impls"]-1):
|
||||||
|
cluster += """, "" using {}:xticlabels(1) title col""".format(i+4)
|
||||||
|
f = open("{plots_dir}/{object}_by_{criterion}_{side}.gnuplot".format(plots_dir=PLOTS_DIR, **kwargs), "w")
|
||||||
|
f.write("""\
|
||||||
|
set terminal pngcairo enhanced font "CMU Sans Serif,11" fontscale 1.0 size 800, 600
|
||||||
|
set output "{plots_dir}/{object}_by_{criterion}_{side}.png"
|
||||||
|
set boxwidth 0.9 absolute
|
||||||
|
set style fill solid 1.0 border lt -1
|
||||||
|
set style histogram clustered gap 1 title textcolor lt -1
|
||||||
|
set style data histograms
|
||||||
|
set title font "CMU Sans Serif,12" "{object_title} by {criterion_title} ({side} side) ({unit})"
|
||||||
|
set xtics border in scale 0,0 nomirror rotate by -45 autojustify
|
||||||
|
set key fixed right top vertical Right noreverse noenhanced autotitle nobox
|
||||||
|
set colorbox vertical origin screen 0.9, 0.2 size screen 0.05, 0.6 front noinvert bdefault
|
||||||
|
set xrange [ * : * ] noreverse writeback
|
||||||
|
plot \
|
||||||
|
newhistogram "", "{plots_dir}/{object}_by_{criterion}_{side}.dat" using 2:xticlabels(1) notitle col, \
|
||||||
|
newhistogram "", "{plots_dir}/{object}_by_{criterion}_{side}.dat" using 3:xticlabels(1) title col{cluster}
|
||||||
|
""".format(plots_dir=PLOTS_DIR, cluster=cluster, **kwargs))
|
||||||
|
f.close()
|
||||||
|
os.system("gnuplot {plots_dir}/{object}_by_{criterion}_{side}.gnuplot".format(plots_dir=PLOTS_DIR, **kwargs))
|
||||||
|
|
||||||
|
def make_plot(records, exp, criterion, side, obj):
|
||||||
|
f = open(f"/dev/shm/plots/{obj}_by_{criterion}_{side}.dat", "w")
|
||||||
|
ciphers = {}
|
||||||
|
impls = []
|
||||||
|
plain_line = None
|
||||||
|
idle_val = None
|
||||||
|
|
||||||
|
for record in records:
|
||||||
|
if record["exp"] == "idle":
|
||||||
|
idle_val = float(record[COL[obj]]) / float(record["time"])
|
||||||
|
if record["exp"] != exp:
|
||||||
|
continue
|
||||||
|
if record["setup"] == "none":
|
||||||
|
plain_line = "plain {}".format(float(record[COL[obj]]) - idle_val * float(record["time"]))
|
||||||
|
|
||||||
|
if plain_line == None:
|
||||||
|
return
|
||||||
|
|
||||||
|
for record in records:
|
||||||
|
if record["exp"] != exp:
|
||||||
|
continue
|
||||||
|
elif record["setup"] == side:
|
||||||
|
if record[COL[criterion]] not in ciphers:
|
||||||
|
ciphers[record[COL[criterion]]] = {}
|
||||||
|
ciphers[record[COL[criterion]]][record["impl"]] = float(record[COL[obj]]) - idle_val * float(record["time"])
|
||||||
|
if record["impl"] not in impls:
|
||||||
|
impls.append(record["impl"])
|
||||||
|
impls.sort()
|
||||||
|
f.write("{} none {}\n".format(criterion, " ".join(impls)))
|
||||||
|
f.write(plain_line+" -"*len(impls)+"\n")
|
||||||
|
for cipher in ciphers:
|
||||||
|
f.write("{}({}) - {}\n".format(
|
||||||
|
ALG_LABEL[cipher],
|
||||||
|
VER_LABEL[record["cipher"]],
|
||||||
|
" ".join([
|
||||||
|
str(ciphers[cipher][impl])
|
||||||
|
for impl in impls
|
||||||
|
]),
|
||||||
|
))
|
||||||
|
f.close()
|
||||||
|
gnuplot_histogram(object=obj, criterion=criterion, side=side, object_title=OBJ_TITLE[obj], criterion_title=CRITERION_TITLE[criterion], unit=UNIT[obj], nb_impls=len(impls))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
logfile_name = sys.argv[1]
|
||||||
|
logfile = open(logfile_name, "r")
|
||||||
|
lines = logfile.readlines()
|
||||||
|
logfile.close()
|
||||||
|
|
||||||
|
colnames = lines[0].removesuffix("\n").split(" ")
|
||||||
|
|
||||||
|
records = []
|
||||||
|
for line in lines[1:]:
|
||||||
|
cols = line.removesuffix("\n").split(" ")
|
||||||
|
record = {}
|
||||||
|
for col in range(len(cols)):
|
||||||
|
record[colnames[col]] = cols[col]
|
||||||
|
records.append(record)
|
||||||
|
|
||||||
|
os.makedirs("/dev/shm/plots", exist_ok=True)
|
||||||
|
|
||||||
|
for side in ["client", "server"]:
|
||||||
|
make_plot(records, "impl-cipher-ver", "cipher", side, "cpu")
|
||||||
|
make_plot(records, "impl-cipher-ver", "cipher", side, "energy")
|
||||||
|
make_plot(records, "impl-cert-ver", "cert", side, "cpu")
|
||||||
|
make_plot(records, "impl-cert-ver", "cert", side, "energy")
|
||||||
|
make_plot(records, "impl-kex-ver", "kex", side, "cpu")
|
||||||
|
make_plot(records, "impl-kex-ver", "kex", side, "energy")
|
||||||
BIN
records/wikipedia
Normal file
BIN
records/wikipedia
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue