#####################################solution for the caesar cypher########

### use hw 4 
from string import *
def convert_char(c):
    return ascii_lowercase.find(c,0)



### convert a text into a list of integers.
def convert_text(t):
    n=len(t)
    output=[]
    for i in range(0,n):
        output.append(convert_char(t[i]))
    return output
    
def list_to_text(l):
    chain=""
    for i in range(0,len(l)):
        chain+= ascii_lowercase[l[i]]    
    return chain

### takes a text with the key, apply the caesar encryption to the text and returns the encrypted text   
def caesar_encrypt(text,key):
    l=convert_text(text)
    for i in range(0,len(l)):
        l[i]= (l[i]+key) % 26 
    return list_to_text(l)


def caesar_encrypt_file(inputname,outputname,key):
    f_in= open(inputname,"r+")
    f_out= open(outputname, "w")
    for line in f_in:
        f_out.write(caesar_encrypt(line,key))    
        f_out.write("\n")
    f_in.close()
    f_out.close()


##determine caesar key

def determine_caesar_key(filename):
    f=open(filename,"r")
    line=f.readline()
    print("size of the line "+ str(len(line)))
    for p in range(1,26):
        ## encrypt file with the key p
        m_p=caesar_encrypt(line,p)
        if (m_p.find("the")!= -1):
            print("Decrypting with the key "+str(p)+" and the first line gives :"+ str(m_p))
            
    f.close()

determine_caesar_key("caesar_encrypted_110801618.txt")
    

 
#file_treatment("text_decrypt_caesar.txt", "decrypt_caesar.txt")
 
#caesar_encrypt_file("decrypt_caesar.txt","caesar_encrypted.txt",6) 


#####################################################################
######################################################################
########################### Vigenere decryption######################

### take a full text and the key is a list of integers
### encrypts using a vigenere method
def vigenere_encrypt(text,key):
    offset=0
    n=len(key)
    chain=""
    for i in range(0,len(text)):
        c=text[i]
        if (c.isalpha()==True):
            num_k= (convert_char(c)+ key[offset])%26
            chain+= ascii_lowercase[num_k]
            offset= (offset +1)%n
        else:
            chain+= c
    return chain        

def vigenere_encrypt_file(inname,outname,key):
    fin=open(inname,"r+")
    fout=open(outname,"w")
    print("Encrypting with key "+ str(key))
    text=fin.read()
    
    fout.write(vigenere_encrypt(text,key))
    
    fin.close()
    fout.close()

def determine_vigenere_key(filename):
    f=open(filename,"r")
    
    line=f.readline()
    print("the first line has size : "+str(len(line)))
    for i in range(0,26):
        for j in range(0,26):
            key=[i,j]    
            m=vigenere_encrypt(line,key)
            if(m.find("the")!=-1):
                print("testing for the key "+ str(key)+ "and the decrypted line is:\n  \t "+ m)
    f.close()
determine_vigenere_key("vigenere_encrypted_110801618.txt") 

###############################################################
#############################RSA

n=3387981625011481

def find_factor(n):
    d=2
    list_factor=[]
    while (d*d <= n):
        if ((n%d)==0):
            return d
        else:
            d+=1
    ### ending here d^2 > n
    print("no factor found, the number is prime")
    return -1 

#p=find_factor(n)
#q=int(n/p)
#print("The prime numbers are "+str(p) + " and "+str(q))

p= 32452843
q= 104397067
N=(p-1)*(q-1)

### assume d1 <= d2
def bezout(d1,d2):
    if ((d2%d1)==0):
        k=d2//d1
        return [1-k , 1]
    k=d2//d1
    r=d2%d1
    l=bezout(r, d1)
    l0=l[0]
    l1=l[1]
    return [l1 - l0* k , l0]    


def compute_decryption_key(e,N):
    d1=1
    d2=1
    if (e< N):
        l=bezout(e,N)
        d1=l[0]%N
        d2=l[1]%N
    else:
        l=bezout(N,e)
        d1=l[1]
        d2=l[0]
    ### we found the two bezout integers
    ## d1 e + d2 N = 1 
    return d1   

#print(compute_decryption_key(e,N))


def fast_expand(m,e,n):
    if (e==0):
        return 1
    if ((e%2)==1):
        return (m* fast_expand(m, e-1,n))%n        
    else: 
        k=e//2
        
        return  fast_expand( ((m*m)%n), k,n)

def rsa_decrypt(m,d,n):
    return fast_expand(m,d,n)
def ascii_to_char(n):
    return chr(n)    
    
### take a number (with 15 digits) and recover a string    
def reconvert(n):
    l=[]
    value=n
    for i in range(0,5):
        l.insert(0,value%1000)
        value=value//1000
    output=""
    for j in l:
        #print("the value of j is" + str(j))
        output= output+ ascii_to_char(j)
    return output        

def decrypt_rsa_file(filename):
    fin=open(filename,"r")
    first=fin.readline()
    line1_list=first.split("=")
    e=int(line1_list[1])
    global N,n
    d=compute_decryption_key(e,N)
    print("The encryption key is "+str(e))
    ##read the second line
    fin.readline()
    
    line=fin.readline()
    l=line.split(",")
    num=len(l)
    out=""
    for j in range(0,num):
        out+= reconvert(rsa_decrypt(int(l[j]), d, n))
    ##print(out)
    fin.close()
    return out


def decrypt_rsa_file_output(infile,outname):
    m=decrypt_rsa_file(infile)
    f=open(outname,"w")
    f.write(m)
    f.close()
    

decrypt_rsa_file_output("rsa_encrypted_110801618.txt","rsa_decrypted_110801618.txt" )           
