Python标准库中的私有/公共加密

23

有没有一个模块可以让我像下面这样写代码?我搜索了很久也没找到。我想要这样写代码的原因并不重要,我只是想要一些能够简单生成公钥和私钥的代码,并且可以轻松地使用这些密钥对数据进行编码和解码的简单 API。

import module, os

method, bits, data = 'RSA', 1024, os.urandom(1024)
public, private = module.generate_keys(method, bits)

assert isinstance(public, bytes) and isinstance(private, bytes)
assert module.decode(module.encode(data, private), public) == data
assert module.decode(module.encode(data, public), private) == data

大部分看起来可用的选项都需要下载一个Python 2.x的包才能运行。还经常会发现只适用于PEM文件或其他类型证书的库。我想避免处理这些文件,并希望能够动态生成公钥和私钥,快速在内存中处理数据。


1
我不知道有什么理想的解决方案,但你可以使用Python子进程模块通过命令行调用gpg。 - TJD
4个回答

38

公钥加密不在标准库中。但是可以在PyPi上找到一些第三方库:

如果你对其背后的数学感兴趣,Python使得实验变得容易:

code = pow(msg, 65537, 5551201688147)               # encode using a public key
plaintext = pow(code, 109182490673, 5551201688147)  # decode using a private key

密钥生成稍微有些复杂。这是一个使用urandom作为熵源在内存中进行密钥生成的简化示例。 该代码可以在Py2.6和Py3.x下运行:

import random

def gen_prime(N=10**8, bases=range(2,20000)):
    # XXX replace with a more sophisticated algorithm
    p = 1
    while any(pow(base, p-1, p) != 1 for base in bases):
        p = random.SystemRandom().randrange(N)
    return p

def multinv(modulus, value):
    '''Multiplicative inverse in a given modulus

        >>> multinv(191, 138)
        18
        >>> 18 * 138 % 191
        1

    '''
    # http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
    x, lastx = 0, 1
    a, b = modulus, value
    while b:
        a, q, b = b, a // b, a % b
        x, lastx = lastx - q * x, x
    result = (1 - lastx * modulus) // value
    return result + modulus if result < 0 else result

def keygen(N):
    '''Generate public and private keys from primes up to N.

        >>> pubkey, privkey = keygen(2**64)
        >>> msg = 123456789012345
        >>> coded = pow(msg, 65537, pubkey)
        >>> plain = pow(coded, privkey, pubkey)
        >>> assert msg == plain

    '''
    # http://en.wikipedia.org/wiki/RSA
    prime1 = gen_prime(N)
    prime2 = gen_prime(N)
    totient = (prime1 - 1) * (prime2 - 1)
    return prime1 * prime2, multinv(totient, 65537)

1
你知道这些库中是否有支持像上面展示的简单 API,且可以在 Python 3.x 上运行的吗? - Noctis Skytower
3
这个 RSA Python 链接包含了纯 Python 代码,其中包括你所寻找的许多内容。你可能需要稍微调整一下它才能完全匹配你所需的 API。APSN 的示例、pow 示例和 PyCrypto 在 Python 3 上也可以正常工作。 - Raymond Hettinger
嗨@RaymondHettinger,我所缺少的是模幂运算。Python在本地实现了它。因此,即使在RPi上,计算速度也非常快。再次感谢。 - Mert Gülsoy
@MertGülsoy 快速模指数计算很容易实现。请参见http://math.stackexchange.com/a/453108 - Raymond Hettinger
@BoppreH 请重新阅读这篇文章。我给出了“预制库”的链接。代码本身加上了“如果您对其背后的数学感兴趣,Python使得实验变得容易”的前缀。我还写道“这里有一个简化的例子”。我认为那已经很清楚了。您的评论质疑了答案,好像它有什么问题一样。在我看来,这并没有为文章的读者提供服务——它只会让人们不愿意回答如何使算法工作的问题。 - Raymond Hettinger
显示剩余3条评论

3

PyCrypto 在 2.4.1 版本后支持 Python 3。


2

这是另一个例子

import random


# RSA Algorithm



ops = raw_input('Would you like a list of prime numbers to choose from (y/n)? ')
op = ops.upper()

if op == 'Y':
    print """\n 2      3      5      7     11     13     17     19     23     29 
31     37     41     43     47     53     59     61     67     71 
73     79     83     89     97    101    103    107    109    113 
127    131    137    139    149    151    157    163    167    173 
179    181    191    193    197    199    211    223    227    229 
233    239    241    251    257    263    269    271    277    281 
283    293    307    311    313    317    331    337    347    349 
353    359    367    373    379    383    389    397    401    409 
419    421    431    433    439    443    449    457    461    463 
467    479    487    491    499    503    509    521    523    541 
547    557    563    569    571    577    587    593    599 \n"""
    rsa()
else:
    print "\n"
    rsa()

def rsa():
    # Choose two prime numbers p and q
    p = raw_input('Choose a p: ')
    p = int(p)

while isPrime(p) == False:
    print "Please ensure p is prime"
    p = raw_input('Choose a p: ')
    p = int(p)

q = raw_input('Choose a q: ')
q = int(q)

while isPrime(q) == False or p==q:
    print "Please ensure q is prime and NOT the same value as p"
    q = raw_input('Choose a q: ')
    q = int(q)

# Compute n = pq
n = p * q

# Compute the phi of n
phi = (p-1) * (q-1)

# Choose an integer e such that e and phi(n) are coprime
e = random.randrange(1,phi)

# Use Euclid's Algorithm to verify that e and phi(n) are comprime
g = euclid(e,phi)
while(g!=1):
    e = random.randrange(1,phi)
    g = euclid(e,phi)

# Use Extended Euclid's Algorithm 
d = extended_euclid(e,phi)

# Public and Private Key have been generated
public_key=(e,n)
private_key=(d,n)
print "Public Key [E,N]: ", public_key
print "Private Key [D,N]: ", private_key

# Enter plain text to be encrypted using the Public Key
sentence = raw_input('Enter plain text: ')
letters = list(sentence)

cipher = []
num = ""

# Encrypt the plain text
for i in range(0,len(letters)):
    print "Value of ", letters[i], " is ", character[letters[i]]

    c = (character[letters[i]]**e)%n
    cipher += [c]
    num += str(c)
print "Cipher Text is: ", num

plain = []
sentence = ""

# Decrypt the cipher text    
for j in range(0,len(cipher)):

    p = (cipher[j]**d)%n

    for key in character.keys():
        if character[key]==p:
            plain += [key]
            sentence += key
            break
print "Plain Text is: ", sentence

# Euclid's Algorithm
def euclid(a, b):
   if b==0:
   return a
else:
   return euclid(b, a % b)

# Euclid's Extended Algorithm
def extended_euclid(e,phi):
    d=0
    x1=0
    x2=1
    y1=1
    orig_phi = phi
    tempPhi = phi

while (e>0):
  temp1 = int(tempPhi/e)
  temp2 = tempPhi - temp1 * e
  tempPhi = e
  e = temp2

  x = x2- temp1* x1
  y = d - temp1 * y1

  x2 = x1
  x1 = x
  d = y1
  y1 = y

  if tempPhi == 1:
      d += phi
      break
return d

# Checks if n is a prime number
def isPrime(n):
   for i in range(2,n):
    if n%i == 0:
        return False
return True

character = {"A":1,"B":2,"C":3,"D":4,"E":5,"F":6,"G":7,"H":8,"I":9,"J":10,
     "K":11,"L":12,"M":13,"N":14,"O":15,"P":16,"Q":17,"R":18,"S":19,
     "T":20,"U":21,"V":22,"W":23,"X":24,"Y":25,"Z":26,"a":27,"b":28,
     "c":29,"d":30,"e":31,"f":32,"g":33,"h":34,"i":35,"j":36,"k":37,
     "l":38,"m":39,"n":40,"o":41,"p":42,"q":43,"r":44,"s":45,"t":46,
     "u":47,"v":48,"w":49,"x":50,"y":51,"z":52, " ":53, ".":54, ",":55,
     "?":56,"/":57,"!":58,"(":59,")":60,"$":61,":":62,";":63,"'":64,"@":65,
     "#":66,"%":67,"^":68,"&":69,"*":70,"+":71,"-":72,"_":73,"=":74}

2
这段代码没有任何机会能够工作。缩进有问题。此外,很难阅读(变量名称)。 - Mikaelblomkvistsson

1
在这里提到了PyCrypto的各种要点。我想指出的是,PyCrypto的最后一个版本发布于2013年,因此本回答不是评论。对于加密库来说,这是不可接受的,因为潜在的危险问题没有得到修复。
然而,有一个名为 PyCryptodome 的PyCrypto分支将继续开发。链接到Github:https://github.com/Legrandin/pycryptodome

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