Частное/общедоступное шифрование в Python со стандартной библиотекой
Есть ли модуль, который мой поиск не смог обнаружить, что позволит писать код следующим образом? Причина того, что вы хотите написать такой код, неважно. Все, что мне нужно - это код, который имеет простой 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
Шифрование с открытым ключом не входит в стандартную библиотеку. Существуют некоторые сторонние библиотеки на 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)
Ответ 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 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 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 Algorithm
def euclid(a, b):
if b==0:
return a
else:
return euclid(b, a % b)
# Euclid 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}
Ответ 3
PyCrypto работает на Python 3 с 2.4.1.