Criptografia com Python - Guia rápido

A criptografia é a arte da comunicação entre dois usuários por meio de mensagens codificadas. A ciência da criptografia surgiu com o motivo básico de fornecer segurança às mensagens confidenciais transferidas de uma parte para outra.

A criptografia é definida como a arte e a ciência de ocultar a mensagem para introduzir privacidade e sigilo, conforme reconhecido na segurança da informação.

Terminologias de criptografia

Os termos frequentemente usados ​​em criptografia são explicados aqui -

Texto simples

A mensagem de texto simples é o texto que pode ser lido e compreendido por todos os usuários. O texto simples é a mensagem que é criptografada.

Texto Cifrado

Texto cifrado é a mensagem obtida após a aplicação de criptografia em texto simples.

Encriptação

O processo de conversão de texto simples em texto cifrado é chamado de criptografia. Também é chamado de codificação.

Decifrar

O processo de conversão de texto cifrado em texto simples é chamado de descriptografia. Também é denominado como decodificação.

O diagrama abaixo mostra uma ilustração do processo completo de criptografia -

Características da criptografia moderna

As características básicas da criptografia moderna são as seguintes -

  • Ele opera em sequências de bits.

  • Ele usa algoritmos matemáticos para proteger as informações.

  • Requer as partes interessadas em um canal de comunicação seguro para obter privacidade.

A criptografia de dupla força, também chamada de criptografia múltipla, é o processo de criptografar um texto já criptografado uma ou mais vezes, com o mesmo algoritmo / padrão ou diferente.

Os outros nomes para criptografia de força dupla incluem criptografia em cascata ou criptografia em cascata.

Níveis de criptografia de dupla força

A criptografia de dupla força inclui vários níveis de criptografia que são explicados aqui em -

Primeira camada de criptografia

O texto cifrado é gerado a partir da mensagem legível original usando algoritmos hash e chaves simétricas. Posteriormente, as chaves simétricas são criptografadas com a ajuda de chaves assimétricas. A melhor ilustração para esse padrão é combinar o resumo hash do texto cifrado em uma cápsula. O receptor irá computar o resumo primeiro e depois descriptografar o texto para verificar se o texto não foi adulterado no meio.

Segunda camada de criptografia

A segunda camada de criptografia é o processo de adicionar mais uma camada ao texto cifrado com algoritmo igual ou diferente. Normalmente, uma senha simétrica de 32 bits com caracteres de comprimento é usada para o mesmo.

Terceira camada de criptografia

Neste processo, a cápsula criptografada é transmitida via conexão SSL / TLS para o parceiro de comunicação.

O diagrama a seguir mostra o processo de criptografia dupla pictoricamente -

Criptografia Híbrida

A criptografia híbrida é o processo de usar várias cifras de diferentes tipos em conjunto, incluindo os benefícios de cada uma das cifras. Há uma abordagem comum que geralmente é seguida para gerar uma chave secreta aleatória para uma cifra simétrica e, em seguida, criptografar essa chave por meio de criptografia de chave assimétrica.

Devido a esse padrão, a própria mensagem original é criptografada usando a cifra simétrica e, em seguida, usando a chave secreta. O destinatário, após receber a mensagem, a descriptografa usando primeiro a chave secreta, usando sua própria chave privada e, em seguida, usa a chave especificada para descriptografar a mensagem.

Python é uma linguagem de script de código aberto de alto nível, interpretada, interativa e orientada a objetos. Ele é projetado para ser altamente legível. A sintaxe da linguagem Python é fácil de entender e usa palavras-chave em inglês com frequência.

Recursos da linguagem Python

Python fornece os seguintes recursos principais -

Interpretado

Python é processado em tempo de execução usando o interpretador. Não há necessidade de compilar um programa antes da execução. É semelhante a PERL e PHP.

Orientado a Objeto

Python segue o estilo orientado a objetos e padrões de design. Inclui definição de classe com vários recursos como encapsulamento e polimorfismo.

Pontos principais da linguagem Python

Os pontos principais da linguagem de programação Python são os seguintes -

  • Inclui programação e métodos funcionais e estruturados, bem como métodos de programação orientada a objetos.

  • Pode ser usado como linguagem de script ou linguagem de programação.

  • Inclui coleta automática de lixo.

  • Inclui tipos de dados dinâmicos de alto nível e oferece suporte a várias verificações de tipo dinâmico.

  • Python inclui um recurso de integração com C, C ++ e linguagens como Java.

O link de download para a linguagem Python é o seguinte - www.python.org/downloads Inclui pacotes para vários sistemas operacionais como distribuições Windows, MacOS e Linux.

Python Strings

A declaração básica de strings é mostrada abaixo -

str = 'Hello World!'

Listas Python

As listas de python podem ser declaradas como tipos de dados compostos, separados por vírgulas e colocados entre colchetes ([]).

list = [ 'abcd', 786 , 2.23, 'john', 70.2 ]
tinylist = [123, 'john']

Python Tuples

Uma tupla é um tipo de dados dinâmico do Python, que consiste em vários valores separados por vírgulas. As tuplas estão entre parênteses.

tinytuple = (123, 'john')

Dicionário Python

O dicionário Python é um tipo de tabela hash. Uma chave de dicionário pode ser quase qualquer tipo de dados de Python, que geralmente são números ou strings.

tinydict = {'name': 'omkar','code':6734, 'dept': 'sales'}

Pacotes de criptografia

Python inclui um pacote chamado criptografia que fornece receitas criptográficas e primitivas. Suporta Python 2.7, Python 3.4+ e PyPy 5.3+. A instalação básica do pacote de criptografia é obtida através do seguinte comando -

pip install cryptography

Existem vários pacotes com receitas de alto nível e interfaces de baixo nível para algoritmos criptográficos comuns, como symmetric ciphers, message digests e key derivation functions.

Ao longo deste tutorial, estaremos usando vários pacotes de Python para implementação de algoritmos criptográficos.

O capítulo anterior deu a você uma visão geral da instalação do Python em seu computador local. Neste capítulo, você aprenderá em detalhes sobre a cifra reversa e sua codificação.

Algoritmo de Cifra Reversa

O algoritmo de cifra reversa possui os seguintes recursos -

  • Cifra reversa usa um padrão de reversão da string de texto simples para converter como texto cifrado.

  • O processo de criptografia e descriptografia é o mesmo.

  • Para descriptografar o texto cifrado, o usuário simplesmente precisa reverter o texto cifrado para obter o texto simples.

Recua

A principal desvantagem da cifra reversa é que ela é muito fraca. Um hacker pode quebrar facilmente o texto cifrado para obter a mensagem original. Portanto, a cifra reversa não é considerada uma boa opção para manter um canal de comunicação seguro.

Exemplo

Considere um exemplo em que a declaração This is program to explain reverse cipherdeve ser implementado com algoritmo de cifra reversa. O código Python a seguir usa o algoritmo para obter a saída.

message = 'This is program to explain reverse cipher.'
translated = '' #cipher text is stored in this variable
i = len(message) - 1

while i >= 0:
   translated = translated + message[i]
   i = i - 1
print(“The cipher text is : “, translated)

Resultado

Você pode ver o texto invertido, que é a saída, conforme mostrado na imagem a seguir -

Explicação

  • O texto simples é armazenado na mensagem variável e a variável traduzida é usada para armazenar o texto cifrado criado.

  • O comprimento do texto simples é calculado usando for loop e com a ajuda de index number. Os caracteres são armazenados na variável de texto cifradotranslated que é impresso na última linha.

No último capítulo, lidamos com a cifra reversa. Este capítulo fala sobre a cifra de César em detalhes.

Algoritmo da Cifra de César

O algoritmo da cifra de César possui os seguintes recursos -

  • Caesar Cipher Technique é o método simples e fácil de técnica de criptografia.

  • É um tipo simples de cifra de substituição.

  • Cada letra do texto simples é substituída por uma letra com um número fixo de posições abaixo do alfabeto.

O diagrama a seguir descreve o funcionamento da implementação do algoritmo de cifra de César -

A implementação do programa de algoritmo de cifra de César é a seguinte -

def encrypt(text,s):
result = ""
   # transverse the plain text
   for i in range(len(text)):
      char = text[i]
      # Encrypt uppercase characters in plain text
      
      if (char.isupper()):
         result += chr((ord(char) + s-65) % 26 + 65)
      # Encrypt lowercase characters in plain text
      else:
         result += chr((ord(char) + s - 97) % 26 + 97)
      return result
#check the above function
text = "CEASER CIPHER DEMO"
s = 4

print "Plain Text : " + text
print "Shift pattern : " + str(s)
print "Cipher: " + encrypt(text,s)

Resultado

Você pode ver a cifra de César, que é a saída conforme mostrado na imagem a seguir -

Explicação

O caractere de texto simples é percorrido um de cada vez.

  • Para cada caractere no texto simples fornecido, transforme o caractere fornecido de acordo com a regra dependendo do procedimento de criptografia e descriptografia do texto.

  • Após as etapas serem seguidas, uma nova string é gerada, chamada de texto cifrado.

Hacking of Caesar Cipher Algorithm

O texto cifrado pode ser hackeado com várias possibilidades. Uma dessas possibilidades éBrute Force Technique,que envolve tentar todas as chaves de descriptografia possíveis. Essa técnica não exige muito esforço e é relativamente simples para um hacker.

A implementação do programa para hackear o algoritmo de cifra Caesar é a seguinte -

message = 'GIEWIVrGMTLIVrHIQS' #encrypted message
LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

for key in range(len(LETTERS)):
   translated = ''
   for symbol in message:
      if symbol in LETTERS:
         num = LETTERS.find(symbol)
         num = num - key
         if num < 0:
            num = num + len(LETTERS)
         translated = translated + LETTERS[num]
      else:
         translated = translated + symbol
print('Hacking key #%s: %s' % (key, translated))

Considere o texto cifrado criptografado no exemplo anterior. Então, a saída com possíveis métodos de hacking com a chave e usando a técnica de ataque de força bruta é a seguinte -

Até agora, você aprendeu sobre cifra reversa e algoritmos de cifra de César. Agora, vamos discutir o algoritmo ROT13 e sua implementação.

Explicação do Algoritmo ROT13

A cifra ROT13 refere-se à forma abreviada Rotate by 13 places. É um caso especial de Cifra de César em que o deslocamento é sempre 13. Cada letra é deslocada em 13 lugares para criptografar ou descriptografar a mensagem.

Exemplo

O diagrama a seguir explica o processo do algoritmo ROT13 pictoricamente -

Código do Programa

A implementação do programa do algoritmo ROT13 é a seguinte -

from string import maketrans

rot13trans = maketrans('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 
   'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm')

# Function to translate plain text
def rot13(text):
   return text.translate(rot13trans)
def main():
   txt = "ROT13 Algorithm"
   print rot13(txt)
	
if __name__ == "__main__":
   main()

Você pode ver a saída ROT13 conforme mostrado na imagem a seguir -

Recua

O algoritmo ROT13 usa 13 turnos. Portanto, é muito fácil deslocar os caracteres no sentido inverso para descriptografar o texto cifrado.

Análise do Algoritmo ROT13

O algoritmo de cifra ROT13 é considerado um caso especial de Cifra de César. Não é um algoritmo muito seguro e pode ser quebrado facilmente com a análise de frequência ou apenas tentando 25 chaves possíveis, enquanto o ROT13 pode ser quebrado mudando 13 lugares. Portanto, não inclui nenhum uso prático.

Cifra de transposição é um algoritmo criptográfico em que a ordem dos alfabetos no texto simples é reorganizada para formar um texto cifrado. Nesse processo, os alfabetos de texto simples reais não são incluídos.

Exemplo

Um exemplo simples de cifra de transposição é columnar transposition cipheronde cada caractere no texto simples é escrito horizontalmente com a largura do alfabeto especificada. A cifra é escrita verticalmente, o que cria um texto cifrado totalmente diferente.

Considere o texto simples hello world, e vamos aplicar a técnica de transposição colunar simples, conforme mostrado abaixo

Os caracteres de texto simples são colocados horizontalmente e o texto cifrado é criado com formato vertical como : holewdlo lr. Agora, o receptor precisa usar a mesma tabela para descriptografar o texto cifrado em texto simples.

Código

O código do programa a seguir demonstra a implementação básica da técnica de transposição colunar -

def split_len(seq, length):
   return [seq[i:i + length] for i in range(0, len(seq), length)]
def encode(key, plaintext):
   order = {
      int(val): num for num, val in enumerate(key)
   }
ciphertext = ''

for index in sorted(order.keys()):
   for part in split_len(plaintext, len(key)):
      try:ciphertext += part[order[index]]
         except IndexError:
            continue
   return ciphertext
print(encode('3214', 'HELLO'))

Explicação

  • Usando a função split_len(), podemos dividir os caracteres de texto simples, que podem ser colocados em formato de coluna ou linha.

  • encode O método ajuda a criar texto cifrado com chave especificando o número de colunas e imprime o texto cifrado lendo os caracteres em cada coluna.

Resultado

O código do programa para a implementação básica da técnica de transposição colunar fornece a seguinte saída -

Note- Os criptanalistas observaram uma melhora significativa na segurança da criptografia quando a técnica de transposição é realizada. Eles também observaram que criptografar novamente o texto cifrado usando a mesma cifra de transposição cria melhor segurança.

No capítulo anterior, aprendemos sobre a Cifra de Transposição. Neste capítulo, vamos discutir sua criptografia.

Pyperclip

O principal uso de pyperclipplugin na linguagem de programação Python é executar módulo de plataforma cruzada para copiar e colar texto para a área de transferência. Você pode instalar o pythonpyperclip módulo usando o comando como mostrado

pip install pyperclip

Se o requisito já existe no sistema, você pode ver a seguinte saída -

Código

O código python para criptografar cifra de transposição em que pyperclip é o módulo principal é mostrado abaixo -

import pyperclip
def main():
   myMessage = 'Transposition Cipher'
   myKey = 10
   ciphertext = encryptMessage(myKey, myMessage)
   
   print("Cipher Text is")
   print(ciphertext + '|')
   pyperclip.copy(ciphertext)

def encryptMessage(key, message):
   ciphertext = [''] * key
   
   for col in range(key):
      position = col
      while position < len(message):
         ciphertext[col] += message[position]
			position += key
      return ''.join(ciphertext) #Cipher text
if __name__ == '__main__':
   main()

Resultado

O código do programa para criptografar a cifra de transposição em que pyperclip é o módulo principal dá a seguinte saída -

Explicação

  • A função main() chama o encryptMessage() que inclui o procedimento para dividir os personagens usando len função e iterando-os em um formato colunar.

  • A função principal é inicializada no final para obter a saída apropriada.

Neste capítulo, você aprenderá o procedimento para descriptografar a cifra de transposição.

Código

Observe o código a seguir para uma melhor compreensão da descriptografia de uma cifra de transposição. O texto cifrado da mensagemTransposition Cipher com chave como 6 é obtido como Toners raiCntisippoh.

import math, pyperclip
def main():
   myMessage= 'Toners raiCntisippoh'
   myKey = 6
   plaintext = decryptMessage(myKey, myMessage)
   
   print("The plain text is")
   print('Transposition Cipher')

def decryptMessage(key, message):
   numOfColumns = math.ceil(len(message) / key)
   numOfRows = key
   numOfShadedBoxes = (numOfColumns * numOfRows) - len(message)
   plaintext = float('') * numOfColumns
   col = 0
   row = 0
   
   for symbol in message:
      plaintext[col] += symbol
      col += 1
      if (col == numOfColumns) or (col == numOfColumns - 1 and row >= numOfRows - numOfShadedBoxes):
         col = 0 row += 1 return ''.join(plaintext)
if __name__ == '__main__':
   main()

Explicação

O texto cifrado e a chave mencionada são os dois valores tomados como parâmetros de entrada para decodificar ou descriptografar o texto cifrado na técnica reversa, colocando os caracteres em formato de coluna e lendo-os na horizontal.

Você pode colocar letras em um formato de coluna e depois combiná-las ou concatená-las usando o seguinte código -

for symbol in message:
   plaintext[col] += symbol
   col += 1
   
   if (col == numOfColumns) or (col == numOfColumns - 1 and row >= numOfRows - numOfShadedBoxes):
   col = 0
   row += 1
return ''.join(plaintext)

Resultado

O código do programa para descriptografar a cifra de transposição fornece a seguinte saída -

Em Python, é possível criptografar e descriptografar arquivos antes de transmitir para um canal de comunicação. Para isso, você terá que usar o pluginPyCrypto. Você pode instalar este plugin usando o comando fornecido abaixo.

pip install pycrypto

Código

O código do programa para criptografar o arquivo com o protetor de senha é mencionado abaixo -

# =================Other Configuration================
# Usages :
usage = "usage: %prog [options] "
# Version
Version="%prog 0.0.1"
# ====================================================
# Import Modules
import optparse, sys,os
from toolkit import processor as ps
def main():
   parser = optparse.OptionParser(usage = usage,version = Version)
   parser.add_option(
      '-i','--input',type = 'string',dest = 'inputfile',
      help = "File Input Path For Encryption", default = None)
   
   parser.add_option(
      '-o','--output',type = "string",dest = 'outputfile',
      help = "File Output Path For Saving Encrypter Cipher",default = ".")
	
   parser.add_option(
      '-p','--password',type = "string",dest = 'password',
      help = "Provide Password For Encrypting File",default = None)
	
   parser.add_option(
      '-p','--password',type = "string",dest = 'password',
      help = "Provide Password For Encrypting File",default = None)
	
   (options, args)= parser.parse_args()
	
   # Input Conditions Checkings
   if not options.inputfile or not os.path.isfile(options.inputfile):
      print " [Error] Please Specify Input File Path"
      exit(0)
   if not options.outputfile or not os.path.isdir(options.outputfile):
      print " [Error] Please Specify Output Path"
      exit(0)
   if not options.password:
      print " [Error] No Password Input"
      exit(0)
   inputfile = options.inputfile

   outputfile = os.path.join(
      options.outputfile,os.path.basename(options.inputfile).split('.')[0]+'.ssb')
   password = options.password
   base = os.path.basename(inputfile).split('.')[1]
   work = "E"

   ps.FileCipher(inputfile,outputfile,password,work)
   return

   if __name__ == '__main__':
   main()

Você pode usar o seguinte comando para executar o processo de criptografia junto com a senha -

python pyfilecipher-encrypt.py -i file_path_for_encryption -o output_path -p password

Resultado

Você pode observar a seguinte saída ao executar o código fornecido acima -

Explicação

As senhas são geradas usando o algoritmo de hash MD5 e os valores são armazenados em arquivos de backup simplesmente seguros no sistema Windows, que inclui os valores exibidos abaixo -

Neste capítulo, vamos discutir a descriptografia de arquivos em criptografia usando Python. Observe que para o processo de descriptografia, seguiremos o mesmo procedimento, mas em vez de especificar o caminho de saída, vamos nos concentrar no caminho de entrada ou no arquivo necessário que está criptografado.

Código

A seguir está um código de amostra para descriptografar arquivos em criptografia usando Python -

#!/usr/bin/python
# ---------------- READ ME ---------------------------------------------
# This Script is Created Only For Practise And Educational Purpose Only
# This Script Is Created For http://bitforestinfo.blogspot.in
# This Script is Written By
#
#
##################################################
######## Please Don't Remove Author Name #########
############### Thanks ###########################
##################################################
#
#
# =================Other Configuration================
# Usages :
usage = "usage: %prog [options] "
# Version
Version="%prog 0.0.1"
# ====================================================
# Import Modules
import optparse, sys,os
from toolkit import processor as ps
def main():
   parser = optparse.OptionParser(usage = usage,version = Version)
   parser.add_option(
      '-i','--input',type = 'string',dest = 'inputfile',
      help = "File Input Path For Encryption", default = None)
   
   parser.add_option(
      '-o','--output',type = "string",dest = 'outputfile',
      help = "File Output Path For Saving Encrypter Cipher",default = ".")
   
   parser.add_option(
      '-p','--password',type = "string",dest = 'password',
      help = "Provide Password For Encrypting File",default = None)
      (options, args) =  parser.parse_args()
      # Input Conditions Checkings
      if not options.inputfile or not os.path.isfile(options.inputfile):
         print " [Error] Please Specify Input File Path"
         exit(0)
      if not options.outputfile or not os.path.isdir(options.outputfile):
         print " [Error] Please Specify Output Path"
         exit(0)
      if not options.password:
         print " [Error] No
         exit(0)
      inputfile = options.inputfile
      outputfile = options.outputfile
      password = options.password
      work = "D"
      ps.FileCipher(inputfile,outputfile,password,work)
      return
if __name__ == '__main__':
   main()

Você pode usar o seguinte comando para executar o código acima -

python pyfilecipher-decrypt.py -i encrypted_file_path -p password

Resultado

Você pode observar o código a seguir ao executar o comando mostrado acima -

Note - A saída especifica os valores de hash antes da criptografia e após a descriptografia, o que mantém uma nota de que o mesmo arquivo está criptografado e o processo foi bem-sucedido.

A codificação Base64 converte os dados binários em formato de texto, que é passado pelo canal de comunicação onde um usuário pode manipular o texto com segurança. Base64 também é chamado dePrivacy enhanced Electronic mail (PEM) e é usado principalmente no processo de criptografia de e-mail.

Python inclui um módulo chamado BASE64 que inclui duas funções principais, conforme fornecido abaixo -

  • base64.decode(input, output) - Ele decodifica o parâmetro de valor de entrada especificado e armazena a saída decodificada como um objeto.

  • Base64.encode(input, output) - Codifica o parâmetro de valor de entrada especificado e armazena a saída decodificada como um objeto.

Programa para codificação

Você pode usar o seguinte trecho de código para realizar a codificação base64 -

import base64
encoded_data = base64.b64encode("Encode this text")

print("Encoded text with base 64 is")
print(encoded_data)

Resultado

O código para codificação base64 oferece a seguinte saída -

Programa para decodificação

Você pode usar o seguinte trecho de código para realizar a decodificação base64 -

import base64
decoded_data = base64.b64decode("RW5jb2RlIHRoaXMgdGV4dA==")

print("decoded text is ")
print(decoded_data)

Resultado

O código para decodificação base64 oferece a seguinte saída -

Diferença entre ASCII e base64

Você pode observar as seguintes diferenças ao trabalhar em ASCII e base64 para codificação de dados -

  • Ao codificar texto em ASCII, você começa com uma string de texto e a converte em uma sequência de bytes.

  • Ao codificar dados em Base64, você começa com uma sequência de bytes e a converte em uma string de texto.

Recua

O algoritmo Base64 é geralmente usado para armazenar senhas no banco de dados. A principal desvantagem é que cada palavra decodificada pode ser codificada facilmente por meio de qualquer ferramenta online e os invasores podem obter as informações facilmente.

Neste capítulo, vamos entender o processo XOR junto com sua codificação em Python.

Algoritmo

O algoritmo XOR de criptografia e descriptografia converte o texto simples no formato ASCII bytes e usa o procedimento XOR para convertê-lo em um byte especificado. Ele oferece as seguintes vantagens aos seus usuários -

  • Computação rápida
  • Nenhuma diferença marcada no lado esquerdo e direito
  • Fácil de entender e analisar

Código

Você pode usar o seguinte trecho de código para realizar o processo XOR -

def xor_crypt_string(data, key = 'awesomepassword', encode = False, decode = False):
   from itertools import izip, cycle
   import base64
   
   if decode:
      data = base64.decodestring(data)
   xored = ''.join(chr(ord(x) ^ ord(y)) for (x,y) in izip(data, cycle(key)))
   
   if encode:
      return base64.encodestring(xored).strip()
   return xored
secret_data = "XOR procedure"

print("The cipher text is")
print xor_crypt_string(secret_data, encode = True)
print("The plain text fetched")
print xor_crypt_string(xor_crypt_string(secret_data, encode = True), decode = True)

Resultado

O código para o processo XOR fornece a seguinte saída -

Explicação

  • A função xor_crypt_string() inclui um parâmetro para especificar o modo de codificação e decodificação e também o valor da string.

  • As funções básicas são obtidas com módulos base64 que seguem o procedimento / operação XOR para criptografar ou descriptografar o texto simples / texto cifrado.

Note - A criptografia XOR é usada para criptografar dados e é difícil de quebrar pelo método de força bruta, isto é, gerando chaves de criptografia aleatórias para combinar com o texto cifrado correto.

Ao usar a técnica da cifra de César, criptografar e descriptografar símbolos envolve a conversão dos valores em números com um procedimento básico simples de adição ou subtração.

Se a multiplicação for usada para converter em texto cifrado, ela é chamada de wrap-aroundsituação. Considere as letras e os números associados a serem usados ​​conforme mostrado abaixo -

Os números serão usados ​​para o procedimento de multiplicação e a chave associada é 7. A fórmula básica a ser usada em tal cenário para gerar uma cifra multiplicativa é a seguinte -

(Alphabet Number * key)mod(total number of alphabets)

O número obtido por meio da saída é mapeado na tabela mencionada acima e a letra correspondente é considerada a letra criptografada.

A função de modulação básica de uma cifra multiplicativa em Python é a seguinte -

def unshift(key, ch):
   offset = ord(ch) - ASC_A
   return chr(((key[0] * (offset + key[1])) % WIDTH) + ASC_A)

Note- A vantagem de uma cifra multiplicativa é que ela pode funcionar com chaves muito grandes, como 8.953.851. Levaria muito tempo para que um computador utilizasse a força bruta de uma maioria de nove milhões de chaves.

Affine Cipher é a combinação do algoritmo Multiplicative Cipher e Caesar Cipher. A implementação básica da cifra afim é mostrada na imagem abaixo -

Neste capítulo, implementaremos a cifra afim criando sua classe correspondente que inclui duas funções básicas para criptografia e descriptografia.

Código

Você pode usar o seguinte código para implementar uma cifra afim -

class Affine(object):
   DIE = 128
   KEY = (7, 3, 55)
   def __init__(self):
      pass
   def encryptChar(self, char):
      K1, K2, kI = self.KEY
      return chr((K1 * ord(char) + K2) % self.DIE)
		
   def encrypt(self, string):
      return "".join(map(self.encryptChar, string))
   
   def decryptChar(self, char):
      K1, K2, KI = self.KEY
      return chr(KI * (ord(char) - K2) % self.DIE)
   
   def decrypt(self, string):
      return "".join(map(self.decryptChar, string))
		affine = Affine()
print affine.encrypt('Affine Cipher')
print affine.decrypt('*18?FMT')

Resultado

Você pode observar a seguinte saída ao implementar uma cifra afim -

A saída exibe a mensagem criptografada para a mensagem de texto simples Affine Cipher e a mensagem descriptografada para a mensagem enviada como entrada abcdefg.

Neste capítulo, você aprenderá sobre cifras monoalfabéticas e seu hackeamento usando Python.

Cifra Monoalfabética

Uma cifra monoalfabética usa uma substituição fixa para criptografar a mensagem inteira. Uma cifra monoalfabética usando um dicionário Python com objetos JSON é mostrada aqui -

monoalpha_cipher = {
   'a': 'm',
   'b': 'n',
   'c': 'b',
   'd': 'v',
   'e': 'c',
   'f': 'x',
   'g': 'z',
   'h': 'a',
   'i': 's',
   'j': 'd',
   'k': 'f',
   'l': 'g',
   'm': 'h',
   'n': 'j',
   'o': 'k',
   'p': 'l',
   'q': 'p',
   'r': 'o',
   's': 'i',
   't': 'u',
   'u': 'y',
   'v': 't',
   'w': 'r',
   'x': 'e',
   'y': 'w',
   'z': 'q',
	' ': ' ',
}

Com a ajuda deste dicionário, podemos criptografar as letras com as letras associadas como valores no objeto JSON. O programa a seguir cria um programa monoalfabético como uma representação de classe que inclui todas as funções de criptografia e descriptografia.

from string import letters, digits
from random import shuffle

def random_monoalpha_cipher(pool = None):
   if pool is None:
      pool = letters + digits
   original_pool = list(pool)
   shuffled_pool = list(pool)
   shuffle(shuffled_pool)
   return dict(zip(original_pool, shuffled_pool))

def inverse_monoalpha_cipher(monoalpha_cipher):
   inverse_monoalpha = {}
   for key, value in monoalpha_cipher.iteritems():
      inverse_monoalpha[value] = key
   return inverse_monoalpha

def encrypt_with_monoalpha(message, monoalpha_cipher):
   encrypted_message = []
   for letter in message:
      encrypted_message.append(monoalpha_cipher.get(letter, letter))
   return ''.join(encrypted_message)

def decrypt_with_monoalpha(encrypted_message, monoalpha_cipher):
   return encrypt_with_monoalpha(
      encrypted_message,
      inverse_monoalpha_cipher(monoalpha_cipher)
   )

Este arquivo é chamado posteriormente para implementar o processo de criptografia e descriptografia da cifra monoalfabética, mencionada a seguir -

import monoalphabeticCipher as mc

cipher = mc.random_monoalpha_cipher()
print(cipher)
encrypted = mc.encrypt_with_monoalpha('Hello all you hackers out there!', cipher)
decrypted = mc.decrypt_with_monoalpha('sXGGt SGG Nt0 HSrLXFC t0U UHXFX!', cipher)

print(encrypted)
print(decrypted)

Resultado

Você pode observar a seguinte saída ao implementar o código fornecido acima -

Assim, você pode hackear uma cifra monoalfabética com um par de valores-chave especificado que converte o texto cifrado em texto simples real.

A cifra de substituição simples é a cifra mais comumente usada e inclui um algoritmo de substituição de cada caractere de texto simples para cada caractere de texto cifrado. Nesse processo, os alfabetos são misturados em comparação com o algoritmo de cifra de César.

Exemplo

As chaves para uma cifra de substituição simples geralmente consistem em 26 letras. Um exemplo de chave é -

plain alphabet : abcdefghijklmnopqrstuvwxyz
cipher alphabet: phqgiumeaylnofdxjkrcvstzwb

Um exemplo de criptografia usando a chave acima é -

plaintext : defend the east wall of the castle
ciphertext: giuifg cei iprc tpnn du cei qprcni

O código a seguir mostra um programa para implementar a cifra de substituição simples -

import random, sys

LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
def main():
   message = ''
   if len(sys.argv) > 1:
      with open(sys.argv[1], 'r') as f:
         message = f.read()
   else:
      message = raw_input("Enter your message: ")
   mode = raw_input("E for Encrypt, D for Decrypt: ")
   key = ''
   
   while checkKey(key) is False:
      key = raw_input("Enter 26 ALPHA key (leave blank for random key): ")
      if key == '':
         key = getRandomKey()
      if checkKey(key) is False:
		print('There is an error in the key or symbol set.')
   translated = translateMessage(message, key, mode)
   print('Using key: %s' % (key))
   
   if len(sys.argv) > 1:
      fileOut = 'enc.' + sys.argv[1]
      with open(fileOut, 'w') as f:
         f.write(translated)
      print('Success! File written to: %s' % (fileOut))
   else: print('Result: ' + translated)

# Store the key into list, sort it, convert back, compare to alphabet.
def checkKey(key):
   keyString = ''.join(sorted(list(key)))
   return keyString == LETTERS
def translateMessage(message, key, mode):
   translated = ''
   charsA = LETTERS
   charsB = key
   
   # If decrypt mode is detected, swap A and B
   if mode == 'D':
      charsA, charsB = charsB, charsA
   for symbol in message:
      if symbol.upper() in charsA:
         symIndex = charsA.find(symbol.upper())
         if symbol.isupper():
            translated += charsB[symIndex].upper()
         else:
            translated += charsB[symIndex].lower()
				else:
               translated += symbol
         return translated
def getRandomKey():
   randomList = list(LETTERS)
   random.shuffle(randomList)
   return ''.join(randomList)
if __name__ == '__main__':
   main()

Resultado

Você pode observar a seguinte saída ao implementar o código fornecido acima -

Neste capítulo, vamos nos concentrar em testar a cifra de substituição usando vários métodos, o que ajuda a gerar strings aleatórias conforme fornecido abaixo -

import random, string, substitution
def main():
   for i in range(1000):
      key = substitution.getRandomKey()
      message = random_string()
      print('Test %s: String: "%s.."' % (i + 1, message[:50]))
      print("Key: " + key)
      encrypted = substitution.translateMessage(message, key, 'E')
      decrypted = substitution.translateMessage(encrypted, key, 'D')
      
      if decrypted != message:
         print('ERROR: Decrypted: "%s" Key: %s' % (decrypted, key))
         sys.exit()
      print('Substutition test passed!')

def random_string(size = 5000, chars = string.ascii_letters + string.digits):
   return ''.join(random.choice(chars) for _ in range(size))
if __name__ == '__main__':
   main()

Resultado

Você pode observar a saída como strings geradas aleatoriamente, o que ajuda a gerar mensagens de texto simples aleatórias, conforme mostrado abaixo -

Depois que o teste for concluído com sucesso, podemos observar a mensagem de saída Substitution test passed!.

Assim, você pode hackear uma cifra de substituição de maneira sistemática.

Neste capítulo, você pode aprender sobre a implementação simples da cifra de substituição que exibe a mensagem criptografada e descriptografada de acordo com a lógica usada na técnica de cifra de substituição simples. Isso pode ser considerado uma abordagem alternativa de codificação.

Código

Você pode usar o seguinte código para realizar a descriptografia usando cifra de substituição simples -

import random
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + \
   'abcdefghijklmnopqrstuvwxyz' + \
   '0123456789' + \
   ':.;,?!@#$%&()+=-*/_<> []{}`~^"\'\\'

def generate_key():
   """Generate an key for our cipher"""
   shuffled = sorted(chars, key=lambda k: random.random())
   return dict(zip(chars, shuffled))

def encrypt(key, plaintext):
   """Encrypt the string and return the ciphertext"""
   return ''.join(key[l] for l in plaintext)

def decrypt(key, ciphertext):
   """Decrypt the string and return the plaintext"""
   flipped = {v: k for k, v in key.items()}
   return ''.join(flipped[l] for l in ciphertext)

def show_result(plaintext):
   """Generate a resulting cipher with elements shown"""
   key = generate_key()
   encrypted = encrypt(key, plaintext)
   decrypted = decrypt(key, encrypted)
   
   print 'Key: %s' % key
	print 'Plaintext: %s' % plaintext
   print 'Encrypted: %s' % encrypted
   print 'Decrypted: %s' % decrypted
show_result('Hello World. This is demo of substitution cipher')

Resultado

O código acima fornece a saída conforme mostrado aqui -

Neste capítulo, você aprenderá em detalhes sobre vários módulos de criptografia em Python.

Módulo de Criptografia

Inclui todas as receitas e primitivas e fornece uma interface de alto nível de codificação em Python. Você pode instalar o módulo de criptografia usando o seguinte comando -

pip install cryptography

Código

Você pode usar o seguinte código para implementar o módulo de criptografia -

from cryptography.fernet import Fernet
key = Fernet.generate_key()
cipher_suite = Fernet(key)
cipher_text = cipher_suite.encrypt("This example is used to demonstrate cryptography module")
plain_text = cipher_suite.decrypt(cipher_text)

Resultado

O código fornecido acima produz a seguinte saída -

O código fornecido aqui é usado para verificar a senha e criar seu hash. Ele também inclui lógica para verificar a senha para fins de autenticação.

import uuid
import hashlib

def hash_password(password):
   # uuid is used to generate a random number of the specified password
   salt = uuid.uuid4().hex
   return hashlib.sha256(salt.encode() + password.encode()).hexdigest() + ':' + salt

def check_password(hashed_password, user_password):
   password, salt = hashed_password.split(':')
   return password == hashlib.sha256(salt.encode() + user_password.encode()).hexdigest()

new_pass = input('Please enter a password: ')
hashed_password = hash_password(new_pass)
print('The string to store in the db is: ' + hashed_password)
old_pass = input('Now please enter the password again to check: ')

if check_password(hashed_password, old_pass):
   print('You entered the right password')
else:
   print('Passwords do not match')

Resultado

Scenario 1 - Se você digitou uma senha correta, você pode encontrar a seguinte saída -

Scenario 2 - Se inserirmos a senha errada, você poderá encontrar a seguinte saída -

Explicação

Hashlibpacote é usado para armazenar senhas em um banco de dados. Neste programa,salt é usado, o que adiciona uma sequência aleatória à string da senha antes de implementar a função hash.

Vignere Cipher inclui uma variação do algoritmo Caesar Cipher usado para criptografia e descriptografia. Vignere Cipher funciona de maneira semelhante ao algoritmo Caesar Cipher com apenas uma distinção importante: Caesar Cipher inclui algoritmo para deslocamento de um caractere, enquanto Vignere Cipher inclui chave com deslocamento de vários alfabetos.

Equação Matemática

Para criptografia, a equação matemática é a seguinte -

$$ E_ {k} \ left (M {_ {i {}}} \ right) = \ left (M_ {i} + K_ {i} \ right) \; \; \; mod \; \; 26 $$

Para a descriptografia, a equação matemática é a seguinte -

$$ D_ {k} \ left (C {_ {i {}}} \ right) = \ left (C_ {i} -K_ {i} \ right) \; \; \; mod \; \; 26 $$

A cifra de Vignere usa mais de um conjunto de substituições e, portanto, também é conhecida como polyalphabetic cipher. O Vignere Cipher usará uma chave de letra em vez de uma representação de chave numérica: a letra A será usada para a chave 0, a letra B para a chave 1 e assim por diante. O número das letras antes e depois do processo de criptografia é mostrado abaixo -

A possível combinação do número de chaves possíveis com base no comprimento da chave Vignere é fornecida como segue, o que dá o resultado de quão seguro é o Algoritmo de Cifra de Vignere -

Tableau Vignere

O quadro usado para a cifra de Vignere é mostrado abaixo -

Neste capítulo, vamos entender como implementar a cifra de Vignere. Considere o textoThis is basic implementation of Vignere Cipher deve ser codificado e a chave usada é PIZZA.

Código

Você pode usar o seguinte código para implementar uma cifra Vignere em Python -

import pyperclip

LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
def main():
   myMessage = "This is basic implementation of Vignere Cipher"
   myKey = 'PIZZA'
   myMode = 'encrypt'
   
   if myMode == 'encrypt':
      translated = encryptMessage(myKey, myMessage)
   elif myMode == 'decrypt':
      translated = decryptMessage(myKey, myMessage)
   
   print('%sed message:' % (myMode.title()))
   print(translated)
   print()
def encryptMessage(key, message):
   return translateMessage(key, message, 'encrypt')
def decryptMessage(key, message):
   return translateMessage(key, message, 'decrypt')
def translateMessage(key, message, mode):
   translated = [] # stores the encrypted/decrypted message string
   keyIndex = 0
   key = key.upper()
   
   for symbol in message:
      num = LETTERS.find(symbol.upper())
      if num != -1:
         if mode == 'encrypt':
            num += LETTERS.find(key[keyIndex])
				elif mode == 'decrypt':
               num -= LETTERS.find(key[keyIndex])
            num %= len(LETTERS)
            
            if symbol.isupper():
               translated.append(LETTERS[num])
            elif symbol.islower():
               translated.append(LETTERS[num].lower())
            keyIndex += 1
            
            if keyIndex == len(key):
               keyIndex = 0
         else:
            translated.append(symbol)
      return ''.join(translated)
if __name__ == '__main__':
   main()

Resultado

Você pode observar a seguinte saída ao implementar o código fornecido acima -

As combinações possíveis de hackear a cifra de Vignere são quase impossíveis. Portanto, é considerado um modo de criptografia seguro.

A cifra de teclado único é um tipo de cifra de Vignere que inclui os seguintes recursos -

  • É uma cifra inquebrável.

  • A chave é exatamente igual ao comprimento da mensagem criptografada.

  • A chave é composta de símbolos aleatórios.

  • Como o nome sugere, a chave é usada apenas uma vez e nunca mais usada para qualquer outra mensagem a ser criptografada.

Devido a isso, a mensagem criptografada ficará vulnerável a ataques por um criptanalista. A chave usada para uma cifra de teclado única é chamadapad, pois é impresso em blocos de papel.

Por que é inquebrável?

A chave é inquebrável devido aos seguintes recursos -

  • A chave é tão longa quanto a mensagem fornecida.

  • A chave é verdadeiramente aleatória e especialmente gerada automaticamente.

  • Texto chave e simples calculado como módulo 10/26/2.

  • Cada chave deve ser usada uma vez e destruída pelo remetente e pelo destinatário.

  • Deve haver duas cópias da chave: uma com o remetente e outra com o destinatário.

Encriptação

Para criptografar uma carta, o usuário precisa escrever uma chave abaixo do texto simples. A letra do texto simples é colocada na parte superior e a letra da chave à esquerda. A seção transversal obtida entre duas letras é o texto simples. É descrito no exemplo abaixo -

Decifrar

Para descriptografar uma letra, o usuário pega a letra da chave à esquerda e encontra a letra do texto cifrado nessa linha. A letra do texto simples é colocada no topo da coluna onde o usuário pode encontrar a letra do texto cifrado.

Python inclui um módulo de implementação de hacky para one-time-padimplementação de cifra. O nome do pacote é denominado One-Time-Pad, que inclui uma ferramenta de criptografia de linha de comando que usa um mecanismo de criptografia semelhante ao algoritmo de criptografia one-time pad.

Instalação

Você pode usar o seguinte comando para instalar este módulo -

pip install onetimepad

Se você deseja usá-lo na linha de comando, execute o seguinte comando -

onetimepad

Código

O código a seguir ajuda a gerar uma cifra de preenchimento única -

import onetimepad

cipher = onetimepad.encrypt('One Time Cipher', 'random')
print("Cipher text is ")
print(cipher)
print("Plain text is ")
msg = onetimepad.decrypt(cipher, 'random')

print(msg)

Resultado

Você pode observar a seguinte saída ao executar o código fornecido acima -

Note - A mensagem criptografada é muito fácil de quebrar se o comprimento da chave for menor que o comprimento da mensagem (texto simples).

Em qualquer caso, a chave não é necessariamente aleatória, o que torna a criptografia única uma ferramenta válida.

Neste capítulo, vamos discutir em detalhes sobre criptografia simétrica e assimétrica.

Criptografia Simétrica

Nesse tipo, o processo de criptografia e descriptografia usa a mesma chave. Também é chamado desecret key cryptography. As principais características da criptografia simétrica são as seguintes -

  • É mais simples e rápido.
  • As duas partes trocam a chave de forma segura.

Recua

A principal desvantagem da criptografia simétrica é que, se a chave vazar para o intruso, a mensagem pode ser facilmente alterada e isso é considerado um fator de risco.

Padrão de criptografia de dados (DES)

O algoritmo de chave simétrica mais popular é o Data Encryption Standard (DES) e o Python inclui um pacote que inclui a lógica por trás do algoritmo DES.

Instalação

O comando para instalação do pacote DES pyDES em Python é -

pip install pyDES

A implementação de programa simples do algoritmo DES é a seguinte -

import pyDes

data = "DES Algorithm Implementation"
k = pyDes.des("DESCRYPT", pyDes.CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=pyDes.PAD_PKCS5)
d = k.encrypt(data)

print "Encrypted: %r" % d
print "Decrypted: %r" % k.decrypt(d)
assert k.decrypt(d) == data

Requer a variável padmode que busca todos os pacotes de acordo com a implementação do algoritmo DES e segue a criptografia e descriptografia de uma maneira especificada.

Resultado

Você pode ver a seguinte saída como resultado do código fornecido acima -

Criptografia Assimétrica

Também é chamado de public key cryptography.Funciona no sentido inverso da criptografia simétrica. Isso implica que são necessárias duas chaves: uma para criptografar e outra para descriptografar. A chave pública é usada para criptografar e a chave privada é usada para descriptografar.

Recua

  • Devido ao seu comprimento de chave, ele contribui com menor velocidade de criptografia.
  • O gerenciamento de chaves é crucial.

O código de programa a seguir em Python ilustra o funcionamento da criptografia assimétrica usando o algoritmo RSA e sua implementação -

from Crypto import Random
from Crypto.PublicKey import RSA
import base64

def generate_keys():
   # key length must be a multiple of 256 and >= 1024
   modulus_length = 256*4
   privatekey = RSA.generate(modulus_length, Random.new().read)
   publickey = privatekey.publickey()
   return privatekey, publickey

def encrypt_message(a_message , publickey):
   encrypted_msg = publickey.encrypt(a_message, 32)[0]
   encoded_encrypted_msg = base64.b64encode(encrypted_msg)
   return encoded_encrypted_msg

def decrypt_message(encoded_encrypted_msg, privatekey):
   decoded_encrypted_msg = base64.b64decode(encoded_encrypted_msg)
   decoded_decrypted_msg = privatekey.decrypt(decoded_encrypted_msg)
   return decoded_decrypted_msg

a_message = "This is the illustration of RSA algorithm of asymmetric cryptography"
privatekey , publickey = generate_keys()
encrypted_msg = encrypt_message(a_message , publickey)
decrypted_msg = decrypt_message(encrypted_msg, privatekey)

print "%s - (%d)" % (privatekey.exportKey() , len(privatekey.exportKey()))
print "%s - (%d)" % (publickey.exportKey() , len(publickey.exportKey()))
print " Original content: %s - (%d)" % (a_message, len(a_message))
print "Encrypted message: %s - (%d)" % (encrypted_msg, len(encrypted_msg))
print "Decrypted message: %s - (%d)" % (decrypted_msg, len(decrypted_msg))

Resultado

Você pode encontrar a seguinte saída ao executar o código fornecido acima -

O algoritmo RSA é uma técnica de criptografia de chave pública e é considerada a forma mais segura de criptografia. Foi inventado por Rivest, Shamir e Adleman no ano de 1978 e, portanto, o nomeRSA algoritmo.

Algoritmo

O algoritmo RSA possui os seguintes recursos -

  • O algoritmo RSA é uma exponenciação popular em um campo finito sobre números inteiros, incluindo números primos.

  • Os inteiros usados ​​por este método são suficientemente grandes tornando-o difícil de resolver.

  • Existem dois conjuntos de chaves neste algoritmo: chave privada e chave pública.

Você terá que seguir as etapas a seguir para trabalhar no algoritmo RSA -

Etapa 1: Gerar o módulo RSA

O procedimento inicial começa com a seleção de dois números primos, a saber, p e q, e, em seguida, calculando seu produto N, como mostrado -

N=p*q

Aqui, seja N o grande número especificado.

Etapa 2: Número derivado (e)

Considere o número e como um número derivado que deve ser maior que 1 e menor que (p-1) e (q-1). A condição primária será que não deve haver nenhum fator comum de (p-1) e (q-1), exceto 1

Etapa 3: chave pública

O par de números especificado n e e forma a chave pública RSA e é tornada pública.

Etapa 4: Chave privada

Chave privada dé calculado a partir dos números p, q e e. A relação matemática entre os números é a seguinte -

ed = 1 mod (p-1) (q-1)

A fórmula acima é a fórmula básica do Algoritmo Euclidiano Estendido, que leva p e q como parâmetros de entrada.

Fórmula de criptografia

Considere um remetente que envia a mensagem de texto simples para alguém cuja chave pública é (n,e). Para criptografar a mensagem de texto simples em um determinado cenário, use a seguinte sintaxe -

C = Pe mod n

Fórmula de descriptografia

O processo de descriptografia é muito simples e inclui análises para cálculo em uma abordagem sistemática. Considerando o receptor C tem a chave privada d, o módulo de resultado será calculado como -

Plaintext = Cd mod n

Neste capítulo, vamos nos concentrar na implementação passo a passo do algoritmo RSA usando Python.

Gerando chaves RSA

As etapas a seguir estão envolvidas na geração de chaves RSA -

  • Crie dois grandes números primos, a saber p e q. O produto desses números será chamadon, Onde n= p*q

  • Gere um número aleatório que é relativamente primo com (p-1) e (q-1). Deixe o número ser chamado como e.

  • Calcule o inverso modular de e. O inverso calculado será chamado ded.

Algoritmos para gerar chaves RSA

Precisamos de dois algoritmos primários para gerar chaves RSA usando Python - Cryptomath module e Rabin Miller module.

Módulo de criptografia

O código-fonte do módulo de criptografia que segue toda a implementação básica do algoritmo RSA é o seguinte -

def gcd(a, b):
   while a != 0:
      a, b = b % a, a
   return b

def findModInverse(a, m):
   if gcd(a, m) != 1:
      return None
   u1, u2, u3 = 1, 0, a
   v1, v2, v3 = 0, 1, m
   
   while v3 != 0:
      q = u3 // v3
         v1, v2, v3, u1, u2, u3 = (u1 - q * v1), (u2 - q * v2), (u3 - q * v3), v1, v2, v3
   return u1 % m

Módulo RabinMiller

O código-fonte do módulo RabinMiller que segue toda a implementação básica do algoritmo RSA é o seguinte -

import random
def rabinMiller(num):
   s = num - 1
   t = 0
   
   while s % 2 == 0:
      s = s // 2
      t += 1
   for trials in range(5):
      a = random.randrange(2, num - 1)
      v = pow(a, s, num)
      if v != 1:
         i = 0
         while v != (num - 1):
            if i == t - 1:
               return False
            else:
               i = i + 1
               v = (v ** 2) % num
      return True
def isPrime(num):
   if (num 7< 2):
      return False
   lowPrimes = [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, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 
   673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 
   797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 
   911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
	
   if num in lowPrimes:
      return True
   for prime in lowPrimes:
      if (num % prime == 0):
         return False
   return rabinMiller(num)
def generateLargePrime(keysize = 1024):
   while True:
      num = random.randrange(2**(keysize-1), 2**(keysize))
      if isPrime(num):
         return num

O código completo para gerar chaves RSA é o seguinte -

import random, sys, os, rabinMiller, cryptomath

def main():
   makeKeyFiles('RSA_demo', 1024)

def generateKey(keySize):
   # Step 1: Create two prime numbers, p and q. Calculate n = p * q.
   print('Generating p prime...')
   p = rabinMiller.generateLargePrime(keySize)
   print('Generating q prime...')
   q = rabinMiller.generateLargePrime(keySize)
   n = p * q
	
   # Step 2: Create a number e that is relatively prime to (p-1)*(q-1).
   print('Generating e that is relatively prime to (p-1)*(q-1)...')
   while True:
      e = random.randrange(2 ** (keySize - 1), 2 ** (keySize))
      if cryptomath.gcd(e, (p - 1) * (q - 1)) == 1:
         break
   
   # Step 3: Calculate d, the mod inverse of e.
   print('Calculating d that is mod inverse of e...')
   d = cryptomath.findModInverse(e, (p - 1) * (q - 1))
   publicKey = (n, e)
   privateKey = (n, d)
   print('Public key:', publicKey)
   print('Private key:', privateKey)
   return (publicKey, privateKey)

def makeKeyFiles(name, keySize):
   # Creates two files 'x_pubkey.txt' and 'x_privkey.txt' 
      (where x is the value in name) with the the n,e and d,e integers written in them,
   # delimited by a comma.
   if os.path.exists('%s_pubkey.txt' % (name)) or os.path.exists('%s_privkey.txt' % (name)):
      sys.exit('WARNING: The file %s_pubkey.txt or %s_privkey.txt already exists! Use a different name or delete these files and re-run this program.' % (name, name))
   publicKey, privateKey = generateKey(keySize)
   print()
   print('The public key is a %s and a %s digit number.' % (len(str(publicKey[0])), len(str(publicKey[1])))) 
   print('Writing public key to file %s_pubkey.txt...' % (name))
   
   fo = open('%s_pubkey.txt' % (name), 'w')
	fo.write('%s,%s,%s' % (keySize, publicKey[0], publicKey[1]))
   fo.close()
   print()
   print('The private key is a %s and a %s digit number.' % (len(str(publicKey[0])), len(str(publicKey[1]))))
   print('Writing private key to file %s_privkey.txt...' % (name))
   
   fo = open('%s_privkey.txt' % (name), 'w')
   fo.write('%s,%s,%s' % (keySize, privateKey[0], privateKey[1]))
   fo.close()
# If makeRsaKeys.py is run (instead of imported as a module) call
# the main() function.
if __name__ == '__main__':
   main()

Resultado

A chave pública e as chaves privadas são geradas e salvas nos respectivos arquivos, conforme mostrado na saída a seguir.

Neste capítulo, vamos nos concentrar em diferentes implementações de criptografia de criptografia RSA e nas funções envolvidas na mesma. Você pode consultar ou incluir este arquivo python para implementar a implementação do algoritmo de criptografia RSA.

Os módulos incluídos para o algoritmo de criptografia são os seguintes -

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA512, SHA384, SHA256, SHA, MD5
from Crypto import Random
from base64 import b64encode, b64decode
hash = "SHA-256"

Inicializamos o valor de hash como SHA-256 para fins de segurança melhor. Usaremos uma função para gerar novas chaves ou um par de chaves pública e privada usando o código a seguir.

def newkeys(keysize):
   random_generator = Random.new().read
   key = RSA.generate(keysize, random_generator)
   private, public = key, key.publickey()
   return public, private
def importKey(externKey):
   return RSA.importKey(externKey)

Para criptografia, é usada a seguinte função que segue o algoritmo RSA -

def encrypt(message, pub_key):
   cipher = PKCS1_OAEP.new(pub_key)
   return cipher.encrypt(message)

Dois parâmetros são obrigatórios: message e pub_keyque se refere à chave pública. Uma chave pública é usada para criptografar e uma chave privada é usada para descriptografar.

O programa completo para o procedimento de criptografia é mencionado abaixo -

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA512, SHA384, SHA256, SHA, MD5
from Crypto import Random
from base64 import b64encode, b64decode
hash = "SHA-256"

def newkeys(keysize):
   random_generator = Random.new().read
   key = RSA.generate(keysize, random_generator)
   private, public = key, key.publickey()
   return public, private

def importKey(externKey):
   return RSA.importKey(externKey)

def getpublickey(priv_key):
   return priv_key.publickey()

def encrypt(message, pub_key):
   cipher = PKCS1_OAEP.new(pub_key)
   return cipher.encrypt(message)

Este capítulo é uma continuação do capítulo anterior, onde seguimos a implementação passo a passo da criptografia usando o algoritmo RSA e discutimos em detalhes sobre isso.

A função usada para descriptografar o texto cifrado é a seguinte -

def decrypt(ciphertext, priv_key):
   cipher = PKCS1_OAEP.new(priv_key)
   return cipher.decrypt(ciphertext)

Para criptografia de chave pública ou criptografia de chave assimétrica, é importante manter dois recursos importantes, a saber Authentication e Authorization.

Autorização

Autorização é o processo de confirmação de que o remetente é o único que transmitiu a mensagem. O código a seguir explica isso -

def sign(message, priv_key, hashAlg="SHA-256"):
   global hash
   hash = hashAlg
   signer = PKCS1_v1_5.new(priv_key)
   
   if (hash == "SHA-512"):
      digest = SHA512.new()
   elif (hash == "SHA-384"):
      digest = SHA384.new()
   elif (hash == "SHA-256"):
      digest = SHA256.new()
   elif (hash == "SHA-1"):
      digest = SHA.new()
   else:
      digest = MD5.new()
   digest.update(message)
   return signer.sign(digest)

Autenticação

A autenticação é possível pelo método de verificação explicado a seguir -

def verify(message, signature, pub_key):
   signer = PKCS1_v1_5.new(pub_key)
   if (hash == "SHA-512"):
      digest = SHA512.new()
   elif (hash == "SHA-384"):
      digest = SHA384.new()
   elif (hash == "SHA-256"):
      digest = SHA256.new()
   elif (hash == "SHA-1"):
      digest = SHA.new()
   else:
      digest = MD5.new()
   digest.update(message)
   return signer.verify(digest, signature)

A assinatura digital é verificada junto com os detalhes do remetente e do destinatário. Isso adiciona mais peso para fins de segurança.

Decodificação de criptografia RSA

Você pode usar o seguinte código para descriptografia de criptografia RSA -

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA512, SHA384, SHA256, SHA, MD5
from Crypto import Random
from base64 import b64encode, b64decode
hash = "SHA-256"

def newkeys(keysize):
   random_generator = Random.new().read
   key = RSA.generate(keysize, random_generator)
   private, public = key, key.publickey()
   return public, private

def importKey(externKey):
   return RSA.importKey(externKey)

def getpublickey(priv_key):
   return priv_key.publickey()

def encrypt(message, pub_key):
   cipher = PKCS1_OAEP.new(pub_key)
   return cipher.encrypt(message)

def decrypt(ciphertext, priv_key):
   cipher = PKCS1_OAEP.new(priv_key)
   return cipher.decrypt(ciphertext)

def sign(message, priv_key, hashAlg = "SHA-256"):
   global hash
   hash = hashAlg
   signer = PKCS1_v1_5.new(priv_key)
   
   if (hash == "SHA-512"):
      digest = SHA512.new()
   elif (hash == "SHA-384"):
      digest = SHA384.new()
   elif (hash == "SHA-256"):
      digest = SHA256.new()
   elif (hash == "SHA-1"):
      digest = SHA.new()
   else:
      digest = MD5.new()
   digest.update(message)
   return signer.sign(digest)

def verify(message, signature, pub_key):
   signer = PKCS1_v1_5.new(pub_key)
   if (hash == "SHA-512"):
      digest = SHA512.new()
   elif (hash == "SHA-384"):
      digest = SHA384.new()
   elif (hash == "SHA-256"):
      digest = SHA256.new()
   elif (hash == "SHA-1"):
      digest = SHA.new()
   else:
      digest = MD5.new()
   digest.update(message)
   return signer.verify(digest, signature)

Hackear a cifra RSA é possível com números primos pequenos, mas é considerado impossível se for usado com números grandes. Os motivos que especificam porque é difícil hackear a cifra RSA são os seguintes -

  • O ataque de força bruta não funcionaria, pois há muitas chaves possíveis para trabalhar. Além disso, isso consome muito tempo.

  • O ataque de dicionário não funcionará no algoritmo RSA, pois as chaves são numéricas e não incluem nenhum caractere.

  • A análise de frequência dos caracteres é muito difícil de seguir, pois um único bloco criptografado representa vários caracteres.

  • Não há truques matemáticos específicos para hackear a cifra RSA.

A equação de descriptografia RSA é -

M = C^d mod n

Com a ajuda de pequenos números primos, podemos tentar hackear a cifra RSA e o código de amostra para o mesmo é mencionado abaixo -

def p_and_q(n):
   data = []
   for i in range(2, n):
      if n % i == 0:
         data.append(i)
   return tuple(data)

def euler(p, q):
   return (p - 1) * (q - 1)

def private_index(e, euler_v):
   for i in range(2, euler_v):
      if i * e % euler_v == 1:
         return i

def decipher(d, n, c):
   return c ** d % n
	def main():
      e = int(input("input e: "))
      n = int(input("input n: "))
      c = int(input("input c: "))
      
      # t = 123
      # private key = (103, 143)
      p_and_q_v = p_and_q(n)
      # print("[p_and_q]: ", p_and_q_v)
      euler_v = euler(p_and_q_v[0], p_and_q_v[1])
      
      # print("[euler]: ", euler_v)
      d = private_index(e, euler_v)
      plain = decipher(d, n, c)
      print("plain: ", plain)
if __name__ == "__main__":
   main()

Resultado

O código acima produz a seguinte saída -