# -*- coding: cp1252 -*-
# -*- coding: ISO-8859-1 -*-
# Python RSAsms based on Math_lab 0.9.4 by Stefan Mueller-Stach
# Version 0.4
# This software is under GPL
# (c) 2007 Michael Mardaus and Tobias Nagel
# uses Python for Nokia Series 60 

from __future__ import generators
import mmsmodule, random, math, graphics, appuifw, e32, string, operator, sys, os

def sgn(n):
     if n > 0:
         return 1
     elif n < 0:
         return -1
     else:
         return 0

def gcd(a,b):
    x1,x2,y1,y2=1,0,0,1                 
    sgna=sgn(a)  #unnoetig? 
    sgnb=sgn(b)
    a=abs(a)    #unnoetig? 
    b=abs(b)
    while b!=0:                            
        q=a//b                          
        x1,x2,y1,y2=x2,x1-q*x2,y2,y1-q*y2  #x1->x2,x2->x3,y1->y2,y2->y3
        a,b=b,a%b
    return a,x1*sgna,y1*sgnb # ggt>0 and  ax1+bx2=ggt

def miller_rabin(n, num_trials=4):
    if n < 0: n = -n
    if n in [2,3]: return True
    if n <= 4: return False
    m = n - 1
    k = 0
    while m%2 == 0:
        k += 1; m /= 2
    # Now n - 1 = (2**k) * m with m odd
    for i in range(num_trials):
        #ab hier
        if n > 1000000000:
            laenge = len(str(n-1))
            endlaenge = random.randint(2,laenge-1)
            a = bigrand(endlaenge)
        else:
        #fuer diese zeile
            a = random.randrange(2,n-1)                  
        apow = pow(a, m, n)
        if not (apow in [1, n-1]):            
            some_minus_one = False
            for r in range(k-1):              
                apow = (apow**2)%n
                if apow == n-1:
                    some_minus_one = True
                    break                     
        if (apow in [1, n-1]) or some_minus_one:
            prob_prime = True
        else:
            return False
    return True    

def inverse(a,b):
    if a<0:
        while a<0:
             a += b
    y = gcd(a,b)
    if y[0] != 1:
        return None
    return y[1]%b

def nextprime(n):
         np = n + 1
         while np:
                 if miller_rabin(np): return (np)
                 np = np + 1
                 
def powermod(a, m, n):
    ans = 1
    apow = a
    if (m < 0 or n < 1): return None
    while m != 0:
        if m%2 != 0:
            ans = (ans * apow) % n            
        apow = (apow * apow) % n              
        m //= 2
    return ans % n

def rsaKeymaker(bits=768):
    bits = bits//2 - 1
    p = nextprime(bigrand(int(bits*math.log10(2))))
    q = nextprime(bigrand(int(bits*math.log10(2))))    
    n = p * q
    phi = (p-1)*(q-1)
    e = nextprime(bigrand(int(bits*2*math.log10(2))))
    d = inverse(e,phi)
    publicKey = (n,e)
    privateKey = (n,d)
    return (publicKey, privateKey)

def rsaKey_to_file(name,length):
    dir = 'c:'
    if not os.path.isdir(dir+'\\RSA'):
        os.mkdir(dir+'\\RSA')
    if os.path.isfile(dir+'\\RSA\\keys\\prv\\own.prv'):
        return 2
    if not os.path.isdir(dir+'\\RSA\\keys'):
        pubKey, prvKey = rsaKeymaker(int(length))
        os.mkdir(dir+'\\RSA\\keys')
        pub = open(dir+'\\RSA\\keys\\'+name+'.pub','w')
        pub.write(str(pubKey[0])+'\n'+str(pubKey[1])+'\n')
        pub.close()
        os.mkdir(dir+'\\RSA\\keys\\prv')
        prv = open(dir+'\\RSA\\keys\\prv\\own.prv','w')
        prv.write(str(prvKey[0])+'\n'+str(prvKey[1])+'\n')
        prv.close()
        return 1
    else:
        return 0

def rsaEncrypt(msg, key):
    a=[]
    if len(msg) % 16 != 0:
            msg += " "*(16-len(msg)%16)
    while len(msg) != 0:
        tmp= ""
        for i in range(16):
            char = ord(msg[i])
            if char>=100:
                tmp += str(char)
            else:
                tmp += "0"+str(char)
        base=long(tmp)    
        a.append(to_base62(pow(base,key[1],key[0])))
        msg = msg[16:]
    return a

def rsaEn_to_file(msg, recp):
    dir = 'c:\\RSA\\keys'
    if os.path.isfile(dir+'\\'+str(recp)+'.pub'):
        file = open(dir+'\\'+str(recp)+'.pub','r')
        lines = file.readlines()
        file.close()
        N = long(lines[0].replace('\n',''))
        e = long(lines[1].replace('\n',''))
        cipher = rsaEncrypt(msg,(N,e))
        if not os.path.isdir('c:\\RSA\\msg'):
            os.mkdir('c:\\RSA\\msg')
        if os.path.isfile('c:\\RSA\\msg\\msg.py'):
            os.remove('c:\\RSA\\msg\\msg.py')
        file = open('c:\\RSA\\msg\\msg.py','w')
        for i in range(len(cipher)):
            file.write(cipher[i]+'\n')
        file.close()
        return 1
    else:
        return 0
            

def rsaDecrypt(msg, key):
    a = ""
    for i in range(1,len(msg)+1):
        tmp = pow(from_base62(msg[-i]),key[1],key[0])
        while tmp > 0:
            a = chr(tmp%1000) + a
            tmp //= 1000
    return a

def rsaDe_from_file():
    if os.path.isfile('c:\\RSA\\keys\\prv\\own.prv') and os.path.isfile(sys.path[0]+'\\my\\msg.py'):
        homedir = sys.path[0]+'\\my'
        key = open('c:\\RSA\\keys\\prv\\own.prv','r')
        lines = key.readlines()
        key.close()
        N = long(lines[0].replace('\n',''))
        d = long(lines[1].replace('\n',''))
        msg = open(homedir+'\\msg.py','r')
        lines2 = msg.readlines()
        msg.close()
        for i in range(len(lines2)):
            lines2[i]=lines2[i].replace('\n','')
        return rsaDecrypt(lines2,(N,d))
    else:
        return None
    

def to_base62(n):
    alphabet=['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H',
              'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
              'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r',
              's','t','u','v','w','x','y','z']
    v=""
    while n > 0:
        v = (alphabet[n%62])+v
        n //= 62
    return v

def from_base62(v):
    alphabet=['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H',
              'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
              'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r',
              's','t','u','v','w','x','y','z']
    n = 0
    for i in range(len(v)):
        n = 62 * n + alphabet.index(v[i])
    return n
    
def bigrand(n):
    erg = str(random.randint(1,9))
    for i in range(n-1):
        erg += str(random.randint(0,9))
    return long(erg)    

class rsasms:
    def __init__(self):
        self.script_lock = e32.Ao_lock()
        
    def run(self):
        choices=[u"Write & Send RSAsms", u"Write RSAsms", u"Read RSAsms",
                 u"Generate Key Pair"]
        self.lb = appuifw.Listbox(choices, self.sms)
        old_title = appuifw.app.title
        self.T = appuifw.Text()
        self.T.color = (200,0,0)
        self.T.font = u"Series 60 Sans"
        self.refresh()
        self.script_lock.wait()
        appuifw.app.title = old_title
        appuifw.app.body = None
        self.lb = None

    def refresh(self):
        appuifw.app.title = u"RSAsms 0.4"
        appuifw.app.menu = []
        self.T.clear()
        appuifw.app.exit_key_handler = self.exit_key_handler
        appuifw.app.body = self.lb

    def do_exit(self):
        self.exit_key_handler()

    def exit_key_handler(self):
        appuifw.app.exit_key_handler = None
        self.script_lock.signal()

    def display(self,t):
        if t is None:
            pass
        else:            
            self.T.set(unicode(t,'iso-8859-1'))
            appuifw.app.body = self.T  
            appuifw.app.exit_key_handler = self.refresh 
            
    def clear(self):
          self.T.clear()
        
        
    def sms(self, ind = None):
        if not ind == None:
            index = ind
        else:
            index = self.lb.current() 
        if index == 0:
            self.send()   
        if index == 1:
            self.write()
        elif index == 2:
            self.read()
        elif index == 3:
            self.create()
        else:
            pass

    def write(self):        
        self.a=str(appuifw.query(u'Recipient:', 'text'))
        if self.a is None:
            pass
        else:
            if not os.path.isfile('C:\\RSA\\keys\\'+str(self.a)+'.pub'):
                 appuifw.note(u'Missing public key','error')
            else:
                appuifw.app.body = self.T
                appuifw.app.title = u'Text'
                appuifw.app.exit_key_handler = self.refresh
                appuifw.app.menu = [(u'OK',self.save),(u'Clear',self.clear)]
                
    def save(self):
        b = self.T.get()
        if b is None:
            pass
        else:
            appuifw.note(u'Encrypting message...','info')
            res=rsaEn_to_file(b, self.a)
            if res == 1:
                appuifw.note(u'Message encrypted','conf')
            else:
                appuifw.note(u'Error occured','error')
        self.refresh()
    
    def send(self):        
        self.a=str(appuifw.query(u'Recipient:', 'text'))
        if self.a is None:
            pass
        else:
            appuifw.app.body = self.T
            appuifw.app.title = u'Text'
            appuifw.app.exit_key_handler = self.refresh
            appuifw.app.menu = [(u'OK',self.savesend),(u'Clear',self.clear)]
            
    def savesend(self):
        b = self.T.get()
        if b is None:
            pass
        else:
            appuifw.note(u'Encrypting message...','info')
            res=rsaEn_to_file(b, self.a)
            if res == 1:
                appuifw.note(u'Message encrypted','conf')
                sent=mmsmodule.mms_send(unicode(str(self.a),'iso-8859-1'),u'This is a RSAsms v0.4 encrypted message',u'C:\\RSA\\msg\\msg.py')
                if sent == 0:
                    appuifw.note(u'Message sent','conf')
                else:
                    appuifw.note(u'Error occured','error')
            else:
                appuifw.note(u'Error occured','error')
        self.refresh()    
        
    def read(self): 
        appuifw.note(u'Decrypting message...','info') 
        res = rsaDe_from_file()
        if res is not None:
            self.display(res)
        else:
            appuifw.note(u'Error occured','error')
        
    def create(self):
        appuifw.note(u'Creation of a 512 bit RSA key pair may take 5 minutes','info')
        b=appuifw.query(u'Desired Keylength (min: 256):','number',256)
        if b is None or int(b) < 256:
            appuifw.note(u'Invalid Keylength','error')
            pass
        else:
            a=appuifw.query(u'Your Mobile number:','text')
            if a is None:
                appuifw.note(u'No input','error')
                pass
            else:
                appuifw.note(u'Creating keys...','info')
                res = rsaKey_to_file(str(a),str(b))
                if res == 1:
                    appuifw.note(u'Keys successfully created','conf')
                elif res ==2:
                    appuifw.note(u'Keys are already there','error')
                else:
                    appuifw.note(u'Error occured','error')
            
if __name__ == '__main__':
     rsasms().run()
