Skip to content

Instantly share code, notes, and snippets.

@yugi386
Created December 28, 2011 00:00
Show Gist options
  • Save yugi386/1525523 to your computer and use it in GitHub Desktop.
Save yugi386/1525523 to your computer and use it in GitHub Desktop.
Criptografia RSA completa totalmente escrita em Rubi
#################################################################
# O ALGORITMO ASSIMÉTRICO RSA COMPLETO
# PROGRAMADOR: YUGI
# DATA: 27/12/2011
#################################################################
# ============================================================================================
# OBSERVAÇÕES:
# AQUI NÓS TEMOS A CRIPTOGRAFIA RSA TOTALMENTE ESCRITA EM RUBI
# UMA CHAVE DE 1024 BITS PODE SER GERADA EM MENOS DE 2 MINUTOS
# UMA CHAVE DE 2048 BITS PODE SER GERADA EM 10 MINUTOS
# UMA CHAVE DE 4096 BITS PODE SER GERADA EM 1 HORA (PODENDO LEVAR MAIS TEMPO)
# UMA CHAVE DE 8192 BITS PODE LEVAR MUITAS HORAS PARA SER GERADA
# COMO RUBI É UMA LINGUAGEM INTERPRETADA ELA É MUITO MAIS LENTA DO QUE C, POR EXEMPLO.
# --------------------------------------------------------------------------------------------
# OBS2: TESTES FEITOS EM PROCESSADOR INTEL 2,4 GHZ
# ============================================================================================
require 'ftools'
def hora()
agora = Time.new
puts agora.strftime("%d/%m/%Y - %H:%M:%S")
return agora.strftime("%H:%M:%S")
end
# ---------------------------------------------------------------------
# CALCULA O MÁXIMO DIVISOR COMUM ENTRE DOIS NÚMEROS
def mdc(n1,n2)
if n1 > n2
max = n1
min = n2
else
max = n2
min = n1
end
while TRUE
mdc = min
tmp = max % min
max = min
min = tmp
if min == 0
break
end
if max == 1
mdc = 1
break
end
end
return mdc
end
# ---------------------------------------------------------------------
# CALCULA O MÍNIMO MULTIPLO COMUM DE DOIS NUMEROS
def mmc(n1,n2)
tmp = mdc(n1,n2)
mmc = n1 * (n2 / tmp)
return mmc
end
# ---------------------------------------------------------------------
# FUNÇÃO PARA EXPONENCIAÇÃO RÁPIDA:
def pot(n,exp,base)
exp = exp -1
p = n
if exp == 0
return 1
end
if exp == 1
return n
end
if exp <= 1000
for cont in (1..exp)
n = (n * p) % base
end
return n
else
# DINAMIZANDO A POTENCIAÇÃO...
vetormapa = Array.new
for xcont in (0..1000)
vetormapa[xcont] = 1
end
tmp = p
xcel = 0
xzero = 1000
while TRUE
for cont in (1..1000)
vetormapa[xcel] = (vetormapa[xcel] * tmp) % base
end
tmp = vetormapa[xcel]
xcel = xcel + 1
xzero = xzero * 1000
if exp < xzero
break
end
if xcel > 1000
break
end
end
result = 1
exp = exp + 1
# Gerencimento para operacoes com números gigantes:
xcont = 1000
xzero = 1
for ct in (0..1000)
xzero = xzero * 1000
end
while TRUE
if exp >= xzero
while TRUE
if exp >= xzero
result = (result * vetormapa[xcont]) % base
exp = exp - xzero
else
break
end
end
end
xzero = xzero / 1000
xcont = xcont -1
if xcont < 0
break
end
end
n = result
for cont in (1..exp)
n = (n * p) % base
end
return n
end
end
# ----------------------------------------------------------------------
# ALGORITMO DE RABIN MILLER, VERIFICA SE UM NÚMERO PODE SER PRIMO
def rmiller(n,xint)
# a entrada deve ser um número ímpar e maior do que 3
# calculando n-1 na forma 2^s * d, onde d é ímpar
prime = FALSE
k = 0
m = n -1
a = b = j = 0
while (m % 2 == 0)
m = m / 2
k = k + 1
end
verif = 0
while (!prime && j < xint)
a = rand(n) % (n-1) # testemunha
if xint == 1
a = a % 1_000_000_000
end
if a <= 1
a = a + 2
end
b = pot(a,m,n)
if b == 1
prime = TRUE
else
for cont in (1..k)
if (b == n-1)
prime = TRUE
break
else
b = (b * b) % n
end
end
end
j = j + 1
end
if prime == TRUE
#puts "O Número " + n.to_s + " pode ser primo | Rounds.: " + j.to_s
else
puts "O número " + n.to_s + " é composto | Rounds.: " + j.to_s
end
if prime == TRUE
return n # retorna o número caso ele for primo
else
return 0 # caso contrário retorna 0
end
end
# ----------------------------------------------------------------------
# CALCULA O INVERSO MULTIPLICATIVO DE UM NÚMERO POR UMA BASE
def invmul(numero, base)
if numero >= base
puts "ERRO: A BASE DEVE SER MAIOR QUE O NÚMERO"
exit
end
if mdc(base,numero) != 1
puts "NÚMERO E BASE DEVEM SER PRIMOS ENTRE SI!"
exit
end
cof = Array.new
posic = 0
basex = base
num = numero
while (num > 1)
tmp = 1
tmp = basex / num
if tmp > 1
tmp = tmp - 1
end
while TRUE
if num * tmp >= basex
cof[posic] = tmp - 1
posic = posic + 1
break
end
tmp = tmp + 1
end
tmp = basex
basex = num
num = tmp - (num * cof[posic-1])
end
vet = Array.new
tam = cof.length
tam = tam -1
posic = tam
for cont in (0..tam)
vet[posic] = cof[cont]
posic = posic -1
end
varJ = 0
varB = 1
tam = vet.length
tam = tam -1
for cont in (0..tam)
varR = varJ + (varB * vet[cont])
varJ = varB
varB = varR
end
tam = cof.length
if tam % 2 == 0
inv = varR
else
inv = base - varR
end
return inv
end
# --------------------------------------------------------------------
# Função que retorna todos os números primos até 1.000.000
def mapaprimo()
limite = 1_000_000
xcont = 5
num = 13
mapaprimo = Array.new
mapaprimo[0] = 2
mapaprimo[1] = 3
mapaprimo[2] = 5
mapaprimo[3] = 7
mapaprimo[4] = 11
while TRUE
primo = TRUE
divide = 3
cont = 0
tam = mapaprimo.size
tam = tam -1
while TRUE
if num % divide == 0
primo = FALSE
break
end
if cont <= tam
divide = mapaprimo[cont]
else
break
end
if (divide * divide) > num
break
end
cont = cont + 1
end
if primo
mapaprimo[xcont] = num
xcont = xcont + 1
end
num = num + 2
if num > limite
break
end
end
return mapaprimo
end
# ----------------------------------------------------------------------------
# gera um número aleatório até um dado limite
def geranum(limite)
num = rand(limite)
num = num % limite
tam = num.to_s.length
tam = tam -1
for cont in (1..tam)
muda = rand(10) % 10
num = (num + muda) % limite
xnum = num.to_s
xtam = xnum.length
xnum = xnum[1,xtam-1] + xnum[0,1]
num = xnum.to_i % limite
end
if num <= 2
num = num + 1
end
return num
end
# --------------------------------------------------------------------------------
# calcula o tempo de um processamento
def calctime(ini,fim)
n1 = (ini[0,2].to_i * 3600) + (ini[3,2].to_i * 60) + ini[6,2].to_i
n2 = (fim[0,2].to_i * 3600) + (fim[3,2].to_i * 60) + fim[6,2].to_i
result = n2 - n1
hora = minuto = segundo = 0
while TRUE
if result >= 3600
result = result - 3600
hora = hora + 1
else
break
end
end
while TRUE
if result >= 60
result = result - 60
minuto = minuto + 1
else
break
end
end
while TRUE
if result >= 1
result = result - 1
segundo = segundo + 1
else
break
end
end
vh = hora.to_s
if vh.length ==1
vh = "0" + vh
end
vm = minuto.to_s
if vm.length ==1
vm = "0" + vm
end
vs = segundo.to_s
if vs.length ==1
vs = "0" + vs
end
return vh + ":" + vm + ":" + vs
end
# --------------------------------------------------------------------------
# Esta a funcao pricipal que chama todas as outras...
# Com ele podemos gerar uma chave RSA de 1024, 2048, 4096 e até mesmo 8192 bits...
# o segundo parametro permite testar mais vezes o suposto primo encontrado
def gerachave(tam_chave,xverifica)
if xverifica < 1
xverifica == 1
elsif xverifica > 20
xverifica == 20
end
if tam_chave != 1024 && tam_chave != 2048 && tam_chave != 4096 && tam_chave != 8192
puts "Tamanho de chave inválido! Escolha um destes valores: 1024, 2048, 4096 ou 8192 bits."
exit
end
ini = hora()
puts "GERANDO UMA CHAVE PÚBLICA PARA O ALGORITMO RSA"
puts ""
puts "Aguarde, Preparando para os cálculos..: Chave de " + tam_chave.to_s + " bits."
vetprimo = mapaprimo()
arq = File.new("Chave-RSA.txt","w+")
chave = Array.new
vg = 0
posic = 0
while TRUE
while TRUE
falha = 0
# Gerenciando o tamanho da chave:
if tam_chave == 1024
tnum = "000" * 60 # primo 512 bits - gera chave de 1024
elsif tam_chave == 2048
tnum = "000" * 120 # primo 1024 bits - gera chave de 2048
elsif tam_chave == 4096
tnum = "000" * 240 # primo 2048 bits - gera chave de 4096
elsif tam_chave == 8192
tnum = "000" * 480 # primo 4096 bits - gera chave de 8192
else
puts "Tamanho de chave inválido! Escolha um destes valores: 1024, 2048, 4096 ou 8192 bits."
exit
end
tnum = "1" + tnum
limite = tnum.to_i
while TRUE
teste = geranum(limite)
if tam_chave == 1024
if teste.to_s.length >= 160 # Garante número Mínimo de dígitos
break
end
elsif tam_chave == 2048
if teste.to_s.length >= 320
break
end
elsif tam_chave == 4096
if teste.to_s.length >= 640
break
end
elsif tam_chave == 8192
if teste.to_s.length >= 1280
break
end
end
end
if teste % 2 == 0
teste = teste + 1
end
# verifica se o número é divisível por qualquer primo até 1.000.000
vetprimo.each do |valor|
if teste % valor == 0
falha = 1
break
end
end
if falha == 0
#hora()
puts teste
if rmiller(teste,1) != 0
puts hora() + " | É um forte candidato a ser primo!!!"
break
end
hora()
end
posic= posic + 1
if vg != 0
puts "Um número primo já foi encontrado e até agora " + posic.to_s + " foram analisados!"
end
end
k = 0
for cont in (1..xverifica)
if rmiller(teste,100) != 0
k = k + 1
else
break
end
end
if k == xverifica
puts teste.to_s + " é muito provavelmente um número primo!!!"
tmp = teste.to_s + "\n"
arq.write tmp
chave[vg] = teste
vg = vg + 1
end
if vg >= 2
break
end
end
# Gerando a chave Pública RSA:
chN = chave[0] * chave[1]
chR = (chave[0]-1) * (chave[1]-1)
chD = chE = 0
while TRUE
chE = geranum(chR)
if mdc(chE,chR) == 1 && chE < chR
break
end
end
chD = invmul(chE,chR) # Gerando a chave privada...
if (chD * chE) % chR != 1
puts "Erro no calculo do inverso multiplicativo"
exit
end
arq.write "\n"
arq.write "Chave Pública.: \n"
arq.write chE.to_s + "\n"
arq.write chN.to_s + "\n"
arq.write "\n"
arq.write "Chave Privada.: \n"
arq.write chD.to_s + "\n"
arq.write chN.to_s + "\n"
arq.close
puts "Tempo de Processamento: " + calctime(ini,hora())
puts "fim"
puts ""
puts "Testando a sua chave Pública..."
# Validacao da chave gerada:
limite = chN / 1000 # Limite do tamanho do texto para testar a chave...
for ct in (1..2)
texto = geranum(limite)
# codificando:
cripto = pot(texto,chE,chN)
# decodificando:
decod = pot(cripto,chD,chN)
if texto == decod
puts "Teste " + ct.to_s + ": Confere - OK"
else
puts "ERRO na decifragem - Gere outra Chave!!!"
break
end
end
puts ""
puts ""
puts "SUA CHAVE RSA DE " + tam_chave.to_s + " bits foi gerada com sucesso e está registrada no arquivo Chave-RSA.txt!!!"
end
# =====================================================================================================================
# EXEMPLO DE CHAMADA DA FUNÇÃO:
#gerachave(1024,5)
gerachave(2048,5)
#gerachave(4096,5)
#gerachave(8192,5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment