This commit is contained in:
Markus Ottela 2016-10-21 05:14:37 +03:00
parent 3a83d717bd
commit a8c4eae95f
12 changed files with 20370 additions and 13626 deletions

1003
LICENSE.md

File diff suppressed because it is too large Load Diff

2461
NH.py

File diff suppressed because it is too large Load Diff

6963
Rx.py

File diff suppressed because it is too large Load Diff

7968
Tx.py

File diff suppressed because it is too large Load Diff

186
dd.py
View File

@ -1,27 +1,28 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# TFC-NaCl 0.16.05 || dd.py
# TFC 0.16.10 || dd.py
"""
GPL License
Copyright (C) 2013-2016 Markus Ottela
This software is part of the TFC application, which is free software: You can
redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This file is part of TFC.
TFC is free software: you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
TFC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. For
a copy of the GNU General Public License, see <http://www.gnu.org/licenses/>.
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TFC. If not, see <http://www.gnu.org/licenses/>.
"""
import multiprocessing.connection
import multiprocessing
import os
import shlex
import subprocess
import sys
import time
@ -31,6 +32,8 @@ import time
###############################################################################
def lr_upper():
"""Print high signal frame (left to right)."""
print("""
Data flow
@ -42,6 +45,8 @@ GND━━━┿━┥ ├──Rx ├──GND
def lr_lower():
"""Print low signal frame (left to right)."""
print("""
Data flow
@ -53,6 +58,8 @@ GND━━━┿━┥ ├──Rx ├──GND
def lr_idle():
"""Print no signal frame (left to right)."""
print("""
Data flow
@ -64,6 +71,8 @@ GND━━━┿━┥ ├──Rx ├──GND
def rl_upper():
"""Print high signal frame (right to left)."""
print("""
Data flow
@ -75,6 +84,8 @@ GND──┤ Rx──┤ ┝━┿━━━GND
def rl_lower():
"""Print low signal frame (right to left)."""
print("""
Data flow
@ -86,6 +97,8 @@ GND──┤ Rx──┤ ┝━┿━━━GND
def rl_idle():
"""Print no signal frame (right to left)."""
print("""
Data flow
@ -101,6 +114,8 @@ GND──┤ Rx──┤ ┝━┿━━━GND
###############################################################################
def lr():
"""Draw animation (left to right)."""
for _ in range(10):
os.system("clear")
lr_lower()
@ -112,6 +127,8 @@ def lr():
def rl():
"""Draw animation (right to left)."""
for _ in range(10):
os.system("clear")
rl_lower()
@ -127,6 +144,7 @@ def rl():
###############################################################################
def tx_process():
"""Process that reads from sending computer."""
if tx_nh_lr or nh_rx_rl:
lr_idle()
@ -153,100 +171,106 @@ def tx_process():
def rx_process():
"""Process that sends to receiving computer."""
def ipc_to_queue(conn):
"""
Load packet from IPC.
:param conn: Listener object
:return: [no return value]
"""
while True:
time.sleep(0.001)
pkg = str(conn.recv())
pkg = conn.recv()
io_queue.put(pkg)
try:
l = multiprocessing.connection.Listener(('', input_socket))
l = multiprocessing.connection.Listener(("localhost", input_socket))
while True:
ipc_to_queue(l.accept())
except EOFError:
exit_queue.put("exit")
tx_nh_lr = False
nh_rx_lr = False
tx_nh_rl = False
nh_rx_rl = False
if __name__ == "__main__":
input_socket = 0
output_socket = 0
tx_nh_lr = False
nh_rx_lr = False
tx_nh_rl = False
nh_rx_rl = False
# Resize terminal
id_cmd = "xdotool getactivewindow"
resize_cmd = "xdotool windowsize --usehints {id} 25 12"
proc = subprocess.Popen(shlex.split(id_cmd), stdout=subprocess.PIPE)
windowid, err = proc.communicate()
proc = subprocess.Popen(shlex.split(resize_cmd.format(id=windowid)))
proc.communicate()
input_socket = 0
output_socket = 0
try:
# Simulates data diode between Tx.py on left, NH.py on right.
if str(sys.argv[1]) == "txnhlr":
tx_nh_lr = True
input_socket = 5000
output_socket = 5001
# Resize terminal
# sys.stdout.write("\x1b[8;{rows};{cols}t".format(rows=25, cols=12))
# Simulates data diode between Tx.py on right, NH.py on left.
elif str(sys.argv[1]) == "txnhrl":
tx_nh_rl = True
input_socket = 5000
output_socket = 5001
try:
# Simulates data diode between Tx.py on left, NH.py on right.
if str(sys.argv[1]) == "txnhlr":
tx_nh_lr = True
input_socket = 5000
output_socket = 5001
# Simulates data diode between Rx.py on left, NH.py on right.
elif str(sys.argv[1]) == "nhrxlr":
nh_rx_lr = True
input_socket = 5002
output_socket = 5003
# Simulates data diode between Tx.py on right, NH.py on left.
elif str(sys.argv[1]) == "txnhrl":
tx_nh_rl = True
input_socket = 5000
output_socket = 5001
# Simulates data diode between Rx.py on right, NH.py on left.
elif str(sys.argv[1]) == "nhrxrl":
nh_rx_rl = True
input_socket = 5002
output_socket = 5003
# Simulates data diode between Rx.py on left, NH.py on right.
elif str(sys.argv[1]) == "nhrxlr":
nh_rx_lr = True
input_socket = 5002
output_socket = 5003
else:
# Simulates data diode between Rx.py on right, NH.py on left.
elif str(sys.argv[1]) == "nhrxrl":
nh_rx_rl = True
input_socket = 5002
output_socket = 5003
else:
os.system("clear")
print("\nUsage: python dd.py {txnh{lr,rl}, nhrx{lr,rl}\n")
exit()
except IndexError:
os.system("clear")
print("\nUsage: python dd.py {txnh{lr,rl}, nhrx{lr,rl}\n")
print("\nUsage: python dd.py {txnh{lr,rl}, nhrx{lr,rl}}\n")
exit()
except IndexError:
os.system("clear")
print("\nUsage: python dd.py {txnh{lr,rl}, nhrx{lr,rl}}\n")
exit()
try:
print("Waiting for socket")
ipx_send = multiprocessing.connection.Client(("localhost",
output_socket))
print("Connection established.")
time.sleep(0.3)
os.system("clear")
except KeyboardInterrupt:
exit()
try:
print("Waiting for socket")
ipx_send = multiprocessing.connection.Client(("localhost", output_socket))
print("Connection established.")
time.sleep(0.3)
os.system("clear")
except KeyboardInterrupt:
exit()
exit_queue = multiprocessing.Queue()
io_queue = multiprocessing.Queue()
exit_queue = multiprocessing.Queue()
io_queue = multiprocessing.Queue()
txp = multiprocessing.Process(target=tx_process)
rxp = multiprocessing.Process(target=rx_process)
txp = multiprocessing.Process(target=tx_process)
rxp = multiprocessing.Process(target=rx_process)
txp.start()
rxp.start()
txp.start()
rxp.start()
try:
while True:
if not exit_queue.empty():
command = exit_queue.get()
if command == "exit":
txp.terminate()
rxp.terminate()
exit()
time.sleep(0.01)
try:
while True:
if not exit_queue.empty():
command = exit_queue.get()
if command == "exit":
txp.terminate()
rxp.terminate()
exit()
time.sleep(0.01)
except KeyboardInterrupt:
txp.terminate()
rxp.terminate()
exit()
except KeyboardInterrupt:
txp.terminate()
rxp.terminate()
exit()

View File

@ -1,108 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# TFC-NaCl 0.16.05 || hwrng-nacl.py
"""
GPL License
This software is part of the TFC application, which is free software: You can
redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
TFC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. For
a copy of the GNU General Public License, see <http://www.gnu.org/licenses/>.
"""
import binascii
import time
try:
import RPi.GPIO as GPIO
except ImportError:
GPIO = None
pass
###############################################################################
# CONFIGURATION #
###############################################################################
sample_delay = 0.1 # Delay in seconds between samples
gpio_port = 4 # RPi's GPIO pin (Broadcom layout) to collect entropy from.
###############################################################################
# MAIN #
###############################################################################
def main():
"""
Load 32 bytes of entropy from HWRNG.
:return: None
"""
def digits_to_bytes(di):
"""
Convert string of binary digits to byte string.
:param di: Digit string.
:return: Byte string.
"""
return ''.join(chr(int(di[i:i + 8], 2)) for i in xrange(0, len(di), 8))
try:
w0 = 0
w1 = 0
while True:
if w1 > 1500 and w0 > 1500:
break
if GPIO.input(gpio_port) == 1:
w1 += 1
else:
w0 += 1
time.sleep(0.001)
# Perform Von Neumann whitening during sampling
vn_digits = ''
while True:
if len(vn_digits) >= 256:
break
first_bit = GPIO.input(gpio_port)
time.sleep(sample_delay)
second_bit = GPIO.input(gpio_port)
time.sleep(sample_delay)
if first_bit == second_bit:
continue
else:
vn_digits += str(first_bit)
entropy = digits_to_bytes(vn_digits)
if len(entropy) != 32:
print("ERROR")
except KeyboardInterrupt:
GPIO.cleanup()
raise
GPIO.cleanup()
print(binascii.hexlify(entropy))
if __name__ == "__main__":
GPIO.setmode(GPIO.BCM)
GPIO.setup(gpio_port, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
main()

167
readme.md
View File

@ -1,109 +1,134 @@
<img align="right" src="https://cs.helsinki.fi/u/oottela/tfclogo.png" style="position: relative; top: 0; left: 0;">
###Tinfoil Chat NaCl
###Tinfoil Chat
Tinfoil Chat (TFC) is a high assurance encrypted messaging system that
operates on top of existing IM clients. The
[free and open source software](https://en.wikipedia.org/wiki/Free_and_open-source_software)
is used together with free hardware to protect users from
[passive eavesdropping](https://en.wikipedia.org/wiki/Upstream_collection),
[active MITM attacks](https://en.wikipedia.org/wiki/Man-in-the-middle_attack)
and [remote CNE](https://www.youtube.com/watch?v=3euYBPlX9LM) practised by
organized crime and nation state attackers.
TFC-NaCl is a high assurance encrypted messaging system that operates on top of
existing IM clients. The free and open source software is used in conjunction
with free hardware to protect users from passive eavesdropping, active MITM
attacks and remote CNE practised by organized crime and state-level adversaries.
[XSalsa20](https://cr.yp.to/snuffle/salsafamily-20071225.pdf) encryption
and [Poly1305-AES](https://cr.yp.to/mac/poly1305-20050329.pdf) MACs provide
[end-to-end encrypted](https://en.wikipedia.org/wiki/End-to-end_encryption)
communication with [deniable authentication](https://en.wikipedia.org/wiki/Deniable_encryption#Deniable_authentication): Symmetric keys are either
pre-shared, or exchanged using [Curve25519 ECDHE](https://cr.yp.to/ecdh/curve25519-20060209.pdf), the public
keys of which are verified via off-band channel.
TFC-NaCl uses XSalsa-20-Poly1305 AEAD that provides forward secrecy and
deniability. Symmetric keys are either pre-shared, or agreed using Curve25519
ECDHE key exchange.
Key generation relies on Kernel CSPRNG, but also supports mixing of
external entropy from [open circuit design HWRNG](http://holdenc.altervista.org/avalanche/),
that is sampled by a [RPi](https://www.raspberrypi.org/) through it's
GPIO interface either natively, or remotely (SSH over direct ethernet
cable). TFC provides per-message forward secrecy with PBKDF2-HMAC-SHA256
[hash ratchet](https://en.wikipedia.org/wiki/Double_Ratchet_Algorithm).
Key generation utilizes Kernel CSPRNG, but additionally, further entropy can be
loaded from open circuit design HWRNG, that is sampled by a [RPi](https://www.raspberrypi.org/)
through it's GPIO pins either natively, or via SSH. Forward secrecy is obtained
with hash ratchet based on PBKDF2-HMAC-SHA256, where the 256-bit key is changed
after every message.
The software is used in hardware configuration that provides strong
endpoint security: Encryption and decryption are separated on two
isolated computers. The split [TCB](https://en.wikipedia.org/wiki/Trusted_computing_base)
interacts with a third, networked computer through unidirectional [serial](https://en.wikipedia.org/wiki/RS-232)
interfaces. Direction of data flow is enforced with free hardware design
[data diodes](https://en.wikipedia.org/wiki/Unidirectional_network); Lack
of bidirectional channels to isolated computers prevents insertion of
malware to the encrypting computer and exfiltration of keys and plaintexts
from the decrypting computer -- even with exploits against [zero-day vulnerabilities](https://en.wikipedia.org/wiki/Zero-day_(computing))
in software and operating systems of the TCB halves.
The software is used in configuration that provides strong endpoint security.
It does this by separating encryption and decryption on separate, isolated
computers, that interact with a networked computer through unidirectional
serial interfaces. Direction of data flow is enforced with open circuit design
hardware data diodes; lack of bidirectional channels prevents exfiltration of
keys and plaintexts even with exploits against zero-day vulnerabilities in
software and operating systems of TCBs.
TFC defeats metadata about quantity and schedule of communication with trickle
connection that outputs constant stream of encrypted noise data. Covert file
transfer can take place in background during the trickle connection.
TFC also supports multicasting of messages to enable basic group messaging.
TFC supports multiple IM accounts per user to hide the network structure
of communicating parties, even during end-to-end encrypted group
conversations.
TFC allows a group or two parties to defeat metadata about quantity and
schedule of communication with trickle connection, where messages are
inserted into a constant stream of encrypted noise traffic. Covert file
transfer can take place in background during conversation over the
trickle connection.
###How it works
![](https://cs.helsinki.fi/u/oottela/tfc_graph2.png)
![](https://cs.helsinki.fi/u/oottela/tfcwiki/tfc_overview.png)
TFC uses three computers per endpoint. Alice enters her commands and messages to
program Tx.py running on her Transmitter computer (TxM), a [TCB](https://en.wikipedia.org/wiki/Trusted_computing_base)
separated from network. Tx.py encrypts and signs plaintext data and relays it
to receiver computers (RxM) via networked computer (NH) through RS-232 interface
and a data diode.
TFC uses three computers per endpoint. Alice enters her messages and
commands to program Tx.py running on her transmitter computer (TxM), a
TCB separated from network. Tx.py encrypts and signs plaintext data and
relays the ciphertext from TxM to her networked computer (NH) trough a
serial (RS-232) interface and a hardware data diode.
Depending on packet type, the program NH.py running on Alice's NH forwards
packets from TxM-side serial interface to Pidgin and local RxM (through another
RS-232 interface and data diode). Local RxM authenticates and decrypts received
data before processing it.
Messages and commands received to NH are relayed to IM client (Pidgin or
Finch), and to Alice's receiver computer (RxM) via another serial interface
and data diode. The program Rx.py on Alice's RxM authenticates, decrypts
and processes the received messages and commands.
Pidgin sends the packet either directly or through Tor network to IM server,
that then forwards it directly (or again through Tor) to Bob.
The IM client sends the packet either directly or through Tor network to
IM server, that then forwards it directly (or again through Tor) to Bob.
NH.py on Bob's NH receives Alice's packet from Pidgin, and forwards it through
RS-232 interface and data diode to Bob's RxM, where the ciphertext is
authenticated, decrypted, and processed. When the Bob responds, he will send
the message/file using his TxM and in the end Alice reads the message from her RxM.
IM client on Bob's NH forwards packet to NH.py, that then forwards it to
Bob's RxM (again through data diode enforced serial interface). Bob's
Rx.py on his RxM then authenticates, decrypts, and processes the packet.
When the Bob responds, he will send the message using Tx.py on his
TxM and in the end, Alice reads the message from Rx.py on her RxM.
###Why keys can not be exfiltrated
1. Malware that exploits an unknown vulnerability in RxM can infiltrate to
the system, but is unable to exfiltrate keys or plaintexts, as data diode prevents
all outbound traffic.
1. Malware that exploits an unknown vulnerability in RxM can infiltrate
the system, but is unable to exfiltrate keys or plaintexts, as data
diode prevents all outbound traffic.
2. Malware can not breach TxM as data diode prevents all inbound traffic. The
only data input from RxM to TxM is the 72 char public key, manually typed by
user.
2. Malware can not infiltrate TxM as data diode prevents all inbound
traffic. The only data input to TxM is the public key of contact, which
is manually typed by the user.
3. The NH is assumed to be compromised, but unencrypted data never touches it.
3. The NH is assumed to be compromised: all sensitive data that passes
through NH is always encrypted and signed.
![](https://cs.helsinki.fi/u/oottela/tfc_attacks2.png)
![](https://cs.helsinki.fi/u/oottela/tfcwiki/tfc_attacks.png)
Optical repeater inside the optocoupler of the data diode (below) enforces
direction of data transmission.
Optical repeater inside the [optocoupler](https://en.wikipedia.org/wiki/Opto-isolator)
of the data diode (below) enforces direction of data transmission with
the laws of physics.
<img src="https://cs.helsinki.fi/u/oottela/data_diode.png" align="center" width="74%" height="74%"/>
<img src="https://cs.helsinki.fi/u/oottela/tfcwiki/pbdd.jpg" align="center" width="74%" height="74%"/>
###Supported Operating Systems
####TxM and RxM
- *buntu 16.04
- Linux Mint 17.3 Rosa
- Raspbian Jessie
- Linux Mint 18 Sarah
- Raspbian Jessie (Only use RPi version
[1](https://www.raspberrypi.org/products/model-b-plus/) or
[2](https://www.raspberrypi.org/products/raspberry-pi-2-model-b/))
####NH
- Tails 2.3
- *buntu 16.04,
- Linux Mint 17.3 Rosa
- Tails 2.6
- *buntu 16.04
- Linux Mint 18 Sarah
- Raspbian Jessie
###Installation
[![Installation](http://img.youtube.com/vi/D5pDoJZj2Uw/0.jpg)](http://www.youtube.com/watch?v=D5pDoJZj2Uw)
###How to use
[![Use](http://img.youtube.com/vi/tH8qbl1USoo/0.jpg)](http://www.youtube.com/watch?v=tH8qbl1USoo)
###More information
White paper and manual for previous versions are listed below. Version specific
updates are listed in the updatelog. Updated white paper and documentation are
under work.
[Threat model](https://github.com/maqp/tfc-backup/wiki/Threat-model)<br>
[FAQ](https://github.com/maqp/tfc-backup/wiki/FAQ)<br>
White paper: https://cs.helsinki.fi/u/oottela/tfc.pdf
In depth<br>
&nbsp;&nbsp;&nbsp;&nbsp;[Security design](https://github.com/maqp/tfc-backup/wiki/Security-design)<br>
&nbsp;&nbsp;&nbsp;&nbsp;[Protocol](https://github.com/maqp/tfc-backup/wiki/Protocol)<br>
Manual: https://cs.helsinki.fi/u/oottela/tfc-manual.pdf
Hardware<br>
&nbsp;&nbsp;&nbsp;&nbsp;[Hardware configurations](https://github.com/maqp/tfc-backup/wiki/Hardware-configurations)<br>
&nbsp;&nbsp;&nbsp;&nbsp;[Data diode (perfboard)](https://github.com/maqp/tfc-backup/wiki/Data-Diode-(perfboard))<br>
&nbsp;&nbsp;&nbsp;&nbsp;[Data diode (point to point)](https://github.com/maqp/tfc-backup/wiki/Data-diode-(point-to-point))<br>
&nbsp;&nbsp;&nbsp;&nbsp;[HWRNG (perfboard)](https://github.com/maqp/tfc-backup/wiki/HWRNG-(perfboard))<br>
&nbsp;&nbsp;&nbsp;&nbsp;[HWRNG (breadboard)](https://github.com/maqp/tfc-backup/wiki/HWRNG-(breadboard))<br>
Software<Br>
&nbsp;&nbsp;&nbsp;&nbsp;[Installation](https://github.com/maqp/tfc-backup/wiki/Installation)<br>
&nbsp;&nbsp;&nbsp;&nbsp;[How to use](https://github.com/maqp/tfc-backup/wiki/How-to-use)<br>
[Update Log](https://github.com/maqp/tfc-backup/wiki/Update-Log)<br>

2042
setup.py

File diff suppressed because it is too large Load Diff

View File

@ -1,111 +1,104 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# TFC-CEV 0.16.05 || test_nh.py
# TFC 0.16.10 || test_nh.py
"""
GPL License
Copyright (C) 2013-2016 Markus Ottela
This software is part of the TFC application, which is free software: You can
redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This file is part of TFC.
TFC is free software: you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
TFC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details. For
a copy of the GNU General Public License, see <http://www.gnu.org/licenses/>.
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TFC. If not, see <http://www.gnu.org/licenses/>.
"""
import NH
from NH import *
import binascii
import unittest
# Import crypto libraries
import hashlib
###############################################################################
# UNITTEST HELPERS #
###############################################################################
def ut_sha2_256(message):
h_function = hashlib.sha256()
h_function.update(message)
return binascii.hexlify(h_function.digest())
not_str = [1, 1.0, True]
not_int = ["string", 1.0]
not_tup = [1.0, "string", 1, True]
###############################################################################
# HELPERS #
# MISC #
###############################################################################
NH.unittesting = True
class TestGracefulExit(unittest.TestCase):
class TestGracefulExit(unittest.TestCase):
def test_1_input_parameter(self):
for a in not_str:
with self.assertRaises(SystemExit):
graceful_exit(a)
def test_2_function(self):
with self.assertRaises(SystemExit):
graceful_exit()
class TestPrintBanner(unittest.TestCase):
def test_1_non_rpi(self):
# Setup
NH.rpi_os = False
# Test
self.assertIsNone(print_banner())
def test_2_rpi(self):
# Setup
NH.rpi_os = True
# Test
self.assertIsNone(print_banner())
class TestInputValidation(unittest.TestCase):
def test_1_input_parameter(self):
for a in not_tup:
with self.assertRaises(TypeError):
input_validation(a)
class TestPhase(unittest.TestCase):
def test_1_input_parameters(self):
for a in [1, 1.0, True]:
for b in ["string", 1.0, True]:
for a in not_str:
for b in not_int:
with self.assertRaises(SystemExit):
phase(a, b)
def test_2_output_type(self):
self.assertIsNone(phase("test", 10))
print("Done.")
self.assertIsNone(phase("\ntest", 10))
print("Done.")
self.assertIsNone(phase("\n\n\ntest", 10))
print("Done.")
class TestSHA256(unittest.TestCase):
def test_1_input_parameter(self):
for a in [1, 1.0, True]:
with self.assertRaises(SystemExit):
sha2_256(a)
def test_2_SHA256_vector(self):
"""
Test SHA256 with official test vector:
http://csrc.nist.gov/groups/ST/toolkit/
documents/Examples/SHA_All.pdf // page 14
"""
self.assertEqual(sha2_256("abc"), "ba7816bf8f01cfea414140de5dae2223"
"b00361a396177a9cb410ff61f20015ad")
class TestVerifyChecksum(unittest.TestCase):
def test_1_input_parameter(self):
for a in [1, 1.0, True]:
with self.assertRaises(SystemExit):
verify_checksum(a)
def test_2_function(self):
pt = "test_packet"
tv = ut_sha2_256(pt)
self.assertTrue(verify_checksum("%s|%s" % (pt, tv[:NH.checksum_len])))
class TestGracefulExit(unittest.TestCase):
class TestClearScreen(unittest.TestCase):
def test_1_function(self):
with self.assertRaises(SystemExit):
graceful_exit()
class TestGetTTyWH(unittest.TestCase):
def test_output_types(self):
w, h = get_tty_wh()
self.assertTrue(isinstance(w, int))
self.assertTrue(isinstance(h, int))
class TestPrintBanner(unittest.TestCase):
def test_output_type(self):
self.assertIsNone(print_banner())
self.assertIsNone(clear_screen())
class TestGetSerialInterfaces(unittest.TestCase):
@ -114,95 +107,150 @@ class TestGetSerialInterfaces(unittest.TestCase):
"""
###############################################################################
# RECEIVER #
###############################################################################
class TestDBusReceiver(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestPidginToRxMQueue(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestPidginReceiverProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
###############################################################################
# OTHER #
###############################################################################
class TestHeaderPrinterProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestNHSideCommandProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestQueueToPidginProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class NHToRxMSenderProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
###############################################################################
# PACKETS FROM TxM #
###############################################################################
class TestChooseTxMPacketQueues(unittest.TestCase):
def test_1_input_parameter(self):
for a in [1, 1.0, True]:
with self.assertRaises(SystemExit):
choose_txm_packet_queues(a)
class TestTxMPacketLoadProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestRxMPortListener(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestTxMPortListener(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestProcessArguments(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
###############################################################################
# REED SOLOMON ENCODING #
###############################################################################
class TestRSEncode(unittest.TestCase):
def test_1_correction(self):
string = 10 * "Testmessage"
print("Original: %s" % string)
encoded = rs.encode(string)
print ("After encoding: %s" % encoded)
error = NH.e_correction_ratio
altered = os.urandom(error) + encoded[error:]
print("After errors: %s" % altered)
corrected = rs.decode(altered)
print("Corrected: %s" % corrected)
self.assertEqual(corrected, string)
###############################################################################
# LOCAL DATA PROCESSING #
###############################################################################
class TestHeaderPrinterProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestNHCommandProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
###############################################################################
# PACKETS FROM PIDGIN #
###############################################################################
class TestPidginConnection(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestPidginToRxMQueue(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestDBusReceiver(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestPidginReceiverProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
###############################################################################
# PACKETS FROM TxM #
###############################################################################
class TestTxMIPCReceiverProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestTxMSerial0ReceiverProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestTxMSerial1ReceiverProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestTxMPacketProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
###############################################################################
# PACKETS TO RxM #
###############################################################################
class TestRxMIPCSenderProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
class TestRxMSerialSenderProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
###############################################################################
# PACKETS TO PIDGIN #
###############################################################################
class TestPidginSenderProcess(unittest.TestCase):
"""
This function doesn't have any tests yet.
"""
###############################################################################
# MAIN #
###############################################################################
if __name__ == "__main__":
NH.unit_testing = True
try:
os.remove("NH.pyc")
except OSError:
pass
unittest.main(exit=False)
try:
os.remove("NH.pyc")
except OSError:
pass

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

497
updatelog
View File

@ -1,497 +0,0 @@
TFC NaCl 0.16.05 | Update log
-------------------------------------------------------------------------------
Common changes
-------------------------------------------------------------------------------
Removed from x import y to avoid conflicts in namespace etc.
Refactored code here and there.
Added more unittests. test_tx.py and test_rx.py now evaluate XSalsa20-Poly1305
implementation in PyNaCl using official test vectors by djb. Unittests can now
be run from RPi over SSH.
Improved LUI here and there.
Banner can now be skipped with keyboard interrupt
-------------------------------------------------------------------------------
Tx.py
-------------------------------------------------------------------------------
User can now send encrypted command to RxM with command '/rxkey' that opens a
file prompt. This allows user to load the PSK for contact without turning off
Rx.py.
Added boolean show_file_prompts that by default opens a storage prompt where
user can store contact's PSK. When false, keys are stored in 'keys_to_contact'.
Resolved the "CTR mode needs counter parameter, not IV" issue with Paramiko's
SSH connection with AES CTR mode.
Disallowed ':' and '/' chars in accounts to fix crashes.
Reversed PSK and ECDHE key choice answer to more intuitive order.
Fixed issues when sending dotfiles.
Changed trickle delay's time's constant delay time exceeding from critical
error to soft warning. Raspberry Pi tends to send first packet with greater
delay. User will now be prompted to increase trickle_c_delay if the problem
persists.
-------------------------------------------------------------------------------
Rx.py
-------------------------------------------------------------------------------
Opens a file prompt when '/rxkey' command is sent by TxM. This allows user to
load the PSK for contact without turning off Rx.py.
Fixed issue where lack of rx.<xmpp>.e key on RxM crashes Rx.py when /logging
on <xmpp> command is issued from TxM.
Opens file prompts based on keyfile change commands.
-------------------------------------------------------------------------------
setup.py
-------------------------------------------------------------------------------
Added preinstalled hashes of tested (not audited) crypto libraries.
Improved SSH configuration during installation.
Added NH installation configuration.
Reduced window of compromise time to minimum: setup.py now first downloads
apt-packets. It then downloads and verifies crypto libraries and TFC.
Finally, the installer runs 'sudo ifconfig down' on every interface excluding
'lo', listed by 'ifconfig -a', before extracting and building libraries.
Fixed issues with file permissions when running installer as superuser.
-------------------------------------------------------------------------------
hwrng-nacl.py
-------------------------------------------------------------------------------
Renamed hwrng.py to hwrng-nacl.py in case multiple versions of TFC (CEV/OTP)
use same RPi to load entropy from HWRNG.
-------------------------------------------------------------------------------
dd.py
-------------------------------------------------------------------------------
dd.py now automatically re-sizes terminal window to proper size.
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
TFC NaCl 0.16.01 | Update log
Local key transmission: Bootstrapping security
----------------------------------------------
In the initial bootstrap, Tx.py generates 256-bit local key and 256-bit key
encryption keys with separate processes, where 32-byte /dev/urandom string is
hashed with SHA3-256 (simplesha3 library), that is then passed through 25k
iteration PBKDF2-HMAC-SHA256.
If Tx.py is run on a Raspbian (Raspberry Pi), user can mix entropy from free
hardware design HWRNG, connected to GPIO 4 of the SoC board into the PBKDF2
function. Entropy is sampled with 10Hz frequency and von Neumann whitened
during sampling. Once the vN whitened samples have been collected, the
256-bit entropy is compressed using SHA3-256 hash function.
If Tx.py is run on a computer that has direct ethernet connection to Raspberry
Pi with GPIO HWRNG, Tx.py can SSH into that computer using paramiko library,
and query entropy with program hwrng.py.
The local key is padded to 254 bytes and encrypted with the key encryption key
using PyCrypto library's XSalsa20 stream cipher (192 bit nonce), and 128-bit
Poly1305 MAC. The signed ciphertext is transmitted to RxM through data diode.
User can choose whether to leave data diodes connected to NH and let signed
ciphertext pass through, or whether they want to transmit keys directly from
TxM to RxM by connecting serial interfaces that way. Such configuration
prevents adversary from obtaining the signed ciphertext from NH in case it has
been compromised at this point.
RxM will then ask user to manually type the 64 hex char key decryption key
displayed by TxM. The key decryption key is concatenated with 8 hex char
checksum, that is the truncated SHA3-256 hash of the key decryption key.
Once the 72 char hex key has been typed to Rx.py, the program decrypts the
local key, adds it to database, and shows a two char hex code that lets TxM
know local key delivery succeeded. This is a pre-requisite for the next step,
where account data/keys are transmitted to RxM, encrypted with the local key.
If RxM does not receive the encrypted local key, user can send the packet again
by typing "replay" instead of the device code. The local key transmission
can later be redone with command '/localkey'.
First contact
-------------
User is guided when adding first contact. Tx.py first prompts for account, e.g.
alice@jabber.org and a nick. Empty nick uses nick 'Alice' (automatically parsed
from account). Tx.py asks user to confirm account and nick (choosing no jumps
to beginning of account creation). After this Tx.py prompts user to choose key
exchange method:
Use PSK instead of ECDHE (y/n)?
PSK is explained later so here we choose 'n'/'no' to start ECDHE key exchange.
ECDHE Private key generation
----------------------------
Tx.py generates a curve 25519 ECDHE private key by with PyNaCl's
PrivateKey.generate(), that has been modified to XOR in either bitstring of 256
zeroes, or if provided, 256 bits string of external entropy. Tx.py always
provides the external entropy:
ext_ent = PBKDF2-HMAC-SHA256(SHA3-256(32-bytes from /dev/urandom, salt)).
If Raspbian with HWRNG is available, Tx.py will add the salt to PBKDF2-mix:
salt = SHA3-256( Von Neumann whitening (HWRNG samples))
The number of samples is dynamic and depends on results. This ensures SHA3
always takes in 256 Von Neumann whitened samples. If HWRNG produces bad entropy
i.e. chunk of just zeroes / ones, they are not added as samples.
PyNaCl's PrivateKey.generate()'s own entropy is loaded after external entropy
is provided, thus even if external entropy adds zero entropy, it does not
weaken the overall security, as in such case it would be the equal of XORing
PyNaCl's entropy with bitstring of zeroes.
Once the final entropy has been generated, PyNaCl will use it to create a
private key object.
ECDHE Public key delivery and verification of key authenticity
--------------------------------------------------------------
Tx.py generates the ECDHE public key from the private key object, and transmits
it to the recipient's RxM. Once the 64 hex char public key of contact has been
received by Rx.py the program shows it concatenated with an eight char hex
checksum like the one in local key. User must manually type the 72 hex char
string to TxM. Manual process ensures no automated data channel from network
can infect TxM after setup.
Once key has been successfully entered, Tx.py will ask user to use Signal by
Open Whisper Systems to verify the authenticity of contact's public key.
MITM against OTR session is possible if the adversary has has exfiltrated
respective keys from end points of users. If users find out during Signal call
that the public keys have been generated by a man in the middle, they do not
have to throw in the towel. Instead, users can read the public keys to each
other over Signal, manually type in new public key and effectively bypass the
MITM in network. Once the public key has been successfully typed, Tx.py will
log the public keys for later, higher assurance verification done face to face.
This also enables retrospective detection of MITM, if for some reason users are
unable to verify authenticity of public keys during key exchange.
Shared secret derivation
------------------------
TxM is the only device that receives no automatically input data after setup,
so it is the only device trusted to generate secret keys. Tx.py will generate
two symmetric keys (one for encryption, one for decryption) by concatenating
ECDHE shared secret with one of the public keys, and passing them through
PBKDF2-HMAC-SHA256 (25 000 iterations). This is mandatory for the forward
secrecy to work. Forward secrecy is obtained by passing the encryption keys
through PBKDF2-HMAC-SHA256 (1 000 iterations) between every message. Were the
ECDHE shared secret used as symmetric key for communication in both directions,
offset in key derivation could lead to decryption of collected ciphertexts by
iterating physically compromised key, that lacks behind in PBKDF2 iterations.
Once the symmetric keys are generated, the account details are encrypted and
signed with XSalsa20-Poly1305 using the local key, and transmitted to RxM,
where the contact is automatically added. While this packet doesn't differ in
any way from encrypted command, user can still choose to prevent NH from
receiving the ciphertext by plugging the TxM's data diode directly to RxM once
the public key of contact has been received to RxM. During this period any
message sent by contacts is not received. Dropped packets do not cause
de-synchronisation of keys, as each packet contains the number of times Tx.py
has iterated the initial symmetric encryption key with PBKDF2. This means both
receiving devices can catch up with the Tx.py's key. If Rx.py detects dropped
packets, it will display the catch up progress. KeyID introduces a DoS attack
vector where packets with great keyID blocks Rx.py from operating. This would
however require a MITM attack against the OTR, or messing with the NH; Such DoS
would blow the cover of the high-strength attacker. A more covert DoS can be
mitigated from within the network or IM server, so this attack is an unlikely
problem. Were this evaluation incorrect, an efficient fix would be to use a
separate static MAC key that signs the keyID. For now, it is not implemented.
It should be mentioned that this DoS attack can also be mitigated by frenemies,
but they are easy to block from the IM client.
Additional accounts can be added with commands
/dh <account>( <nick>)
and
/add <account>( <nick>)
PSK keys
--------
While TFC-NaCl is all about convenient public key crypto with exfiltration
secure private keys, it's security will not hold in the long run. Quantum
computers are making their way albeit slowly, and in the future any symmetric
key agreed using Curve25519 ECDHE will be broken. The only public key algorithm
secure against Shor's quantum algorithm is McEliece with Goppa Codes. Long term
security would require users to type in 1 000 000 bit public keys, which is
highly inconvenient regardless of encoding used. As an initial answer to
quantum computing, TFC-NaCl retains the possibility to create pre-shared
symmetric keys for quantum-secure 256-bit XSalsa20-Poly1305:
Answering yes to PSK question in the beginning will create symmetric keys with
PBKDF-HMAC-SHA256 (25 000 iterations), using SHA3-256(urandom(32)) as password,
and if HWRNG connected to Raspbian (SSH or not) is available, by using
SHA3-512(VN(256-bit HWRNG entropy)) as salt.
The contact's account, nick and the symmetric key for local decryption is sent
to RxM, encrypted with local key (again, NH doesn't have to be in between if
user so prefers). Tx.py then prompts user for his or her account name.
If Alice is adding bob@jabber.org as contact, a copy of her symmetric key is
generated for Bob, and conveniently placed inside folder "PSKs", under the name
rx.alice@jabber.org.e - Give this file to bob@jabber.org
Alice must then take a never before used thumb drive, copy the PSK to that and
give it to Bob in a face-to-face meeting. Bob must also have generated a PSK
for Alice in advance. Once Alice has received the thumb drive from Bob, she
plugs it into her RxM (NOT TxM), and copies the
rx.bob@jabber.org.e - Give this file to alice@jabber.org
keyfile to folder "keys". She must then restart Rx.py. Rx.py automatically
strips the trailing instruction from the keyfile and adds Bob as contact. Since
keys for encrypting messages to Bob are already installed, once Bob has copied
keyfile generated by Alice to his RxM, they are ready to communicate.
To ensure forward secrecy and privacy of messages, both parties MUST ensure the
thumb drive given by their contact is physically destroyed immediately after
keys have been added.
If contacts have already been generated, new PSKs can be generated with command
/psk <account>( <nick>)
--------------------------------------------------------------------------------
Other updates over TFC 0.5.5:
-Change of version style to 0.16.01 (0.YY.MM).
-Fully PEP8 compliant coding style/variable naming.
New local testing IPC
---------------------
Local testing of TFC with single computer now uses multiprocessing sockets
instead of files. This reduces IO errors also means less files in TFC root
directory.
Data diode simulators
---------------------
Added dd.py program that emulates data diodes on screen. User
needs to enable dd_sockets boolean in Tx.py and NH.py with argument -d
before this can take place. Each dd.py program is launched with a set of
arguments so that they know which sockets to use and to what direction data
visually flows between terminals. An example set of commands that launches TFC
on *buntu is
gnome-terminal --title='TxM' --geometry=100x35+0+630 -x sh -c "python /dir/Tx.py -d -l"
gnome-terminal --title='NH' --geometry=71x41+920+150 -x sh -c "python /dir/NH.py -d -l"
gnome-terminal --title='RxM' --geometry=100x20+0+0 -x sh -c "python /dir/Rx.py -l"
gnome-terminal --title='dd' --geometry=25x12+740+630 -x sh -c "python /dir/dd.py txnhlr"
gnome-terminal --title='dd' --geometry=25x12+740+425 -x sh -c "python /dir/dd.py nhrxlr"
Setting keyboard shortcut or alias for each of these makes local test startup
fast.
Serial interface auto-config
----------------------------
User's device configuration is asked during installation. This will configure
Tx.py, NH.py and Rx.py to look for either integrated ttyS# (or ttyAMA0 in the
case of Raspbian) serial interface, or for a USB interface (ttyUSB#) if user
decides to use those. The serial interface numbering is finally automatically
detected, so if user accidentally pulls out serial interface, user doesn't have
to manually edit the interface if OS remaps /dev/ttyUSB0 to /dev/ttyUSB1.
NH interface auto-flip
----------------------
Removed the need to run NH.py with -f flag to flip interfaces:
Tx.py will send a serial interface configuration packet to NH.py during start.
In the event NH.py has mapped TxM and RxM in opposite interfaces, initial
listener processes detect Tx.py's configuration packet (or any packet for that
matter), and map correct interfaces to TxM and RxM.
Organized files to folders
--------------------------
Moved location of group files, keyfiles, received files and logfiles to
respective folders. Renamed txc.tfc and rxc.tfc as dotfiles .tx_contacts and
.rx_contacts. The only TFC files visible in software root directory are .py
files (and syslog.tfc once it's first generated).
Added some metadata about TFC to packet headers
-----------------------------------------------
In future this prevents inter-operation with older versions of TFC. It allows
fingerprinting of users (ONLY if NH is remotely exploited or OTR is being MITM
attacked / not used) but forces users to keep up with security updates. New
protocol uses more simple and mature separation of payload components.
Re-designed trickle connection
------------------------------
input_process() now prepares all data to packets with length in range [0, 253]
and puts the data into message or file queue. The queue is periodically read by
sender_process() that opens a thread that padds, encrypts, signs, adds headers
and outputs messages. XSalsa20-Poly1305 algorithms are designed to run constant
time. The system time in ms is recorded immediately before function starts;
Once the function finishes, the timestamp is passed to function trickle_delay()
for evaluation. This function will then sleep the difference between Thread
runtime and value trickle_c_delay to hide platform speed. Platforms should not
introduce problems, as older Raspberry Pi (generation 2), only takes about
400ms to encrypt a message, leaving 1600ms headroom for even slower SoC boards.
Changed random sleep to use /dev/urandom instead of Python math.random. The
CSPRNG prevents statistical attacks that might be able to calculate internal
state of math.random() to detect whether communication is taking place. When
print_ct_stats boolean is enabled, Tx.py shows the statistics about how long
the message/command output thread ran, how long constant time sleep was added,
and how well the constant time matched trickle_c_delay: Average error in
constant time delay was 2ms so the CSPRNG based random sleep will hide the
slight differences effectively. Tx.py will gracefully exit if thread runtime
exceeds trickle_c_delay.
The packet_delay used to prevent congestion / IM server spam with long messages
is now also constant time, to prevent slower data transmission with slower
devices. Default value is 500ms which should be enough to hide metadata about
TxM device performance and make hardware fingerprinting harder. This also makes
prediction of file transfer duration easier.
Improved logging
----------------
Logging can now be enabled for individual contacts with command
/logging {on,off} <account>. When logging is enabled, in addition to automatic
logging of public keys, Tx.py will also log messages sent to contact. This
allows the two users to manually audit whether malware has at some point
infected RxM device(s) and substituted words in logfiles, by cross-comparing
the clean TxM logfile of Alice and purported RxM logfile of Bob, and vice
versa. Rx.py also stores information about dropped packets. Malware that
replaces received messages with notification about dropped packet is harder to
detect; offline record keeping might be required.
Tweakable checksums for data diode error detection
--------------------------------------------------
Changed CRC32 checksums to truncated SHA-256 hashes (8 hex = 32 bits) so
data diode error detection accuracy can be tweaked at will by changing
variable checksum_len. The checksum doesn't have any effect on security:
it only detects transmission errors inside datadiode.
Rewritten NH.py
---------------
Converted classes to functions to fit with procedural programming style. The
program is now much more structured and easier to audit. Added processes that
exchange data via queues. DBus / purple should no longer output error messages,
nor should they drop packets. NH multiprocessing now cleanly exits.
Re-designed file transmission.
------------------------------
/file 1.txt still sends the .txt file from TxM directory. Absolute paths can
also be defined. Non-TFC filenames in Tx.py directory are now included in
tab-complete list. Command "/file" opens a file dialog for easy file selection.
Tx.py will first encode file data to base64 and load it to memory. It'll
evaluate and display approximate amount of packets and time required for file
transfer, based on delay settings.
File data is prepended with a header that contains the name, extension, file
size and estimated number of packets and delivery time for transfer. This
information is displayed to recipient after first packet of file has been
received. File reception must be enabled enabled.
User can control global file reception by setting boolean file_saving to True.
/store {on,off} enables/disables file reception for all contacts
/store on alice@jabber.org enables file reception for just Alice
By default boolean setting a_close_f_recv is True. This means file reception
for Alice is closed automatically after file has been received. When the
variable is false, file storage will remain open until user enters
/store off alice@jabber.org
/store off
During trickle connection, messages and files can be cancelled with commands
'/cm' and '/cf'. Already sent data is out of control of user. Rx.py will
discard received data when it receives cancel packet / new message/file, but
this is a convenience feature, NOT a security feature. Sender-based control is
snake oil: Nothing prevents receiver from modifying their Rx.py to show/log
partially transmitted data. The only solution to this would be to offer closed
source version of TFC, which would defeat all security FOSS software is
designed to offer.
Since the base64 encoding of transmitted files depends on TxM of contact, a
frenemy could still send malware to user's RxM. Thus, the entire manual
decoding feature was removed. File is no longer generated with subprocess.
This prevents shell injection with custom file names that would have otherwise
become possible.
File data during trickle connection is loaded from separate queue that has
lower priority than message queue. This means that users can still exchange
messages during file transmission: file data is output to contact when there
are no messages to output. File data is indistinguishable from messages to NH,
IM client, IM server and any adversary who might observe data from these
systems. During trickle connection, it is extremely hard to determine whether
user is sending noise data, messages or files. No guarantees can unfortunately
be made. Timing attacks are prone to side channel attacks anywhere from
NH/smartphone microphone to user moving the mouse on NH. Python is also a
high level language, which has it's own problems.
Command line arguments
----------------------
Added arguments for Tx.py, Rx.py and NH.py to control many settings from
command line. View arguments by launching program with -h/--help flag.
Hard coded packet length
------------------------
Packet length was hard coded to 254 to ensure everyone uses same value,
and to minimize chance for errors when sending encrypted commands.
Unittesting
-----------
Wrote unittests for Tx.py, Rx.py and NH.py to reduce the amount of bugs.
Created custom error classes for some functions for this purpose as well.
Unittesting is a work in progress, so while TFC is more stable than ever, no
guarantees are made.
New startup banner animation
----------------------------
I want to thank Tom Wallroth for his awesome work. I had so much fun editing
his project to fit print_banner(). I'll leave the details of style as a
surprise, check it out.
Made edits to installer
-----------------------
Installer now uses SHA256 instead of SHA512. As collision resistance against
quantum computers is still 128 bits. The reason for this was simplified import
of file hashes when making changes.
Even more authentication was added with Trust-on-first-use (that being me)
hashes for most downloaded libraries (PIP has no authentication). Provided that
you can verify the setup.py's authenticity, you can detect MITM against crypto
library downloads.
Added installation configuration for HWRNG Pi that TxM connects to over SSH.
Ensured support for *buntu 16.04 OS and fixed issues with Lubuntu/Xubuntu in
previous versions. Dropped NH support for Fedora and OpenSUSE and added it to
Raspbian Jessie. Ensured NH configuration works with latest release of Tails
(2.2.1).
Changed installer naming style, instead of tfcOTPinstaller.py, it's just
setup.py. Run it with 'sudo python setup.py'.