Download this file
#!/usr/bin/env python
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program 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.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
# Inspired by Jeff Connelly
# Matthieu Weber, 2011
import time, sha, sys, socket
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-l",
help="How much data should be output (use 'b' suffix for bits, 'K' for kByte, 'M' for MByte)",
type="string",
dest="data_length")
parser.add_option("-o",
metavar="FILE",
help="Output file (default is the standard output)",
action="store",
type="string",
dest="output_file")
parser.add_option("-x",
help="Output hexadecimal numbers instead of raw data",
action="store_true",
dest="hex",
default=False)
parser.add_option("-q",
help="Quiet mode",
action="store_true",
dest="quiet",
default=False)
parser.add_option("-e",
metavar="FLOAT",
help="Number of bits of entropy per byte (default is %default)",
action="store",
type="float",
dest="entropy",
default=5.0)
#parser.add_option("-r",
# metavar="INT",
# help="Serial port's bitrate (default is %default)",
# action="store",
# type="int",
# dest="rate",
# default=57600)
#
#parser.add_option("-d",
# metavar="DEVICE",
# help="Serial port device (default is %default)",
# action="store",
# type="string",
# dest="device",
# default="/dev/ttyUSB0")
(options, args) = parser.parse_args()
entropy_per_byte = options.entropy
hash_len = sha.digest_size
read_len = int((hash_len * 8) / entropy_per_byte)
if options.data_length == None:
parser.exit(1, "Error: You must specify a data length\n")
data_length = options.data_length
if data_length[-1] == 'b':
data_length = int(data_length[:-1])
if data_length % 8 != 0:
parser.exit(1, "Error: data length must be a multiple of 8 bits\n")
else:
data_length /= 8
elif data_length[-1] == 'K':
data_length = int(data_length[:-1])*1024
elif data_length[-1] == 'M':
data_length = int(data_length[:-1])*1024*1024
else:
try:
data_length = int(data_length)
except ValueError:
parser.exit(1, "Error: '%s' is not a valid data length\n" % data_length)
output_count = 0
output_file = sys.stdout
if options.output_file:
output_file = open(options.output_file, "w")
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("localhost", 9876))
sock_file = sock.makefile("rb") # buffered
except socket.error:
parser.exit(1, "Error: Failed to connect to button_box_server\n")
start_time = time.time()
next_check_time = start_time+1
cont = True
while cont and (data_length == None or output_count < data_length):
block = ""
while len(block) < read_len:
try:
sock.send("Q")
# expect to receive 'Qx\n' where x is a random byte
buf = sock_file.readline()
while not buf[0] == 'Q':
buf = sock_file.readline()
block += buf[1] # get the random byte
except KeyboardInterrupt:
cont = False
break # exit the inner loop
if not cont:
break # exit the outer loop
to_write = hash_len
if output_count + hash_len > data_length:
to_write = data_length - output_count
if options.hex:
hash = sha.new(block).hexdigest()
output_file.write(hash[:to_write*2])
else:
hash = sha.new(block).digest()
output_file.write(hash[:to_write])
output_file.flush()
output_count += to_write
if not options.quiet and time.time() > next_check_time and output_count > 0:
next_check_time = time.time()+1
elapsed = time.time() - start_time
eta = elapsed / (float(output_count) / data_length) - elapsed
sys.stderr.write("\r%9d bytes (%3d%%), ETA: %02d:%02d (%.3f kbps)" % (output_count, 100.0 * output_count/data_length, eta/60, eta%60, 8*output_count/(1000.0*elapsed)))
sys.stderr.flush()
if options.hex:
output_file.write("\n")
if not options.quiet:
elapsed_time = time.time() - start_time
sys.stderr.write("\nElapsed time: %02d:%02d, rate: %.3f kbps, %d bytes written\n" %
(elapsed_time/60, elapsed_time % 60, 8*output_count/(1000.0*elapsed_time), output_count))