Você está na página 1de 7

Uma introdução prática ao RSA

O esquema RSA

O esquema RSA é composto de 3 algoritmos:

KeyGen Geração de Chaves


Enc Encriptação
Dec Decriptação

KeyGen

Para gerar um par de chaves kSec e kpub , faça:

1. Escolha dois primos grandes p e q


2. Faça n = pq
3. Compute a função totiente de Euler

ϕ(n) = (p − 1)(q − 1)

1. Escolha aleatoriamente um e do conjunto

e ∈ {1 < x < ϕ(n) : gcd(x, ϕ(n)) = 1} .

Isto é, o e e ϕ(n) são é coprimos. Este inteiro e é a chave de encriptação.

1. Compute a chave de decriptação d usando o Algoritmo de Euclides Estendido


−1
d ≡ e mod ϕ(n).

1. O par de chaves secreta e pública é

kSec = (n, e) e kPub = d.

Enc

Seja m um inteiro 0 ≤ m < n a mensagem a ser transmitida. A encriptação de m é simplesmente


e
Enc(m) ≡ m mod n.
Dec

Seja c = Enc(m) , para decriptar c, basta computar


d
Dec(c) ≡ c mod n

e d ed
= (m ) = m mod n .

Como ed ≡ 1 mod ϕ(n) , temos


kϕ(n)+1
Dec(c) = m ,  para algum k

k
ϕ(n)
= (m ) m.


Lembre do Teorema de Euler, que garante que para todo a ∈ Zn , vale que
ϕ
a (n) ≡ 1 mod (n).

Então:
k
ϕ(n)
Dec(c) = (m ) m

k
≡ (1) m mod n

= m mod n.

RSA na prática com SageMath

Geração de chaves

Escolha dois primos

In [12]: MAX_PRIME = 10000


p = random_prime(MAX_PRIME);
q = random_prime(MAX_PRIME)
print('Primos escolhidos: p = %d e q = %d' % (p, q))

Primos escolhidos: p = 367 e q = 1459

Faça n = pq

In [13]: n = p*q
print('n =', n)

n = 535453
Compute a função totiente de Euler

In [14]: phi_n = (p - 1)*(q - 1)


print('phi_n =', phi_n)

phi_n = 533628

Note que o SageMath fornece uma função para isso:

In [15]: euler_phi(n)

Out[15]: 533628

A seguir vem a coisa mais importante dessa revisão pois o resto você acha em qualquer lugar.

Mas observe como ela é mais lenta do que para quem sabe os primos p e q:

In [5]: %time euler_phi(n)

CPU times: user 43 µs, sys: 0 ns, total: 43 µs


Wall time: 49.4 µs

Out[5]: 45211152

In [6]: %time phi_n = (p - 1)*(q - 1)

CPU times: user 20 µs, sys: 0 ns, total: 20 µs


Wall time: 24.6 µs
In [4]: import timeit

START = 10000000
END = 100000000
STEP = 10000000
NSAMPLES = 1000

def estimate_euler_phi_efficiency(start=START, end=END, step=STEP, nsa


mples=NSAMPLES):

data = {
'n': [],
'time_using_primes': [],
'time_without_using_primes': []
}

for max_prime in range(start, end + 1, step):


for _ in range(nsamples):
p = random_prime(max_prime)
q = random_prime(max_prime)

n = p*q

def compute_euler_phi_using_primes():
phi_n = p*q

time_using_primes = timeit.timeit(compute_euler_phi_using_
primes, number=10)

def compute_euler_phi_without_using_primes():
phi_n = euler_phi(n)

time_without_using_primes = timeit.timeit(compute_euler_ph
i_without_using_primes, number=1)

data['n'].append(n)
data['time_using_primes'].append(time_using_primes)
data['time_without_using_primes'].append(time_without_usin
g_primes)

return data

data = estimate_euler_phi_efficiency()
In [47]: %matplotlib notebook

import matplotlib.pyplot as plt

import pandas as pd

df = pd.DataFrame.from_dict(data)

ax = plt.gca()

df.plot.scatter(x='n', y='time_without_using_primes', c='red', ax=ax,


s=0.01)
df.plot.scatter(x='n', y='time_using_primes', c='blue', ax=ax, s=0.01)

Out[47]: <matplotlib.axes._subplots.AxesSubplot object at 0x7fdbf4873940>

A moral da história é: quem não conhece p e q, dificilmente saberá calcular ϕ(n) , se n for suficientemente
grande.

Escolha aleatoriamente um e
e ∈ {1 < x < ϕ(n) : gcd(x, ϕ(n)) = 1}
In [20]: def choose_e(phi_n):
e = randint(1, phi_n)
while gcd(e, phi_n) != 1:
e = randint(1, phi_n)
return e

e = choose_e(phi_n)
print('Chave de encriptação e =', e)

Chave de encriptação e = 362591

In [21]: gcd(e, phi_n)

Out[21]: 1

Compute a chave de decriptação d

Usando o Algoritmo de Euclides Estendido, temos que encontrar:


−1
d ≡ e mod ϕ(n).

Dados a e b, o algoritmo de Euclides estendido nos devolve o gcd(a, b) e inteiros u e v tais que
ua + vb = gcd(a, b).

In [42]: gcd, u, v = xgcd(e, phi_n)


print('gcd =', gcd, ', u =', u, ', v =', v)

gcd = 1 , u = 140579 , v = -95521

Note que
ue + vϕ(n) = 1 ⟹ ue = 1 mod ϕ(n).

Portanto, d = u é a inversa de e mod ϕ(n) .

In [45]: d = u
print('d =', d)

d = 140579

In [41]: e*d % phi_n

Out[41]: 1

Calcular a inversa mod é uma operação muito importante e já vem implementada no Sage:
In [43]: inverse_mod(e, phi_n)

Out[43]: 140579

Encriptação

Seja m um inteiro 0 < m < n .

In [49]: m = randint(1, n)
print(m)

430577

In [60]: enc_m = power_mod(m, e, n)


print('enc_m = ', enc_m)

enc_m = 473622

Decriptação

In [61]: dec_m = power_mod(enc_m, d, n)

In [62]: dec_m

Out[62]: 430577

Você também pode gostar