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

Posted

技术标签:

【中文标题】使用标准库的 Python 中的私有/公共加密【英文标题】:Private/Public Encryption in Python with Standard Library 【发布时间】:2012-01-22 06:59:17 【问题描述】:

是否有一个模块在我的搜索中无法发现允许编写如下代码?想要编写这样的代码的原因并不重要。我所追求的只是一些具有简单 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 文件或其他类型证书的库也很常见。我希望避免处理此类文件,即时生成公钥和私钥,并快速处理内存中的数据。

【问题讨论】:

我不知道一个理想的解决方案,但你总是可以依靠使用 python 子进程模块通过命令行调用 gpg 【参考方案1】:

公钥加密不在标准库中。不过,PyPi 上有一些第三方库:

PyCrypto RSA Python

如果您对它背后的数学感兴趣,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)

【讨论】:

您知道这些库中是否有任何一个既支持如上所示的简单 API 又在 Python 3.x 上运行的库? RSA Python 链接包含纯 Python 代码,包括您正在寻找的大部分内容。您可能需要对其进行一些调整以完全匹配您正在寻找的 API。 APSN 配方、pow 示例和 PyCrypto 在 Python 3 上运行良好。 嗨@RaymondHettinger。正如您在此处描述的那样,我想在 java 中实现此算法。但我看到 python 用pow(code,pub,pri) 轻松做的事情几乎不可能用 java 计算。我想我错过了某事。你会建议我吗? (即使没有,谢谢你的回答:)) 嗨@RaymondHettinger,我缺少的一点是模幂运算。 Python 本机实现它。因此,即使在 RPi 中,计算也非常快。再次感谢。 @MertGülsoy 快速模指数计算很容易实现。见math.stackexchange.com/a/453108【参考方案2】:

PyCrypto 自 2.4.1 起适用于 Python 3。

【讨论】:

【参考方案3】:

这是另一个例子

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

【讨论】:

这段代码没有任何工作机会。缩进被破坏。此外很难阅读(变量名)【参考方案4】:

这里在各个方面都提到了 PyCrypto。有了这个答案,而不是评论,我想指出 PyCrypto 的最后一个版本是从 2013 年开始的。对于密码库,这是不可接受的,因为潜在的危险问题没有得到解决。

但是,PyCrypto 有一个分支,PyCryptodome,将继续开发。 Link to Github: https://github.com/Legrandin/pycryptodome

【讨论】:

以上是关于使用标准库的 Python 中的私有/公共加密的主要内容,如果未能解决你的问题,请参考以下文章

python中的AES加密与解密

python--标准库与扩展库的导入与使用

HTTPS-Only标准:美国所有政府网站将使用HTTPS加密

Python标准库的主要功能都有哪些?

python标准库和第三方库的区别

Python标准库的学习准备