Crittografia con Python - Guida rapida

La crittografia è l'arte della comunicazione tra due utenti tramite messaggi codificati. La scienza della crittografia è emersa con il motivo fondamentale di fornire sicurezza ai messaggi riservati trasferiti da una parte all'altra.

La crittografia è definita come l'arte e la scienza di nascondere il messaggio per introdurre privacy e segretezza come riconosciuto nella sicurezza delle informazioni.

Terminologie della crittografia

I termini usati di frequente in crittografia sono spiegati qui:

Testo normale

Il messaggio di testo normale è il testo che è leggibile e può essere compreso da tutti gli utenti. Il testo in chiaro è il messaggio che subisce la crittografia.

Testo cifrato

Il testo cifrato è il messaggio ottenuto dopo aver applicato la crittografia al testo normale.

Crittografia

Il processo di conversione del testo normale in testo cifrato è chiamato crittografia. È anche chiamato codifica.

Decrittazione

Il processo di conversione del testo cifrato in testo normale è chiamato decrittografia. È anche definito come decodifica.

Il diagramma riportato di seguito mostra un'illustrazione del processo completo di crittografia:

Caratteristiche della crittografia moderna

Le caratteristiche di base della crittografia moderna sono le seguenti:

  • Funziona su sequenze di bit.

  • Utilizza algoritmi matematici per proteggere le informazioni.

  • Richiede alle parti interessate a un canale di comunicazione sicuro per ottenere la privacy.

La crittografia a doppia forza, chiamata anche crittografia multipla, è il processo di crittografia di un testo già crittografato una o più volte, con lo stesso algoritmo / modello o uno diverso.

Gli altri nomi per la crittografia a doppio livello includono la crittografia a cascata o la crittografia a cascata.

Livelli di crittografia a doppia forza

La crittografia a doppia forza include vari livelli di crittografia che sono spiegati qui sotto:

Primo livello di crittografia

Il testo cifrato viene generato dal messaggio leggibile originale utilizzando algoritmi hash e chiavi simmetriche. Successivamente le chiavi simmetriche vengono crittografate con l'aiuto di chiavi asimmetriche. La migliore illustrazione per questo modello è combinare l'hash digest del testo cifrato in una capsula. Il destinatario calcolerà prima il digest e successivamente decifrerà il testo per verificare che il testo non venga manomesso nel mezzo.

Secondo livello di crittografia

Il secondo livello di crittografia è il processo di aggiunta di un ulteriore livello al testo cifrato con algoritmo uguale o diverso. Di solito, per lo stesso viene utilizzata una password simmetrica lunga 32 bit.

Terzo livello di crittografia

In questo processo, la capsula crittografata viene trasmessa tramite connessione SSL / TLS al partner di comunicazione.

Il diagramma seguente mostra il processo di doppia crittografia in modo pittorico:

Crittografia ibrida

La crittografia ibrida è il processo di utilizzo di più cifrari di diversi tipi insieme includendo i vantaggi di ciascuno di essi. Esiste un approccio comune che di solito viene seguito per generare una chiave segreta casuale per un codice simmetrico e quindi crittografare questa chiave tramite crittografia a chiave asimmetrica.

A causa di questo modello, il messaggio originale stesso viene crittografato utilizzando la crittografia simmetrica e quindi utilizzando la chiave segreta. Il destinatario dopo aver ricevuto il messaggio decrittografa il messaggio utilizzando prima la chiave segreta, utilizzando la propria chiave privata e quindi utilizza la chiave specificata per decrittografare il messaggio.

Python è un linguaggio di scripting open source di alto livello, interpretato, interattivo e orientato agli oggetti. È progettato per essere altamente leggibile. La sintassi del linguaggio Python è facile da capire e utilizza frequentemente parole chiave inglesi.

Caratteristiche del linguaggio Python

Python fornisce le seguenti funzionalità principali:

Interpretato

Python viene elaborato in fase di esecuzione utilizzando l'interprete. Non è necessario compilare un programma prima dell'esecuzione. È simile a PERL e PHP.

Orientato agli oggetti

Python segue uno stile orientato agli oggetti e modelli di progettazione. Include la definizione della classe con varie caratteristiche come l'incapsulamento e il polimorfismo.

Punti chiave del linguaggio Python

I punti chiave del linguaggio di programmazione Python sono i seguenti:

  • Comprende programmazione e metodi funzionali e strutturati, nonché metodi di programmazione orientati agli oggetti.

  • Può essere utilizzato come linguaggio di scripting o come linguaggio di programmazione.

  • Include la raccolta automatica dei rifiuti.

  • Include tipi di dati dinamici di alto livello e supporta vari controlli dinamici del tipo.

  • Python include una funzionalità di integrazione con C, C ++ e linguaggi come Java.

Il collegamento per il download per il linguaggio Python è il seguente: www.python.org/downloads Include pacchetti per vari sistemi operativi come Windows, MacOS e distribuzioni Linux.

Stringhe Python

La dichiarazione di base delle stringhe è mostrata di seguito:

str = 'Hello World!'

Elenchi di Python

Gli elenchi di python possono essere dichiarati come tipi di dati composti, separati da virgole e racchiusi tra parentesi quadre ([]).

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

Tuple Python

Una tupla è un tipo di dati dinamico di Python che consiste in un numero di valori separati da virgole. Le tuple sono racchiuse tra parentesi.

tinytuple = (123, 'john')

Dizionario Python

Il dizionario Python è un tipo di tabella hash. Una chiave del dizionario può essere quasi qualsiasi tipo di dati di Python, che di solito sono numeri o stringhe.

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

Pacchetti di crittografia

Python include un pacchetto chiamato crittografia che fornisce ricette e primitive crittografiche. Supporta Python 2.7, Python 3.4+ e PyPy 5.3+. L'installazione di base del pacchetto di crittografia si ottiene tramite il seguente comando:

pip install cryptography

Esistono vari pacchetti con ricette di alto livello e interfacce di basso livello per algoritmi crittografici comuni come symmetric ciphers, message digests e key derivation functions.

In questo tutorial, utilizzeremo vari pacchetti di Python per l'implementazione di algoritmi crittografici.

Il capitolo precedente ti ha fornito una panoramica dell'installazione di Python sul tuo computer locale. In questo capitolo imparerai in dettaglio la cifratura inversa e la sua codifica.

Algoritmo di Reverse Cipher

L'algoritmo di cifratura inversa contiene le seguenti caratteristiche:

  • Reverse Cipher utilizza un modello di inversione della stringa di testo normale per convertirla come testo cifrato.

  • Il processo di crittografia e decrittografia è lo stesso.

  • Per decrittografare il testo cifrato, l'utente deve semplicemente invertire il testo cifrato per ottenere il testo normale.

Inconveniente

Il principale svantaggio della cifratura inversa è che è molto debole. Un hacker può facilmente rompere il testo cifrato per ottenere il messaggio originale. Pertanto, la crittografia inversa non è considerata una buona opzione per mantenere un canale di comunicazione sicuro.

Esempio

Considera un esempio in cui l'affermazione This is program to explain reverse cipherdeve essere implementato con algoritmo di cifratura inversa. Il seguente codice Python utilizza l'algoritmo per ottenere l'output.

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)

Produzione

Puoi vedere il testo invertito, che è l'output come mostrato nell'immagine seguente -

Spiegazione

  • Il testo normale viene memorizzato nel messaggio variabile e la variabile tradotta viene utilizzata per memorizzare il testo cifrato creato.

  • La lunghezza del testo normale viene calcolata utilizzando for loop e con l'aiuto di index number. I caratteri vengono memorizzati nella variabile di testo cifratotranslated che è stampato nell'ultima riga.

Nell'ultimo capitolo abbiamo trattato la cifratura inversa. Questo capitolo parla del cifrario di Cesare in dettaglio.

Algoritmo di Caesar Cipher

L'algoritmo del cifrario Cesare ha le seguenti caratteristiche:

  • Caesar Cipher Technique è il metodo semplice e facile della tecnica di crittografia.

  • È un semplice tipo di cifratura a sostituzione.

  • Ogni lettera di testo normale viene sostituita da una lettera con un numero fisso di posizioni in basso con l'alfabeto.

Il diagramma seguente illustra il funzionamento dell'implementazione dell'algoritmo di cifratura Caesar:

L'implementazione del programma dell'algoritmo di cifratura Caesar è la seguente:

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)

Produzione

Puoi vedere il codice di Cesare, che è l'output come mostrato nell'immagine seguente -

Spiegazione

Il carattere di testo normale viene attraversato uno alla volta.

  • Per ogni carattere nel testo normale dato, trasforma il carattere dato secondo la regola a seconda della procedura di crittografia e decrittografia del testo.

  • Dopo aver seguito i passaggi, viene generata una nuova stringa che viene definita testo cifrato.

Hacking di Caesar Cipher Algorithm

Il testo cifrato può essere violato con varie possibilità. Una di queste possibilità èBrute Force Technique,che comporta il tentativo di ogni possibile chiave di decrittazione. Questa tecnica non richiede molti sforzi ed è relativamente semplice per un hacker.

L'implementazione del programma per l'hacking dell'algoritmo di cifratura Caesar è la seguente:

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))

Considera il testo cifrato criptato nell'esempio precedente. Quindi, l'output con i possibili metodi di hacking con la chiave e l'utilizzo della tecnica di attacco di forza bruta è il seguente:

Fino ad ora, hai imparato a conoscere gli algoritmi di cifratura inversa e di cifratura Caesar. Parliamo ora dell'algoritmo ROT13 e della sua implementazione.

Spiegazione dell'algoritmo ROT13

Il cifrario ROT13 si riferisce alla forma abbreviata Rotate by 13 places. È un caso speciale di Caesar Cipher in cui lo spostamento è sempre 13. Ogni lettera viene spostata di 13 posizioni per crittografare o decrittografare il messaggio.

Esempio

Il diagramma seguente spiega graficamente il processo dell'algoritmo ROT13:

Codice programma

L'implementazione del programma dell'algoritmo ROT13 è la seguente:

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()

È possibile visualizzare l'uscita ROT13 come mostrato nell'immagine seguente:

Inconveniente

L'algoritmo ROT13 utilizza 13 turni. Pertanto, è molto facile spostare i caratteri in modo inverso per decrittografare il testo cifrato.

Analisi dell'algoritmo ROT13

L'algoritmo di cifratura ROT13 è considerato come un caso speciale di Caesar Cipher. Non è un algoritmo molto sicuro e può essere rotto facilmente con l'analisi della frequenza o semplicemente provando 25 tasti possibili, mentre ROT13 può essere rotto spostando 13 posizioni. Pertanto, non include alcun utilizzo pratico.

Transposition Cipher è un algoritmo crittografico in cui l'ordine degli alfabeti nel testo in chiaro viene riorganizzato per formare un testo cifrato. In questo processo, gli alfabeti di testo normale non sono inclusi.

Esempio

Un semplice esempio di cifrario di trasposizione è columnar transposition cipherdove ogni carattere nel testo normale è scritto orizzontalmente con la larghezza dell'alfabeto specificata. Il codice è scritto verticalmente, il che crea un testo cifrato completamente diverso.

Considera il testo normale hello worlde applichiamo la semplice tecnica di trasposizione colonnare come mostrato di seguito

I caratteri di testo normale vengono posizionati orizzontalmente e il testo cifrato viene creato con formato verticale come : holewdlo lr. Ora, il destinatario deve utilizzare la stessa tabella per decrittografare il testo cifrato in testo normale.

Codice

Il seguente codice di programma dimostra l'implementazione di base della tecnica di trasposizione colonnare:

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'))

Spiegazione

  • Utilizzo della funzione split_len(), possiamo dividere i caratteri di testo normale, che possono essere inseriti in formato colonna o riga.

  • encode Il metodo aiuta a creare un testo cifrato con la chiave che specifica il numero di colonne e stampa il testo cifrato leggendo i caratteri in ogni colonna.

Produzione

Il codice del programma per l'implementazione di base della tecnica di trasposizione colonnare fornisce il seguente output:

Note- I crittoanalisti hanno osservato un miglioramento significativo della sicurezza crittografica quando viene eseguita la tecnica di trasposizione. Hanno anche notato che la ricrittografia del testo cifrato utilizzando lo stesso cifrario di trasposizione crea una maggiore sicurezza.

Nel capitolo precedente, abbiamo imparato a conoscere Transposition Cipher. In questo capitolo, discutiamo la sua crittografia.

Pyperclip

L'utilizzo principale di pyperclipplugin nel linguaggio di programmazione Python serve per eseguire il modulo multipiattaforma per copiare e incollare il testo negli appunti. Puoi installare pythonpyperclip modulo utilizzando il comando come mostrato

pip install pyperclip

Se il requisito esiste già nel sistema, è possibile visualizzare il seguente output:

Codice

Il codice python per crittografare il cifrario di trasposizione in cui pyperclip è il modulo principale è come mostrato di seguito:

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()

Produzione

Il codice del programma per crittografare il cifrario di trasposizione in cui pyperclip è il modulo principale dà il seguente output -

Spiegazione

  • La funzione main() chiama il encryptMessage() che include la procedura per dividere i caratteri usando len funzione e iterandoli in un formato colonnare.

  • La funzione principale viene inizializzata alla fine per ottenere l'output appropriato.

In questo capitolo imparerai la procedura per decrittografare il cifrario di trasposizione.

Codice

Osservare il codice seguente per una migliore comprensione della decrittografia di un cifrario di trasposizione. Il testo cifrato per il messaggioTransposition Cipher con chiave as 6 viene recuperato come 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()

Spiegazione

Il testo cifrato e la chiave citata sono i due valori presi come parametri di input per decodificare o decifrare il testo cifrato con tecnica inversa posizionando i caratteri in un formato di colonna e leggendoli in modo orizzontale.

È possibile inserire lettere in un formato di colonna e successivamente combinarle o concatenarle insieme utilizzando il seguente pezzo di codice:

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)

Produzione

Il codice del programma per la decrittografia del cifrario di trasposizione fornisce il seguente output:

In Python, è possibile crittografare e decrittografare i file prima di trasmetterli a un canale di comunicazione. Per questo, dovrai utilizzare il pluginPyCrypto. È possibile installare questo plug-in utilizzando il comando fornito di seguito.

pip install pycrypto

Codice

Il codice del programma per crittografare il file con protezione password è menzionato di seguito:

# =================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()

È possibile utilizzare il seguente comando per eseguire il processo di crittografia insieme alla password:

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

Produzione

È possibile osservare il seguente output quando si esegue il codice sopra riportato:

Spiegazione

Le password vengono generate utilizzando l'algoritmo hash MD5 ei valori vengono archiviati in file di backup semplicemente sicuri nel sistema Windows, che include i valori come mostrato di seguito:

In questo capitolo, discutiamo della decrittografia dei file in crittografia utilizzando Python. Si noti che per il processo di decrittografia, seguiremo la stessa procedura, ma invece di specificare il percorso di output, ci concentreremo sul percorso di input o sul file necessario che è crittografato.

Codice

Di seguito è riportato un codice di esempio per la decrittografia di file in crittografia utilizzando 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()

È possibile utilizzare il seguente comando per eseguire il codice sopra:

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

Produzione

È possibile osservare il codice seguente quando si esegue il comando mostrato sopra:

Note - L'output specifica i valori hash prima della crittografia e dopo la decrittografia, che mantiene una nota che lo stesso file è crittografato e il processo ha avuto successo.

La codifica Base64 converte i dati binari in formato testo, che viene passato attraverso il canale di comunicazione in cui un utente può gestire il testo in modo sicuro. Base64 è anche chiamato comePrivacy enhanced Electronic mail (PEM) e viene utilizzato principalmente nel processo di crittografia della posta elettronica.

Python include un modulo chiamato BASE64 che include due funzioni principali come indicato di seguito:

  • base64.decode(input, output) - Decodifica il parametro del valore di input specificato e memorizza l'output decodificato come un oggetto.

  • Base64.encode(input, output) - Codifica il parametro del valore di input specificato e memorizza l'output decodificato come un oggetto.

Programma per la codifica

È possibile utilizzare la seguente parte di codice per eseguire la codifica base64:

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

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

Produzione

Il codice per la codifica base64 fornisce il seguente output:

Programma per la decodifica

È possibile utilizzare la seguente parte di codice per eseguire la decodifica base64:

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

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

Produzione

Il codice per la decodifica base64 fornisce il seguente output:

Differenza tra ASCII e base64

Puoi osservare le seguenti differenze quando lavori su ASCII e base64 per la codifica dei dati:

  • Quando codifichi il testo in ASCII, inizi con una stringa di testo e la converti in una sequenza di byte.

  • Quando si codificano i dati in Base64, si inizia con una sequenza di byte e la si converte in una stringa di testo.

Inconveniente

L'algoritmo Base64 viene solitamente utilizzato per memorizzare le password nel database. Lo svantaggio principale è che ogni parola decodificata può essere codificata facilmente tramite qualsiasi strumento online e gli intrusi possono facilmente ottenere le informazioni.

In questo capitolo, comprendiamo il processo XOR insieme alla sua codifica in Python.

Algoritmo

L'algoritmo XOR di crittografia e decrittografia converte il testo normale nel formato ASCII byte e utilizza la procedura XOR per convertirlo in un byte specificato. Offre i seguenti vantaggi ai suoi utenti:

  • Calcolo veloce
  • Nessuna differenza segnata nel lato sinistro e destro
  • Facile da capire e analizzare

Codice

È possibile utilizzare la seguente parte di codice per eseguire il 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)

Produzione

Il codice per il processo XOR fornisce il seguente output:

Spiegazione

  • La funzione xor_crypt_string() include un parametro per specificare la modalità di codifica e decodifica e anche il valore della stringa.

  • Le funzioni di base sono prese con i moduli base64 che seguono la procedura / operazione XOR per crittografare o decrittografare il testo normale / testo cifrato.

Note - La crittografia XOR viene utilizzata per crittografare i dati ed è difficile da decifrare con il metodo della forza bruta, ovvero generando chiavi di crittografia casuali da abbinare al testo cifrato corretto.

Durante l'utilizzo della tecnica di cifratura Caesar, la crittografia e la decrittografia dei simboli comporta la conversione dei valori in numeri con una semplice procedura di base di addizione o sottrazione.

Se la moltiplicazione viene utilizzata per convertire in testo cifrato, viene chiamata a wrap-aroundsituazione. Considera le lettere ei numeri associati da utilizzare come mostrato di seguito:

I numeri verranno utilizzati per la procedura di moltiplicazione e la chiave associata è 7. La formula di base da utilizzare in tale scenario per generare una cifra moltiplicativa è la seguente:

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

Il numero recuperato attraverso l'output viene mappato nella tabella sopra menzionata e la lettera corrispondente viene considerata come lettera crittografata.

La funzione di modulazione di base di un cifrario moltiplicativo in Python è la seguente:

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

Note- Il vantaggio con un cifrario moltiplicativo è che può funzionare con chiavi molto grandi come 8,953,851. Ci vorrebbe molto tempo perché un computer eserciti la forza bruta attraverso una maggioranza di nove milioni di tasti.

Affine Cipher è la combinazione dell'algoritmo Multiplicative Cipher e Caesar Cipher. L'implementazione di base del cifrario affine è come mostrato nell'immagine qui sotto:

In questo capitolo, implementeremo la crittografia affine creando la sua classe corrispondente che include due funzioni di base per la crittografia e la decrittografia.

Codice

È possibile utilizzare il codice seguente per implementare una crittografia affine:

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')

Produzione

È possibile osservare il seguente output quando si implementa una cifratura affine:

L'output visualizza il messaggio crittografato per il messaggio di testo normale Affine Cipher e messaggio decrittografato per il messaggio inviato come input abcdefg.

In questo capitolo imparerai a conoscere la cifratura monoalfabetica e il suo hacking utilizzando Python.

Cipher monoalfabetico

Una crittografia monoalfabetica utilizza una sostituzione fissa per crittografare l'intero messaggio. Qui viene mostrato un cifrario monoalfabetico che utilizza un dizionario Python con oggetti JSON -

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',
	' ': ' ',
}

Con l'aiuto di questo dizionario, possiamo crittografare le lettere con le lettere associate come valori nell'oggetto JSON. Il seguente programma crea un programma monoalfabetico come rappresentazione di classe che include tutte le funzioni di crittografia e decrittografia.

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)
   )

Questo file viene chiamato in seguito per implementare il processo di crittografia e decrittografia del cifrario monoalfabetico menzionato di seguito:

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)

Produzione

È possibile osservare il seguente output quando si implementa il codice sopra riportato:

Pertanto, è possibile hackerare una crittografia monoalfabetica con una coppia chiave-valore specificata che trasforma il testo cifrato in testo normale.

La cifratura a sostituzione semplice è la cifratura più comunemente usata e include un algoritmo per sostituire ogni carattere di testo normale per ogni carattere di testo cifrato. In questo processo, gli alfabeti sono confusi rispetto all'algoritmo di cifratura Caesar.

Example

Keys for a simple substitution cipher usually consists of 26 letters. An example key is −

plain alphabet : abcdefghijklmnopqrstuvwxyz
cipher alphabet: phqgiumeaylnofdxjkrcvstzwb

An example encryption using the above key is−

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

The following code shows a program to implement simple substitution cipher −

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()

Output

You can observe the following output when you implement the code given above −

In this chapter, we will focus on testing substitution cipher using various methods, which helps to generate random strings as given below −

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()

Output

You can observe the output as randomly generated strings which helps in generating random plain text messages, as shown below −

After the test is successfully completed, we can observe the output message Substitution test passed!.

Thus, you can hack a substitution cipher in the systematic manner.

In this chapter, you can learn about simple implementation of substitution cipher which displays the encrypted and decrypted message as per the logic used in simple substitution cipher technique. This can be considered as an alternative approach of coding.

Code

You can use the following code to perform decryption using simple substitution cipher −

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')

Output

The above code gives you the output as shown here −

In this chapter, you will learn in detail about various modules of cryptography in Python.

Cryptography Module

It includes all the recipes and primitives, and provides a high level interface of coding in Python. You can install cryptography module using the following command −

pip install cryptography

Code

You can use the following code to implement the cryptography module −

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)

Output

The code given above produces the following output −

The code given here is used to verify the password and creating its hash. It also includes logic for verifying the password for authentication purpose.

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')

Output

Scenario 1 − If you have entered a correct password, you can find the following output −

Scenario 2 − If we enter wrong password, you can find the following output −

Explanation

Hashlib package is used for storing passwords in a database. In this program, salt is used which adds a random sequence to the password string before implementing the hash function.

Vignere Cipher includes a twist with Caesar Cipher algorithm used for encryption and decryption. Vignere Cipher works similar to Caesar Cipher algorithm with only one major distinction: Caesar Cipher includes algorithm for one-character shift, whereas Vignere Cipher includes key with multiple alphabets shift.

Mathematical Equation

For encryption the mathematical equation is as follows −

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

For decryption the mathematical equation is as follows −

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

Vignere cipher uses more than one set of substitutions, and hence it is also referred as polyalphabetic cipher. Vignere Cipher will use a letter key instead of a numeric key representation: Letter A will be used for key 0, letter B for key 1 and so on. Numbers of the letters before and after encryption process is shown below −

The possible combination of number of possible keys based on Vignere key length is given as follows, which gives the result of how secure is Vignere Cipher Algorithm −

Vignere Tableau

The tableau used for Vignere cipher is as shown below −

In this chapter, let us understand how to implement Vignere cipher. Consider the text This is basic implementation of Vignere Cipher is to be encoded and the key used is PIZZA.

Code

You can use the following code to implement a Vignere cipher in 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()

Output

You can observe the following output when you implement the code given above −

The possible combinations of hacking the Vignere cipher is next to impossible. Hence, it is considered as a secure encryption mode.

One-time pad cipher is a type of Vignere cipher which includes the following features −

  • It is an unbreakable cipher.

  • The key is exactly same as the length of message which is encrypted.

  • The key is made up of random symbols.

  • As the name suggests, key is used one time only and never used again for any other message to be encrypted.

A causa di ciò, il messaggio crittografato sarà vulnerabile agli attacchi per un crittoanalista. Viene chiamata la chiave utilizzata per un cifrario a blocco unicopad, poiché è stampato su blocchi di carta.

Perché è infrangibile?

La chiave è infrangibile grazie alle seguenti caratteristiche:

  • La chiave è lunga quanto il messaggio fornito.

  • La chiave è veramente casuale e appositamente generata automaticamente.

  • Testo chiave e semplice calcolato come modulo 10/26/2.

  • Ogni chiave deve essere utilizzata una volta e distrutta sia dal mittente che dal destinatario.

  • Dovrebbero esserci due copie della chiave: una con il mittente e l'altra con il destinatario.

Crittografia

Per crittografare una lettera, un utente deve scrivere una chiave sotto il testo in chiaro. La lettera in chiaro è posta in alto e la lettera chiave a sinistra. La sezione trasversale ottenuta tra due lettere è il testo normale. È descritto nell'esempio seguente:

Decrittazione

Per decrittografare una lettera, l'utente prende la lettera chiave a sinistra e trova la lettera del testo cifrato in quella riga. La lettera di testo normale viene posizionata nella parte superiore della colonna dove l'utente può trovare la lettera di testo cifrato.

Python include un modulo di implementazione hacky per one-time-padimplementazione della cifratura. Il nome del pacchetto è chiamato One-Time-Pad che include uno strumento di crittografia della riga di comando che utilizza un meccanismo di crittografia simile all'algoritmo di crittografia one-time pad.

Installazione

È possibile utilizzare il seguente comando per installare questo modulo:

pip install onetimepad

Se desideri utilizzarlo dalla riga di comando, esegui il seguente comando:

onetimepad

Codice

Il codice seguente aiuta a generare un cifrario pad monouso:

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)

Produzione

È possibile osservare il seguente output quando si esegue il codice sopra indicato:

Note - Il messaggio crittografato è molto facile da decifrare se la lunghezza della chiave è inferiore alla lunghezza del messaggio (testo normale).

In ogni caso, la chiave non è necessariamente casuale, il che rende il cifrario a blocco unico uno strumento utile.

In questo capitolo, discutiamo in dettaglio della crittografia simmetrica e asimmetrica.

Crittografia simmetrica

In questo tipo, il processo di crittografia e decrittografia utilizza la stessa chiave. È anche chiamato comesecret key cryptography. Le caratteristiche principali della crittografia simmetrica sono le seguenti:

  • È più semplice e veloce.
  • Le due parti si scambiano la chiave in modo sicuro.

Inconveniente

Il principale svantaggio della crittografia simmetrica è che se la chiave viene trapelata all'intruso, il messaggio può essere facilmente modificato e questo è considerato un fattore di rischio.

Data Encryption Standard (DES)

L'algoritmo di chiave simmetrica più popolare è Data Encryption Standard (DES) e Python include un pacchetto che include la logica alla base dell'algoritmo DES.

Installazione

Il comando per l'installazione del pacchetto DES pyDES in Python è -

pip install pyDES

La semplice implementazione del programma dell'algoritmo DES è la seguente:

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

Richiede la variabile padmode che recupera tutti i pacchetti secondo l'implementazione dell'algoritmo DES e segue la crittografia e la decrittografia in un modo specificato.

Produzione

È possibile visualizzare il seguente output come risultato del codice sopra riportato:

Crittografia asimmetrica

È anche chiamato come public key cryptography.Funziona al contrario della crittografia simmetrica. Ciò implica che richiede due chiavi: una per la crittografia e l'altra per la decrittografia. La chiave pubblica viene utilizzata per la crittografia e la chiave privata viene utilizzata per la decrittografia.

Inconveniente

  • A causa della sua lunghezza della chiave, contribuisce a una velocità di crittografia inferiore.
  • La gestione delle chiavi è fondamentale.

Il seguente codice di programma in Python illustra il funzionamento della crittografia asimmetrica utilizzando l'algoritmo RSA e la sua implementazione:

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))

Produzione

È possibile trovare il seguente output quando si esegue il codice sopra indicato:

L'algoritmo RSA è una tecnica di crittografia a chiave pubblica ed è considerato il modo più sicuro di crittografia. È stato inventato da Rivest, Shamir e Adleman nell'anno 1978 e da qui il nomeRSA algoritmo.

Algoritmo

L'algoritmo RSA contiene le seguenti caratteristiche:

  • L'algoritmo RSA è un esponenziale popolare in un campo finito su interi compresi i numeri primi.

  • I numeri interi usati da questo metodo sono sufficientemente grandi, rendendo difficile la risoluzione.

  • Ci sono due serie di chiavi in ​​questo algoritmo: chiave privata e chiave pubblica.

Dovrai eseguire i seguenti passaggi per lavorare sull'algoritmo RSA:

Passaggio 1: generazione del modulo RSA

La procedura iniziale inizia con la selezione di due numeri primi, vale a dire peq, e quindi calcola il loro prodotto N, come mostrato -

N=p*q

Qui, sia N il numero grande specificato.

Passaggio 2: numero derivato (e)

Considera il numero e come un numero derivato che dovrebbe essere maggiore di 1 e minore di (p-1) e (q-1). La condizione principale sarà che non ci dovrebbe essere alcun fattore comune di (p-1) e (q-1) tranne 1

Passaggio 3: chiave pubblica

La coppia di numeri specificata n e e forma la chiave pubblica RSA e viene resa pubblica.

Passaggio 4: chiave privata

Chiave privata dè calcolato dai numeri p, q ed e. La relazione matematica tra i numeri è la seguente:

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

La formula sopra è la formula di base per l'algoritmo euclideo esteso, che accetta peq come parametri di input.

Formula di crittografia

Considera un mittente che invia il messaggio di testo normale a qualcuno la cui chiave pubblica è (n,e). Per crittografare il messaggio di testo normale nello scenario specificato, utilizzare la seguente sintassi:

C = Pe mod n

Formula di decrittografia

Il processo di decrittografia è molto semplice e include analisi per il calcolo in un approccio sistematico. Considerando il ricevitore C ha la chiave privata d, il modulo del risultato sarà calcolato come -

Plaintext = Cd mod n

In questo capitolo, ci concentreremo sull'implementazione graduale dell'algoritmo RSA utilizzando Python.

Generazione di chiavi RSA

I seguenti passaggi sono coinvolti nella generazione di chiavi RSA:

  • Crea due numeri primi grandi cioè p e q. Il prodotto di questi numeri verrà chiamaton, dove n= p*q

  • Genera un numero casuale che è relativamente primo con (p-1) e (q-1). Lascia che il numero sia chiamato come e.

  • Calcola l'inverso modulare di e. L'inverso calcolato sarà chiamato comed.

Algoritmi per la generazione di chiavi RSA

Abbiamo bisogno di due algoritmi primari per generare chiavi RSA usando Python - Cryptomath module e Rabin Miller module.

Modulo Cryptomath

Il codice sorgente del modulo cryptomath che segue tutta l'implementazione di base dell'algoritmo RSA è il seguente:

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

Modulo RabinMiller

Il codice sorgente del modulo RabinMiller che segue tutta l'implementazione di base dell'algoritmo RSA è il seguente:

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

Il codice completo per la generazione delle chiavi RSA è il seguente:

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()

Produzione

La chiave pubblica e le chiavi private vengono generate e salvate nei rispettivi file come mostrato nell'output seguente.

In questo capitolo, ci concentreremo su diverse implementazioni della crittografia di cifratura RSA e sulle funzioni coinvolte per la stessa. Puoi fare riferimento o includere questo file python per implementare l'implementazione dell'algoritmo di cifratura RSA.

I moduli inclusi per l'algoritmo di crittografia sono i seguenti:

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"

Abbiamo inizializzato il valore hash come SHA-256 per una migliore sicurezza. Useremo una funzione per generare nuove chiavi o una coppia di chiavi pubbliche e private utilizzando il codice seguente.

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)

Per la crittografia, viene utilizzata la seguente funzione che segue l'algoritmo RSA:

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

Due parametri sono obbligatori: message e pub_keyche si riferisce alla chiave pubblica. Una chiave pubblica viene utilizzata per la crittografia e una chiave privata viene utilizzata per la decrittografia.

Il programma completo per la procedura di crittografia è menzionato di seguito:

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)

Questo capitolo è una continuazione del capitolo precedente in cui abbiamo seguito l'implementazione graduale della crittografia utilizzando l'algoritmo RSA e ne abbiamo discusso in dettaglio.

La funzione utilizzata per decrittografare il testo cifrato è la seguente:

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

Per la crittografia a chiave pubblica o la crittografia a chiave asimmetrica, è importante mantenere due importanti caratteristiche Authentication e Authorization.

Autorizzazione

L'autorizzazione è il processo per confermare che il mittente è l'unico che ha trasmesso il messaggio. Il codice seguente spiega questo:

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)

Autenticazione

L'autenticazione è possibile tramite il metodo di verifica spiegato come di seguito:

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)

La firma digitale viene verificata insieme ai dettagli del mittente e del destinatario. Ciò aggiunge più età di peso per motivi di sicurezza.

Decrittografia della crittografia RSA

È possibile utilizzare il codice seguente per la decrittografia della crittografia 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)

L'hacking del codice RSA è possibile con numeri primi piccoli, ma è considerato impossibile se viene utilizzato con numeri grandi. I motivi che specificano perché è difficile hackerare il codice RSA sono i seguenti:

  • L'attacco di forza bruta non funzionerebbe perché ci sono troppe chiavi possibili su cui lavorare. Inoltre, questo richiede molto tempo.

  • L'attacco del dizionario non funzionerà nell'algoritmo RSA poiché le chiavi sono numeriche e non includono alcun carattere.

  • L'analisi della frequenza dei caratteri è molto difficile da seguire poiché un singolo blocco crittografato rappresenta vari caratteri.

  • Non esistono trucchi matematici specifici per hackerare il codice RSA.

L'equazione di decrittazione RSA è:

M = C^d mod n

Con l'aiuto di piccoli numeri primi, possiamo provare a hackerare il codice RSA e il codice di esempio per lo stesso è menzionato di seguito:

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()

Produzione

Il codice precedente produce il seguente output: