#!/usr/bin/python2.7
# Authored by Adam Carpenter
# Initial code base authored by Prof. Dmitry Evtyushkin
import random
import time
from mr import is_probable_prime as is_prime
def int_to_bin(i):
o = '{0:08b}'.format(i)
o = (8 - (len(o) % 8)) * '0' + o
return o
# def int_to_bin(i):
# # deprecated; incorrect output
# return "{0:08b}".format(i)
def bin_to_int(b):
return int(b,2)
def str_to_bin(s):
o = ''
for i in s:
o += '{0:08b}'.format(ord(i))
return o
def bin_to_str(b):
l = [b[i:i+8] for i in xrange(0,len(b),8)]
o = ''
for i in l:
o+=chr(int(i,2))
return o
def egcd(a, b): # can be used to test if numbers are co-primes
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
#if g==1, the numbers are co-prime
def modinv(a, m):
#returns multiplicative modular inverse of a in mod m
g, x, y = egcd(a, m)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % m
def sxor(a, b):
# returns the exclusive-or result of two strings/characters
if a == b:
return "0"
else:
return "1"
def srshift(a, b = "0"):
# performs right-shift-like operation on a string;
# b serves as the replacement most-significant bit
return b + a[:-1]
class lfsr:
# Class implementing linear feedback shift register. Please note that it operates
# with binary strings, strings of '0's and '1's.
taps = []
def __init__ (self, taps):
# Receives a list of taps. Taps are the bit positions that are XOR-ed
# together and provided to the input of lfsr
globals()['taps'] = taps
self.register = '1111111111111111'
# initial state of lfsr
def clock(self, i='0'):
# Receives input bit and simulates one cycle
# This include xoring, shifting, updating input bit and returning output
# input bit must be XOR-ed with the taps!!
# grab output bit
outputBit = self.register[-1]
# xor all tap values together
tapXor = "0"
for tap in taps:
tapXor = sxor(tapXor, self.register[tap])
# xor input bit with resulting tap
inputBit = sxor(i, tapXor)
# shift register bits and prepend input bit to stream
self.register = srshift(self.register, inputBit)
# return output bit
return outputBit
def seed(self, s):
# This function seeds the lfsr by feeding all bits from s into input of
# lfsr, output is ignored
for i in s:
o = self.clock(i)
def gen(self,n,skip=0):
# This function clocks lfsr 'skip' number of cycles ignoring output,
# then clocks 'n' cycles more and records the output. Then returns
# the recorded output. This is used as hash or pad
for x in xrange(skip):
self.clock()
out = ''
for x in xrange(n):
out += self.clock()
return out
def H(inp):
# Hash function, it must initialize a new lfsr, seed it with the inp binary string
# skip and read the required number of lfsr output bits, returns binary string
l = lfsr([2,4,5,7,11,14])
l.seed(inp)
return l.gen(56, 1000)
def enc_pad(m,p):
# encrypt message m with pad p, return binary string
# note: function assumes pad p is the same length
# as message m, per the definition of OTP
o = ''
for i in range(0, len(m)):
o += sxor(m[i], p[i])
return o
def GenRSA():
# Function to generate RSA keys. Use the Euler's totient function (phi)
# As we discussed in lectures. Function must: 1) seed python's random number
# generator with time.time() 2) Generate RSA primes by keeping generating
# random integers of size 512 bit using the random.getrandbits(512) and testing
# whether they are prime or not using the is_prime function until both primes found.
# 3) compute phi 4) find e that is coprime to phi. Start from e=3 and keep
# incrementing until you find a suitable one. 4) derive d 5) return tuple (n,e,d)
# n - public modulo, e - public exponent, d - private exponent
# seed random number generator
random.seed(time.time())
# generate rsa primes
p = random.getrandbits(512)
q = random.getrandbits(512)
while not is_prime(p):
p = random.getrandbits(512)
while not is_prime(q):
q = random.getrandbits(512)
# compute n and phi
n = p * q
phi = (p - 1) * (q - 1)
# find an e coprime to phi
e = 3
while egcd(e, phi)[0] != 1:
e += 1
# derive d
d = modinv(e, phi)
# return the tuple
return (n,e,d)