RSA Python Issue

Viewed 160

I am having an issue with getting my python program to decrypt a message with an RSA problem. For some reason my Python program is stalling, really just not outputting anything. Anyone got an idea as to why?

n = 23952937352643527451379227516428377705004894508566304313177880191662177061878993798938496818120987817049538365206671401938265663712351239785237507341311858383628932183083145614696585411921662992078376103990806989257289472590902167457302888198293135333083734504191910953238278860923153746261500759411620299864395158783509535039259714359526738924736952759753503357614939203434092075676169179112452620687731670534906069845965633455748606649062394293289967059348143206600765820021392608270528856238306849191113241355842396325210132358046616312901337987464473799040762271876389031455051640937681745409057246190498795697239
p = 153143042272527868798412612417204434156935146874282990942386694020462861918068684561281763577034706600608387699148071015194725533394126069826857182428660427818277378724977554365910231524827258160904493774748749088477328204812171935987088715261127321911849092207070653272176072509933245978935455542420691737433
c = 18031488536864379496089550017272599246134435121343229164236671388038630752847645738968455413067773166115234039247540029174331743781203512108626594601293283737392240326020888417252388602914051828980913478927759934805755030493894728974208520271926698905550119698686762813722190657005740866343113838228101687566611695952746931293926696289378849403873881699852860519784750763227733530168282209363348322874740823803639617797763626570478847423136936562441423318948695084910283653593619962163665200322516949205854709192890808315604698217238383629613355109164122397545332736734824591444665706810731112586202816816647839648399
e = 65537
q = 156408916769576372285319235535320446340733908943564048157238512311891352879208957302116527435165097143521156600690562005797819820759620198602417583539668686152735534648541252847927334505648478214810780526425005943955838623325525300844493280040860604499838598837599791480284496210333200247148213274376422459183
phi = (q-1)*(p-1)
d = pow(e,-1,phi)
m = pow(c,d)%n
print(m)

I apologize for the weird code formatting. Thanks in advance.

2 Answers

Assuming the math is correct (I didn't check), you definitely want to change this:

m = pow(c,d)%n

to this:

m = pow(c, d, n)

The first spelling computes c**d to full precision before dividing by n to find the remainder. That can be enormously expensive. The second way keeps reducing intermediate results, under the covers, mod n all along, and never needs to do arithmetic in integers larger than about n**2.

So, replacing the last line of your code and continuing:

>>> m = pow(c, d, n) # less than an eyeblink
>>> m
14311663942709674867122208214901970650496788151239520971623411712977120586163535880168563325
>>> pow(m, e, n) == c
True

So the original "message" (c) is recovered by doing modular exponentiation to powers d and e in turn.

As already answered by @TimPeters main issue you have is pow(c,d)%n which should be replaced with pow(c, d, n) for huge performance improvement.

So as your question was already answered, I decided to dig a bit further. Inspired by your question I decided to implement most of RSA mathematics from scratch according to WikiPedia article. Maybe it is a bit offtopic (not what you asked) but I'm sure next code will be useful demo for somebody who wants to try RSA in plain Python, and may be helpful to you too.

Next code has all variables named same as in wikipedia, formulas are also taken from there. Important!, one thing is missing in my code, I didn't implement padding for simplicity (just to show classical RSA math), it is very important to have correct (e.g. OAEP) padding in your system, without it there exist attacks on RSA. Also I used just 512 bits for prime parts of modulus, real systems shoud have thousands of bits to be secure. Also I don't do any splitting of message, long messages should be split into sub-messages and padded to fit modulus bitsize.

Try it online!

import random

def fermat_prp(n):
    # https://en.wikipedia.org/wiki/Fermat_primality_test
    assert n >= 4, n
    for i in range(24):
        a = (3, 5, 7)[i] if n >= 9 and i < 3 else random.randint(2, n - 2)
        if pow(a, n - 1, n) != 1:
            return False
    return True

def gen_prime(bits):
    assert bits >= 3, bits
    while True:
        n = random.randrange(1 << (bits - 1), 1 << bits)
        if fermat_prp(n):
            return n
            
def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a
    
def lcm(a, b):
    return a * b // gcd(a, b)
            
def egcd(a, b):
    # https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
    ro, r, so, s, to, t = a, b, 1, 0, 0, 1
    while r != 0:
        q = ro // r
        ro, r = r, ro - q * r
        so, s = s, so - q * s
        to, t = t, to - q * t
    return ro, so, to

def demo():
    # https://en.wikipedia.org/wiki/RSA_(cryptosystem)
    bits = 512
    p, q = gen_prime(bits), gen_prime(bits)
    n = p * q
    ln = lcm(p - 1, q - 1)
    e = 65537
    print('PublicKey: e =', e, 'n =', n)
    d = egcd(e, ln)[1] % ln
    mtext = 'Hello, World!'
    print('Plain:', mtext)
    m = int.from_bytes(mtext.encode('utf-8'), 'little')
    c = pow(m, e, n)
    print('Encrypted:', c)
    md = pow(c, d, n)
    mdtext = md.to_bytes((md.bit_length() + 7) // 8, 'little').decode('utf-8')
    print('Decrypted:', mdtext)

if __name__ == '__main__':
    demo()

Output:

PublicKey: e = 65537 n = 110799663895649286762656294752173883884148615506062673584673343016070245791505883867301519267702723384430131035038547340921850290913097297607190494504060280758901448419479350528305305851775098631904614278162314251019568026506239421634950337278112960925116975344093575400871044570868887447462560168862887909233
Plain: Hello, World!
Encrypted: 51626387443589883457155394323971044262931599278626885275220384098221412582734630381413609428210758734789774315702921245355044370166117558802434906927834933002999816979504781510321118769252529439999715937013823223670924340787833496790181098038607416880371509879507193070745708801500713956266209367343820073123
Decrypted: Hello, World!
Related