Python中的RSA加密

6
我决定使用Python编写一个简单的RSA加密实现,但每次运行时,在解密和find_key中都会打印出错误信息“IndexError: list out of range”。
以下是错误信息:
p  937
q  353
n  330761
phi  329472
e  5
d  264609
Traceback (most recent call last):
  File "rsa.py", line 94, in 
    print dec_rsa(b, d, n)
  File "rsa.py", line 88, in dec_rsa
    char_array.append(decrypt_byte(i, d, n))
  File "rsa.py", line 77, in decrypt_byte
    return find_key(alpha, (c**d)%n)
  File "rsa.py", line 67, in find_key
    return [k for k, v in dic.iteritems() if v == val][0]
IndexError: list index out of range
代码如下:
import fractions, sys, random, math

def isPrime( no ):
    if no < 2: return False
    if no == 2: return True
    if not no&1: return False
    for x in range(3, int(no**0.5)+1, 2):
        if no%x == 0:
            return False
    return True

def primes_range(low, high):
    primes = []
    for i in range(high-low):
        if isPrime(i+low):
            primes.append(i+low)
    return primes

let = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789~!@#$%^&*()_+'";:[]/<>,."
a, alpha = 2, {}
for i in let:
    alpha[i] = a
    a+=1

Low = 29
High = 1000
p = random.choice(primes_range(Low, High))
q = random.choice(primes_range(Low, High))
while p == q:
    q = random.choice(primes_range(Low, High))
print "p ",p
print "q ",q
#p = 104729
#q = 3

p, q = int(p), int(q)
n = p*q
phi = (p-1)*(q-1)
print "n ",n
print "phi ",phi

for i in range(2, q if q>p else p):
    if fractions.gcd(i, phi) == 1:
        e = i
        break
print "e ",e

def egcd(a,b):
    u, u1 = 1, 0
    v, v1 = 0, 1
    while b:
        q = a // b
        u, u1 = u1, u - q * u1
        v, v1 = v1, v - q * v1
        a, b = b, a - q * b
    return u, v, a

def modInverse(e, phi):
    return egcd(e, phi)[0]%n

d = modInverse(e, n)
print "d ",d

def find_key(dic, val):
    #print "val ",val
    #print "dic ",list(dic.iteritems())
    return [k for k, v in dic.iteritems() if v == val][0]

def encrypt_byte(byte, e, n):
    try:
        m = alpha[byte]
    except:
        m = int(byte)
    return (m**e)%n

def decrypt_byte(c, d, n):
    return find_key(alpha, (c**d)%n)

def enc_rsa(string, e, n):
    char_array = []
    for i in range(len(string)):
        char_array.append(encrypt_byte(alpha[string[i]], e, n))
    return char_array

def dec_rsa(enc_arr, d, n):
    char_array = []
    for i in enc_arr:
        char_array.append(decrypt_byte(i, d, n))
    return ''.join(char_array)

a = "hello, world"
b = enc_rsa(a, e, n)
#print b
print dec_rsa(b, d, n)

2
作为警告——你在这里实现的并不是任何有意义的RSA算法。不要将此代码或其任何衍生代码用于安全目的。事实上,根本不要使用它。 - user149341
2个回答

5

我希望你喜欢学习Python!

以下是需要注意的几点:

(1) 你的isPrime函数有问题:它认为1是质数,2和3不是,但是所有的25、35、121、143、289、323、529、841、899都不是。得到一个合成数会导致问题。

(2) 你还没有检查p != q。

(3) alpha[str(byte)] 应该是alpha[byte](否则你会得到“96llo, worl5”)。

(4) 你选择了错误的乘法模反元素。你需要modInverse(e, phi(n)),而不是modInverse(e, n);可以参考这个实例

修复这些问题后,它对我来说似乎可以工作了。

以下不是错误,而是建议:你应该使用pow(c,d,n)而不是(c**d)%n;对于大数字,前者将更快。此外,如果你想把字母转换成数字,而你并不真正关心数字是多少,你可以使用“ord”/“chr”函数,甚至不需要字典。无论如何,你可能想要交换字典中的键和值:现在你的find_key就像使用列表一样,因为你只是在所有的k,v对中搜索,直到找到匹配项。

希望这有所帮助!


  1. 修复了素数函数,谢谢您的提示。
  2. 我现在检查 p != q
  3. 已修复。
  4. 我将其更改为 modInverse(e, phi)
  5. 仍然出现 IndexError。
  6. 我现在将重新发布代码。
- tekknolagi
1
你没有在代码中进行更改,你只是将 modInverse 函数中第二个变量的名称从 n 改为了 phi。你仍然使用 'd = modInverse(e, n)' 进行调用。这意味着 modInverse 函数内部的 "phi" 仍然是 n。 - DSM
哦,我太蠢了...非常感谢! 我太累了 :) - tekknolagi

0

RSA的实现可以进一步简化如下:

1.选择两个不同的大素数,为了简单起见,我们选择p=937q=353,就像例子中一样。

2.计算n = p*q

3.计算欧拉函数φ(n) ≡ (p-1)*(q-1)

4.选择公钥eφ(n)互质,为了简单起见,我们选择e=5,它是一个素数

5.使用扩展欧几里得算法(乘法逆元算法)从这里计算私钥d,使得d*e ≡ 1 (mod φ(n))

计算模n的乘法逆元

# solution t to a*t ≡ 1 (mod n) 

def multiplicative_inverse(a, n):

    t, newt = 0, 1
    r, newr = n, a

    while newr != 0:
        q = r // newr
        t, newt = newt, t - q * newt
        r, newr = newr, r - q * newr

    if t < 0:
        t = t + n

    return t

步骤1-5的Python代码:

p, q = 937, 353 # use large primes here
n = p*q
φ = (p-1)*(q-1)
e = 5 # choose public key e as a prime, s.t., gcd(φ, e) = 1
d = multiplicative_inverse(e, φ) # private key d
print(d)
# 131789

6. 在发送端使用接收者的公钥(e)对消息(明文)进行加密

7. 在接收者端使用其私钥(d)解密接收到的密文

以下代码展示了加密/解密的实现方法:

def rsa_encrypt(plain_text, e, n):
    # ideally we should convert the plain text to byte array and 
    # then to a big integer which should be encrypted, but here for the sake of 
    # simplicity character-by-character encryption is done, which will be slow in practice
    cipher_text = [ord(x)**e % n for x in plain_text]        
    return cipher_text

def rsa_decrypt(cipher_text, d, n):
    decoded_text = ''.join([chr(x**d % n) for x in cipher_text])
    return decoded_text 

现在,让我们使用上述函数进行加密/解密:
plain_text = 'Hello world'
cipher_text = rsa_encrypt(plain_text, e, n)
print(cipher_text)
# [296543, 169726, 215626, 215626, 293167, 147571, 122732, 293167, 217253, 215626, 102687]
decoded_text = rsa_decrypt(cipher_text, d, n)
decoded_text 
# Hello world

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接