Ferramentas de Utilizador

Ferramentas de Site


dev_geral:python:criptografia
Esta página não se encontra completa, por favor ajude a melhorá-la

Primeiramente, quero deixar bem claro que este pequeno tutorial é de nível básico, ou seja, vou postar aqui o pouco conhecimento que tenho sobre criptografia, e vou aplica-la usando Python. Irei mostrar mais os exemplos em si, e não como funciona a criptografia.

Na própria documentação do Python (seja qual for a versão que você tem), há um exemplo super básico de como usar as bibliotecas embutidas de criptografia.

Mecanismos de criptografias permitem a transformação reversível da informação de forma a torná-la ininteligível a terceiros. Utiliza-se para tal, algoritmos determinados e uma chave secreta para, a partir de um conjunto de dados não cifrados, produzir uma sequência de dados cifrados. A operação inversa é a decifração.

IMPORTATE SABER: Os módulos nativos do Python não são usados para criptografia propriamente dita, ou seja, são usados somente para hashing (checagem) como o md5, sha e hashlib. Para cifrar dados, terá que usar libs de criptografia simétrica, ou seja, que faz uso de chave (publica ou privada), mas isto não é problema, pois na web você encontrará uma infinidade de ferramentas, tanto para Python, quanto para qualquer outra linguagem de programação.

Estes modulos abaixo são nativos do Python: hashlib - Secure hash and message digest algorithms. hmac - Keyed-Hashing for Message Authentication (HMAC) implementation for Python. md5 - RSA's MD5 message digest algorithm. sha - NIST's secure hash algorithm, SHA.

Mais abaixo, darei exemplos avançados que encontrei na web, mas para começar, darei uma explicação básica. Não pretendo narrar toda historia da criptografia na humanidade, mas resumindo, a criptografia, em geral, é a forma de codificar uma mensagem, ou algum dado qualquer, de forma que somente seja "humanamente" compreendida por uma pessoa que saiba descodificar esta mesma mensagem. Em tempos passados, quando povos entravam em guerra, e quando queriam se comunicar entre si de forma que outras pessoas, ou outros povos não soubesse, se usavam todo tipo de artimanha.

Pombos correios; Sinal de Fumaça; Gravuras em pedras; Desenhos nas árvores, Pintando o corpo, e até gestos com as mãos.

Em era passadas, os índios de guerra usavam o famoso sinal de fumaça para se comunicarem, e assim, saberem aonde atacar, em que momento atacar e a quem atacar, ou qualquer outra coisa que nenhum outro povo deveria saber.

O espião infiltrado em território inimigo, usava o código morse para se comunicar com a base dele. Na minha opinião, sempre foi um fetiche do homem querer guardar segredo, e para isto, com a ajuda da Matemática, foi se desenvolvendo vários métodos de cifrar algum texto, varias formas de "embaralhar" algum dados, vários algoritmos de manter um determinado dado, ilegível a certas pessoas.

Com a chegada da "era digital", e o aumento de Computadores ligados em redes, o uso da criptografia foi se tornando mais comum e indispensável na "troca de informações", por isto, foram criados várias formas de cifrar. Sempre um algoritmo mais complexo que o outro, alguns algoritmos que conheço são:

Criptografia de Cesar; Criptografia Blowfish; AES;

Outros que servem tanto para construção de cifragem quanto para hashing são:

ARC2; ARC4; CAST; DES; DES3; IDEA; RC5; XOR; RSA; base64; etc.

Vamos começar com a cifragem em md5:

import md5
m = md5.new()
m.update("Nobody inspects")
m.update(" the spammish repetition")
m.digest()
'xbbdx9cx83xddx1exa5xc9xd9xdexc9xa1x8dxf0xffxe9'

Viu o output? Agora vamos usar a base64, exemplo com base64:

import base64
encoded = base64.b64encode('data to be encoded')
>>> encoded
'ZGF0YSB0byBiZSBlbmNvZGVk'
data = base64.b64decode(encoded)
>>> data
'data to be encoded'

Viu agora a diferença no output?, que tal misturamos?

# Gerador de MD5
 
import md5, binascii
 
nome = '?'
 
while nome:
    m = md5.new()
    nome = raw_input('Digite seu nome (ou nada para encerrar):')
    if nome:
        m.update(nome)
        senha = raw_input('Digite sua senha:')
        m.update(senha)
        print 'MD5: ', binascii.b2a_base64(m.digest())

Digite um nome e uma senha e terá um hash md5 cifrado em base64 de output. Neste caso, usou-se base64 como construtor, mas poderá ser usado outros construtores (Base16, Base32, Base64).

Simples, não?

Um simples exemplo didáctico de criptografia simétrica da web que usa o algoritmo de César:

# criptografia.py
# -*- coding: iso-8859-1 -*-
#
# Exemplo de um algoritmo de criptografia com chave
# usando o algoritmo criptográfico de Cesar
#
# /! Este algoritmo é extremamente fraco e serve
# apenas para demonstração
 
maintable = [
" 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,.;/áéíóúÁÉÍÓÚàÀãõÃÕüÜ",
"mübõaÚfSÀy,NtvKcJ0ouICHB nT2kzóÕD;Lw/3rlZÉRÃ4ãP6éjiÜAGÍYM8OX5àÓWsVqFUxEpÁQ7hgúá1í9.de",
".UPeZO/hIxJlzgcáCÀL5õsvE7au1fóÍ,Q8úq9DéãHGXr3jàR ;oyüdíNMÁwiTÜ24tm6nBÕSÓWKÉb0YÃFVAkpÚ",
"fuNDEbmlJ2RÀãovCUGta8AÓ,áXúFYÕWQwh/ rZ1MeSTOPs3yd.IKÜ5BknÃqóíÉ7Íõc4zgÚ9üVjéxHàÁ;0L6ip",
"0É;2vtóQwqaIiKzcBVyG9éãCfsHkmüPFngx/8 WÕeíÜÍDÃULu.ZoMhpbú,NAOÚJ5á7r3ÀSlÓ4T6d1RõàÁjEYX",
"JhYb1OGÁáIKremü78H2Bsgã.õ69P/Qu;AlVWXàzoCf4íDSNZóÜtRkyipÍajÉ ÓqéFMdúLUEn5xTÕ3,0ÃvÚwcÀ",
"ÜãÃHYaQÁi94rGm8ÀxZcàóy2kÚqvU7FouP3VzLXBlgjúÍáIJApWsKtÓCwfdSéíeM0hnbõü1OÕ,T5 ./N6D;ERÉ",
"Zõsd8u1V6aGÀÓÚ/9ÁíÃ2áRH5;X4AvCãWwDüióxÉéjcgJKoyú.eIf7YzhTtUSbBO,mP3pqQÜN0ÍàEkrFlnMLÕ ",
"6;áMua /.ÍcéP2Ysm,ówÁ347í9iJLnpFHK5àeARÜDõúZüÀgQoÓyqkxObÚÉvBlNrXWÕCETIhd8zV10GtSfÃUjã",
"hÉÍ,P7úN;zQõÁocDUàI6rC qOB0ãítMYa8.3pÃyT/2ükdEKxf5éJZÓÜÀRuiH4sASXFó91áwjLGWvlÚngbVÕem",
]
 
def normalize_key(key):
    key = [ ord(k) % 10 for k in key ]
    return len(key), key
 
def crypt(text, key, table):
    size, key = normalize_key(key)
    text = list(text)
 
    for pos,char in enumerate(text):
        subtable = table[key[pos % size]]
        new_char_position = table[0].find(char)
 
        if new_char_position < 0:
            new_char = char
        else:
            new_char = subtable[new_char_position]
        text[pos] = new_char
 
    return ''.join(text)
 
def uncrypt(text, key, table):
    size, key = normalize_key(key)
    text = list(text)
 
    for pos,char in enumerate(text):
        subtable = table[key[pos % size]]
        new_char_position = subtable.find(char)
 
        if new_char_position < 0:
            new_char = char
        else:
            new_char = table[0][new_char_position]
 
        text[pos] = new_char
 
    return ''.join(text)
 
def generate_maintable():
    import random
    print "maintable = ["
    x = list("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,.;/áéíóúÁÉÍÓÚàÀãõÃÕüÜ")
    for i in range(10):
        print '    "%s",' % (''.join(x))
        random.shuffle(x)
    print "]"

Exemplo de uso do modulo acima:

import criptografia
 
mensagem = "Vamos invadir a região amanhã às 15hs GMT"
chave = "mitzuplick"
mensagem_cifrada = crypt(mensagem, chave, maintable)
print "Mensagem original: %s" % (mensagem)
print "Mensagem cifrada: %s" % (mensagem_cifrada)
print "Mensagem de retorno: %s" % (uncrypt(mensagem_cifrada, chave, maintable))

Criptografia avançada

Python tem um toolkit chamado PyCrypto, que te fornece os algoritmos mais usados para criptografia. Se você tem uma boa noção de programação, seja em qual linguagem for, e também uma excelente noção em Matemática, poderá criar seu próprio método de cifrar, ou seja, seu próprio algoritmo, mas isto seria inviável, é uma péssima ideia usar um algoritmo criptográfico desconhecido, o mais indicado é usar os já existentes no mercado, pois já foram testados e aperfeiçoados.

Um exemplo da web:

# -*- coding: UTF-8 -*-
# Por Diogo V. Kerting diogovk@gmail.com
# Sob GNU GPL
 
from optparse import OptionParser
import sys
 
usage = "usage: %prog [options] [mensagem]"
 
# Objeto que manipula a linha de comando
parser = OptionParser()
parser.add_option("-o", "--saida", dest="arquivo_saida", help="Imprime em arquivo",metavar="ARQUIVO")
parser.add_option("-e", "--encripta", action="store_true", dest="encriptar",default=False,help="Encriptar mensagem",metavar="ENCRIPTA")
parser.add_option("-d", "--decripta", action="store_true", dest="decriptar",default=False,help="Decriptar mensagem",metavar="DECRIPTA")
parser.add_option("-c", "--chave", action="store", dest="chave",type='int',help="Chave utilizada para encriptar ou decriptar a mensagem",metavar="CHAVE")
(options, args) = parser.parse_args()
 
 
if options.encriptar and options.decriptar:
    print 'Opções conflitantes -e e -d'
if not options.encriptar and not options.decriptar:
    options.encriptar=True
if options.chave == None:
    print 'É necessaria uma chave para a ação selecionada.nTente passar uma atraves do parametro -c'
    sys.exit(1)    
if options.chave > 25 or options.chave < 1:
    print 'A chave deve ser de 1 a 25'
    print options.chave
    sys.exit(1)
 
if args == ['']:
    mensagem=raw_input()
else:
    mensagem=''
    for string in args:
        mensagem+=string+' '
 
chave=options.chave
mensagem_encriptada=''
 
if options.encriptar:
    for byte in mensagem:
        if byte.isalpha():
            byte_encriptado=chr(ord(byte)+chave)
            if byte.isupper() and ord(byte_encriptado) > 90:
                byte_encriptado=chr(ord(byte_encriptado)-26)
            if byte.islower() and ord(byte_encriptado) > 122:
                byte_encriptado=chr(ord(byte_encriptado)-26)
        else:
            byte_encriptado=byte
        mensagem_encriptada+=byte_encriptado
else:
    for byte in mensagem:
        if byte.isalpha():
            byte_encriptado=chr(ord(byte)-chave)
            if byte.isupper() and ord(byte_encriptado) < 65:
                byte_encriptado=chr(ord(byte_encriptado)+26)
            if byte.islower() and ord(byte_encriptado) < 97:
                byte_encriptado=chr(ord(byte_encriptado)+26)
        else:
            byte_encriptado=byte
        mensagem_encriptada+=byte_encriptado
 
print mensagem_encriptada

Boa? não sei!

Mais exemplos:

Na toolkit PyCrypto tem vários algoritmos para se usar, um deles é o Blowfish. Particularmente, eu uso este, e se você não puder baixar toda toolkit, então tenha a lib blowfish somente:

#
# blowfish.py
# Copyright (C) 2002 Michael Gilfix <mgilfix@eecs.tufts.edu>;
#
# This module is open source; you can redistribute it and/or
# modify it under the terms of the GPL or Artistic License.
# These licenses are available at http://www.opensource.org
#
# This software must be used and distributed in accordance
# with the law. The author claims no liability for its
# misuse.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
 
"""
Blowfish Encryption
 
This module is a pure python implementation of Bruce Schneier's
encryption scheme 'Blowfish'. Blowish is a 16-round Feistel Network
cipher and offers substantial speed gains over DES.
 
The key is a string of length anywhere between 64 and 448 bits, or
equivalently 8 and 56 bytes. The encryption and decryption functions operate
on 64-bit blocks, or 8 byte strings.
 
Send questions, comments, bugs my way:
    Michael Gilfix <mgilfix@eecs.tufts.edu>;
"""
 
__author__ = "Michael Gilfix <mgilfix@eecs.tufts.edu>"
 
class Blowfish:
 
	"""Blowfish encryption Scheme
 
	This class implements the encryption and decryption
	functionality of the Blowfish cipher.
 
	Public functions:
 
		def __init__ (self, key)
			Creates an instance of blowfish using 'key'
			as the encryption key. Key is a string of
			length ranging from 8 to 56 bytes (64 to 448
			bits). Once the instance of the object is
			created, the key is no longer necessary.
 
		def encrypt (self, data):
			Encrypt an 8 byte (64-bit) block of text
			where 'data' is an 8 byte string. Returns an
			8-byte encrypted string.
 
		def decrypt (self, data):
			Decrypt an 8 byte (64-bit) encrypted block
			of text, where 'data' is the 8 byte encrypted
			string. Returns an 8-byte string of plaintext.
 
		def cipher (self, xl, xr, direction):
			Encrypts a 64-bit block of data where xl is
			the upper 32-bits and xr is the lower 32-bits.
			'direction' is the direction to apply the
			cipher, either ENCRYPT or DECRYPT constants.
			returns a tuple of either encrypted or decrypted
			data of the left half and right half of the
			64-bit block.
 
	Private members:
 
		def __round_func (self, xl)
			Performs an obscuring function on the 32-bit
			block of data 'xl', which is the left half of
			the 64-bit block of data. Returns the 32-bit
			result as a long integer.
 
	"""
 
	# Cipher directions
	ENCRYPT = 0
	DECRYPT = 1
 
	# For the __round_func
	modulus = long (2) ** 32
 
	def __init__ (self, key):
 
		if not key or len (key) < 8 or len (key) > 56:
			raise RuntimeError, "Attempted to initialize Blowfish cipher with key of invalid length: %s"# Cycle through the p-boxes and round-robin XOR the
		# key with the p-boxes
		key_len = len (key)
		for i in range (len (self.p_boxes)):
			val = (ord (key[(i * 4) % key_len]) << 24) + 
			      (ord (key[(i * 4 + 1) % key_len]) << 16) + 
			      (ord (key[(i * 4 + 2) % key_len]) << 8) + 
			       ord (key[(i * 4 + 3) % key_len])
			self.p_boxes[i] ^= val
 
		# For the chaining process
		l, r = 0, 0
 
		# Begin chain replacing the p-boxes
		for i in range (0, len (self.p_boxes), 2):
			l, r = self.cipher (l, r, self.ENCRYPT)
			self.p_boxes[i] = l
			self.p_boxes[i + 1] = r
 
		# Chain replace the s-boxes
		for i in range (len (self.s_boxes)):
			for j in range (0, len (self.s_boxes[i]), 2):
				l, r = self.cipher (l, r, self.ENCRYPT)
				self.s_boxes[i][j] = l
				self.s_boxes[i][j + 1] = r
 
	def cipher (self, xl, xr, direction):
 
		if direction == self.ENCRYPT:
			for i in range (16):
				xl ^= self.p_boxes[i]
				xr = self.__round_func (xl) ^ xr
				xl, xr = xr, xl
			xl, xr = xr, xl
			xr ^= self.p_boxes[16]
			xl ^= self.p_boxes[17]
		else:
			for i in range (17, 1, -1):
				xl ^= self.p_boxes[i]
				xr = self.__round_func (xl) ^ xr
				xl, xr = xr, xl
			xl, xr = xr, xl
			xr ^= self.p_boxes[1]
			xl ^= self.p_boxes[0]
		return xl, xr
 
	def __round_func (self, xl):
		a = (xl & 0xFF000000) >> 24
		b = (xl & 0x00FF0000) >> 16
		c = (xl & 0x0000FF00) >> 8
		d = xl & 0x000000FF
 
		# Perform all ops as longs then and out the last 32-bits to
		# obtain the integer
		f = (long (self.s_boxes[0][a]) + long (self.s_boxes[1][b])) % self.modulus
		f ^= long (self.s_boxes[2][c])
		f += long (self.s_boxes[3][d])
		f = (f % self.modulus) & 0xFFFFFFFF
 
		return f
 
	def encrypt (self, data):
 
		if not len (data) == 8:
			raise RuntimeError, "Attempted to encrypt data of invalid block length: %s" %len (data)
 
		# Use big endianess since that's what everyone else uses
		xl = ord (data[3]) | (ord (data[2]) << 8) | (ord (data[1]) << 16) | (ord (data[0]) << 24)
		xr = ord (data[7]) | (ord (data[6]) << 8) | (ord (data[5]) << 16) | (ord (data[4]) << 24)
 
		cl, cr = self.cipher (xl, xr, self.ENCRYPT)
		chars = ''.join ([
			chr ((cl >> 24) & 0xFF), chr ((cl >> 16) & 0xFF), chr ((cl >> 8) & 0xFF), chr (cl & 0xFF),
			chr ((cr >> 24) & 0xFF), chr ((cr >> 16) & 0xFF), chr ((cr >> 8) & 0xFF), chr (cr & 0xFF)
		])
		return chars
 
	def decrypt (self, data):
 
		if not len (data) == 8:
			raise RuntimeError, "Attempted to encrypt data of invalid block length: %s" %len (data)
 
		# Use big endianess since that's what everyone else uses
		cl = ord (data[3]) | (ord (data[2]) << 8) | (ord (data[1]) << 16) | (ord (data[0]) << 24)
		cr = ord (data[7]) | (ord (data[6]) << 8) | (ord (data[5]) << 16) | (ord (data[4]) << 24)
 
		xl, xr = self.cipher (cl, cr, self.DECRYPT)
		chars = ''.join ([
			chr ((xl >> 24) & 0xFF), chr ((xl >> 16) & 0xFF), chr ((xl >> 8) & 0xFF), chr (xl & 0xFF),
			chr ((xr >> 24) & 0xFF), chr ((xr >> 16) & 0xFF), chr ((xr >> 8) & 0xFF), chr (xr & 0xFF)
		])
		return chars
 
	def blocksize (self):
		return 8
 
	def key_length (self):
		return 56
 
	def key_bits (self):
		return 56 * 8
 
##############################################################
# Module testing
 
if __name__ == '__main__':
	key = 'This is a test key'
	cipher = Blowfish (key)
 
	print "Testing encryption:"
	xl = 123456
	xr = 654321
	print "tPlain text: (%s, %s)" %(xl, xr)
	cl, cr = cipher.cipher (xl, xr, cipher.ENCRYPT)
	print "tCrypted is: (%s, %s)" %(cl, cr)
	dl, dr = cipher.cipher (cl, cr, cipher.DECRYPT)
	print "tUnencrypted is: (%s, %s)" %(dl, dr)
 
	print "Testing buffer encrypt:"
	text = 'testtest'
	print "tText: %s" %text
	crypted = cipher.encrypt (text)
	print "tEncrypted: %s" %crypted
	decrypted = cipher.decrypt (crypted)
	print "tDecrypted: %s" %decrypted

Este exemplo acima é Criptografia extremamente forte e pode ser usado para criptografar um texto grande por exemplo, e para usa-lo, tem um segredinho.

A entrada para parte de criptografia ou descriptografia do algoritmo é de 64 bits. Então temos que 64 bits = 8 Bytes = 8 caracteres. Para quem não entendeu ainda, 64 bits / 8 bits = 8 Bytes

O blowfish só recebe em blocos de 8 caracteres as entradas, então vamos ter que separar a string com muitos caracteres em vários blocos de 8 caracteres apenas.

Faremos isso com um laço for e vamos cortar a string em vários blocos de 8 caracteres. Mas e se o último bloco conter apenas 6 caracteres? Para termos certeza de que a string contem 8 caracteres podemos forçar com o método string.ljust(variavel, 8 )

A senha também não deve ter menos de 8 caracteres, então está a outra dica: Usar o ljust() na senha também.

Abaixo uma classe bem simples que criptografa e descriptografa com Blowfish.

# cript.py
# Feito em 22/08/2007
#
 
import sys
import string
import base64
import blowfish
 
__author__ = "Felipe Ferreri Tonello <felipe.tonello@gmail.com>"
 
class BFCript:
    """
Classe que usa criptografia Blowfish juntamente com encodificacão Base64
 
uso: cript.py cript|descript ’senha’ ‘texto’
 
PS: Quando for descriptografar, o texto deve estar codificado em Base64
   """
    CRIPTOGRAFAR = 0
    DESCRIPTOGRAFAR = 1
 
    def cript(self,  sKey,  sTxt,  iAction):
        bf = blowfish.Blowfish((len(sKey) < 8 and [string.ljust(sKey, 8)] or [sKey])[0])
 
        if iAction == self.DESCRIPTOGRAFAR:
            sTxt = base64.b64decode(sTxt)
 
        sCript = ""
 
        for i in range(0, len(sTxt), 8) :
            sSBox = sTxt[i:i+8]
            if len(sSBox) > 0 :
                if iAction == self.CRIPTOGRAFAR:
                    sCript += bf.encrypt(string.ljust(sSBox,  8))
                elif iAction == self.DESCRIPTOGRAFAR:
                    sCript += bf.decrypt(sSBox)
 
        if iAction == self.CRIPTOGRAFAR:
            return base64.b64encode(sCript)
        elif iAction == self.DESCRIPTOGRAFAR:
            return sCript
 
##################################################
 
if __name__ == "__main__" :
    bfc = BFCript()
    if len(sys.argv) != 4 or (sys.argv[1] != "cript" and sys.argv[1] != "descript"):
        print BFCript.__doc__
        sys.exit(0)
    elif sys.argv[1] == "cript" :
        print bfc.cript(sys.argv[2], sys.argv[3],  bfc.CRIPTOGRAFAR)
    elif sys.argv[1] == "descript" :
        print bfc.cript(sys.argv[2],  sys.argv[3],  bfc.DESCRIPTOGRAFAR)

Está gostando? Então para testar descriptografe esta menssagem:

"[color=blue]9M39agUxnX8PRznCylaC1/6rEXVP5R85QTO/be8XAO+WRJ2nAGDQ4PWq SOGSQe/CRDkegrH242gpfOcBHPZ6TURUMcQZXkSV8g7WcEIQiCLTuejOt0HCExewS XUgxg8wRlvO6G2ZrKOv6YLzcsXmBHB/JbZ5nuMnlIYQNGj1ncYHbxyJrGHj1Xr7Q696E+u WfcZAm9z/iRfZ9rb79EXY7f/5BBEvdkluxDpedPzam33CQLZoEVixSOwVI18USigj45W6fDk+ yFTGkLF1tmh5Zg==[/color]"

O que será?? … descubra

Abaixo mais um belo exemplo (pyCrypto):

from Crypto.Cipher import AES 
from md5 import md5 
 
def padded(s, block_size): 
     return s.ljust(len(s) + block_size - (len(s) % block_size)) 
 
aes = AES.new(md5('secret password').digest(), AES.MODE_ECB) 
plaintext = 'secret text' 
ciphertext = aes.encrypt(padded(plaintext, AES.block_size)) 
print 'ciphertext:', `ciphertext` 
 
aes = AES.new(md5('secret password').digest(), AES.MODE_ECB) 
plaintext = aes.decrypt(ciphertext).strip() 
print 'plaintext:', `plaintext` 

Neste caso se usa o AES no modo ECB para cifrar o texto 'secret text' com a chave 'secret password' (na verdade, o MD5 dela) e depois decifra.

Agora com o construtor RSA (exemplo da web):

from Crypto.PublicKey import RSA
from Crypto.Util.randpool import RandomPool
 
texto = "texto a encriptar"
 
# Você deve usar a melhor fonte de dados aleatórios que tiver à
# disposição. Pra manter o exemplo mais portável, usaremos o
# RandomPool do próprio PyCrypto:
 
pool = RandomPool(384)
pool.stir()
 
# randfunc(n) deve retornar uma string de dados aleatórios de
# comprimento n, no caso de RandomPool, o método get_bytes
randfunc = pool.get_bytes
 
# Se tiver uma fonte segura (como /dev/urandom em sistemas unix), ela
# deve ser usada ao invés de RandomPool
 
# pool = open("/dev/urandom")
# randfunc = pool.read
 
# Tamanho da chave, em bits
N = 256
 
# O algoritmo RSA usado aqui não utiliza K, que pode ser uma string
# nula.
K = ""
 
# Geramos a chave (contendo a chave pública e privada):
key = RSA.generate(N, randfunc)
 
# Criptografamos o texto com a chave:
enc = key.encrypt(texto, K)
 
# Podemos decriptografar usando a chave:
dec = key.decrypt(enc)
 
# Separando apenas a chave pública:
pub_key = key.publickey()
 
# Criptografando com a chave pública:
enc = pub_key.encrypt(texto, K)
 
# Decriptografando com a chave privada:
dec = key.decrypt(enc)
 
# As informações da chave são compostas de seis atributos: 'n', 'e',
# 'd', 'p', 'q' e 'u'. Se quiser armazenar ou enviar uma chave você
# pode usar pickle ou simplesmente usar esses atributos com o método
# construct. Por exemplo:
 
# Os atributos 'n' e 'e' correspondem à chave pública:
n, e = key.n, key.e
 
# E recriamos a chave pública com esses dados:
pub_key = RSA.construct((n, e))

Para terminar, vou deixar um super exemplo de dedicação. Este cara faz até uma GUI em Tkinter para implementar seu próprio método de criptografia:

#Created By:Patrick T. Cossette (Nobis Software)  <www.nobis-development.com>
 
#Feel free to use this code however you see fit,
#if you intend to use it's encryption methods it
#would be wise to make some slight alterations to
#the 'special' and 'alpha' dictionaries, as well as
#possibly change up 'num' a little bit. (perhaps times
#it by int((num % (num*.82))+1) or something like that
#(you get the idea)
 
 
from Tkinter import *
import tkMessageBox
from ScrolledText import ScrolledText
import tkFileDialog
#from tkColorButton import * I use this module to make my buttons look nicer, it doesn't come with Tk; but can be found on www.python-forum.org
import string
import random
import bz2
from os import getcwd, sys;cwd = getcwd()
d = {}
rd = {}
#If you intedt to change these dictionaries up a little bit, only change the VALUES, NOT THE KEYS! Changing the keys would raise a KeyError during encryption/decryption
special = {'1':'xff', '2':'xaa', '3':'xdb', '4':'xe4', '5':'xf1', '6':'xfb', '7':'xdd', '9':'xf3', '0':'xxf5', '8':'xfa'} #"Special" Characters
alpha  = {'1':'F', '2':'w]', '3':'H', '4':'%', 'j':')', '6':'Y', '7':'k', '9':'Z', '0':'{', '8':'*'}                                #Ascii Characters
txtz = special 
 
 
#The following code prevents error messages from being seen
 
class errorLog:        #Create class to replace sys.stderr
   def write(self, x):#Dummy function
      pass           #errors will go unheard.
 
ERR = errorLog         
sys.stderr = ERR       #Re-route error messages to dummy class
 
#If errors occur when using this script, comment out or delete
#the above block of code, so you can see the error messages
 
crypted = False #Attempts to keep track if the text is encrypted or not
ALL_ASCII = string.ascii_letters + " " + string.punctuation + string.digits + 'nt'
def encrypt(Event = None):
   if UP.get():setState("disabled")
   root.update()
   global crypted
   a = False
   if crypted:a = tkMessageBox.askyesno(title = "Procede?", message = "The text appears to already have beep Encryptednand cannot be encrypted twice. Would you like tonattempt to encrypt it anyway?")
   if not crypted or a:
      num = random.randint(1, strength.get()) #Grab a random number to base the encryption on
      rd = {} #Create the two dictionaries that will be used to "jumble up" the original text
      d = {}
      for char, index in zip(ALL_ASCII, range(num, 101*num, num)):
         d[index] = char
      for char, index in zip(ALL_ASCII, range(num, 101*num, num)):
         rd[char] = index
      result = []
      for char in txt.get(0.0, (END))[:-1]: #Go through the text character by character (disguarding the trailing 'n')
         try:
            result.append(str(rd[char]))   #Fine each character's alternate value, and add it to a list (not added to a string so that a character can be inserted to seperate them later. This is because one character may have a length of up to 6 or 7 after being translated)
         except:
            tkMessageBox.showwarning(title = "ERROR", message = "An Error Occured During Decryption") #Something bad happened
      txt.delete(0.0, (END))
      final = str(num) +(7-len(str(num)))*" " + "xdf".join(result) + 'xdff'  #Join each changed character with a certain special character, placing the EOF "xdff" at the end, and what number to base the decryption on at the beginning
      if asciiOnly.get():
         for char,val in txtz.items():
            final = final.replace(char, val)
      txt.insert((END),final)
      if jump.get():
                  txt.yview_moveto(1)
      crypted = True #Set text status to "encrypted"
   elif crypted and a:
      tkMessageBox.showwarning(title = "Double Encryption", message = "You cannot encrypt something twice!")
   setState("normal")
 
def setState(state):
   for widget in [c1, c2, b1, b2, b3]: #Disable control buttons at the bottom of the window so the user cannot press them while the program is working
      widget['state'] = state
 
def decrypt(Event = None):  #This version seems to freeze up when decrypting large amounts of text. Not sure why, the original has no problem.
   root.update() #Pop the button back out :P
   if UP.get():setState("disabled")
   global crypted
   a = False
 
   if not crypted:
      if tkMessageBox.askyesno(title = "Procede?", message = "The text does not appear to be encrypted, Would you like to attempt decryption anyway?"):crypted, a = True, True
   if crypted:
      x = txt.get(0.0, (END))[:-1]#Grab the text, disguarding the trailing 'n'
 
      for i in alpha.values(): #Look for any value that may indicate the text was encrypted using "TEXT ONLY"
         if i in x:
            txtz = alpha
            break
 
      for i in special.values():#Look for any value that may indicate the text was encrypted using "SPECIAL ONLY"
         if i in x:
            txtz = special
            break
 
      if asciiOnly.get():                 #Some Confusion here when it comes to decrypting "Numeric", THEN decrypting "SPECIAL" characters. I have yet to find the cause of the error...
         for char,val in txtz.items():        #Get rid of the encrpted text to make room for the result
            x = x.replace(val, char) #If "Numbers Only" was selected, this will replace nothing
 
 
      try:
         num = int(x[:7].strip())       #Retrieve the number used to encrypt the text, and remove any white space (which will only be there if 'num' was <= 99999)
      except:
         tkMessageBox.showwarning(title = "ERROR", message = "An Error Occured During Decryption") #Could not find a number to base decryption on
 
      x = x[7:] #assign the encrypted text to 'x'
      rd = {} #Redefined every time because their contents change every time something is encrypted, they do not hold static values
      d = {}
      for char, index in zip(ALL_ASCII, range(num, 101*num, num)):
         d[index] = char
      for char, index in zip(ALL_ASCII, range(num, 101*num, num)):
         rd[char] = index
      result = ""
      f = ""
      go = False
      for char in x:
         if char == "xdf":#Because one character may have a length of more than 1
            go = True
         if go:
            try:
               result += d[int(f)] #Peice the result together character by character
               if UP.get():
                  txt.insert((END),  d[int(f)])
                  root.update()
               if jump.get():
                  txt.yview_moveto(1)
            except:
               pass
            go = False
            f = ""
         else: 
            f += char
      txt.delete(0.0, (END))
      txt.insert((END), result)
      if jump.get():
                  txt.yview_moveto(1)
      crypted = False
   elif not crypted and a:
      tkMessageBox.showwarning(title = "ERROR", message = "An Error Occured During Decryption")
   setState("normal")
 
def clear():  #Reset
   global crypted
   crypted  = False
   txt.delete(0.0, (END))
 
root = Tk()   
strength = IntVar()
strength.set(9999999)
#The original version of this program required that certain files 
#be present to operate, but has been modified to run without them
#These files included a license file, as well as logo images for
#the "about" window.
 
#logo2 = PhotoImage(file = "%sResourceslogo2.gif" %cwd)
#rocket = PhotoImage(file = "%sResourcesrocket.gif" %cwd)
def about(Event=None): 
    master = Toplevel(root)
    master.title('About Basic Encryption Tool')
    master.focus_set()
    photolabel1 = Label(master, text = "No Image")#image = logo2) XXX Image removed so that this code can be sent raw, and still operate correctly (not dependant on other files)
    photolabel1.grid(row = 1, sticky = NW, column = 0, padx = 10, rowspan = 2)
    photolabel2 = Label(master, text = "No Image")#image = logo2)
    photolabel2.grid(sticky = NE, row = 1, padx = 10, rowspan = 2)
    a = Label(master, text='www.nobis-development.comnCreated By:Patrick T. CossettenCold_Soul79078@yahoo.com', font = ('Trebuchet MS', 7, 'bold'))
    a.grid(row = 0)
    photolabel = Label(master, text = "No Image")#image = rocket) #Nobis Software logo. www.nobis-development.com
    photolabel.grid(row = 2)
    copyright = ScrolledText(master, width = 68, height = 16, bg = 'light grey', font = ("arial", 8))
    #copyright.insert((END), file("%slicense.txt" %cwd, 'r').read())   WAS under a more "strict" license, but I decided to be much more 'lax' with this program
    copyright.insert((END), "OpenSource Freeware.. do with it what you wish...nnnttttm/>.<m/ -- Spade42") #Use it, don't use it, change it, post it.. whatever
    copyright.grid(row = 3, padx = 5, pady = 5)
    f  = Frame(master)
    back = Button(f, text='Exit', command = master.destroy, width = 8, font = ("arial", 10))
    back.grid(pady=10,row = 0, column = 8, padx = 5)
    f.grid(pady=10,row = 4, sticky = E)
    master.minsize(480, 456)
    master.maxsize(480, 456)
    master.resizable(width = False, height = False)
    master.grab_set()
 
def setDictionary(x = None):
   global txtz
   if x != None:
      asciiOnly.set(x)
   if asciiOnly.get() == 1:
      txtz = alpha
   elif asciiOnly.get() == 2:
      txtz = special
 
def openFile(Event = None):
      global crypted
      file = tkFileDialog.askopenfile(title = "Open Encrypted Text File", filetypes = (("Text File", (".txt", )), ("All File Types", ("*.*",))))
      if file != None:
         txt.delete(0.0, (END))
         a = file.read()
         if a.startswith("BZh"): #Auto-detect BZ2 compression, if found, attempt to decompress the file first
            try:
               a = bz2.decompress(a)
            except:
               pass
         #Check for encryption method      
         if "xdf" in a:
            crypted = True
         elif "xdc" in a:
            a = a.replace("xdc", "xdf") #Reverse compatability feature
            crypted = True
         txt.insert((END), a)
         file.close()
         if crypted:decrypt() #If encryption was detected, decrypt the text automatically.
 
def saveFile(Event = None):
      writeT = writeT = txt.get(0.0,(END))
      file = tkFileDialog.asksaveasfile(title = "Save Encrypted Text File", filetypes = (("Text File", (".txt", )), ), defaultextension = (("Text File", (".txt", )), ))
      if file != None:
         if compress.get():
            writeT = bz2.compress(txt.get(0.0,(END))) #Compressing the encrypted text is EXTREMEMLY iffy, but it should work fine to just compress normal text (not encrypted)
         file.write(writeT)
         file.close()
def setCompress():
   if compress.get():   #I wouldn't risk compressing encrypted text, only really good for compressing plain text
      if not tkMessageBox.askyesno(title = "Compress?", message = """
Are you sure you want to compress the output? Doing so may cause this file to be permanantly
lost. You may want to save a backup file that is not compressed, and make sure the compressed
file CAN be opened successfully."""):compress.set(0)
def copyAll():
   root.clipboard_append(txt.get(0.0, (END)))
 
def paste(): #Paste and decrypt
   global crypted
   txt.delete(0.0, (END))
   txt.insert(0.0, root.clipboard_get())
   crypted = True
   decrypt()
 
def pasteE(): #Paste and encrypt
   global crypted
   txt.delete(0.0, (END))
   txt.insert(0.0, root.clipboard_get())
   crypted = False
   encrypt()
 
def endApp(): #Just a fance 'destroy' function I suppose..
   if tkMessageBox.askyesno(title = "Exit?", message = "Are you sure you want to exit?"):
      root.iconify() #Just looks nice =]
      root.destroy()
 
UP = IntVar()
UP.set(0)
jump = IntVar()
jump.set(1)
compress = IntVar()
compress.set(0)
asciiOnly = IntVar()
asciiOnly.set(2)
root.title("Encryption Tool")
#Create event bindings
root.bind("<Control-o>", openFile)
root.bind("<Control-s>", saveFile)
root.bind("<Control-e>", encrypt)
root.bind("<Control-d>", decrypt)
root.bind("<Control-t>", lambda Event:setDictionary(1))
root.bind("<Control-n>", lambda Event:setDictionary(2))
root.bind("<Control-p>", lambda Event:setDictionary(0))
txt = ScrolledText(root, width = 100, height = 28, font = ("Arial", 12))
txt.grid(row = 0, column = 0, columnspan = 25, rowspan = 10, padx = 10, pady = 7)
txt.focus()
c1 = Checkbutton(root, text = "Auto Scroll", variable =jump, font = ("arial", 10))
c1.grid(row = 11, column = 16)
c2 = Checkbutton(root, text = "Realtime Decryption Update", variable = UP, font = ("arial", 10))
c2.grid(row = 11, column = 17, columnspan = 3)
 
b1 = Button(root, text = "Clear", font = ("Arial", 10), command = clear, width = 10)
b1.grid(row = 11, pady = 5, pady = 5, column = 21)
b2 = Button(root, text = "Decrypt", font = ("Arial", 10), command = decrypt, width = 10)
b2.grid(row = 11, pady = 5, pady = 5, column = 22)
b3 = Button(root, text = "Encrypt", font = ("Arial", 10), command = encrypt, width = 10)
b3.grid(row = 11, pady = 5, pady = 5, column = 23)
menu = Menu(root)
txt.bind("<Button-3>", lambda Event:editmenu.post(Event.x_root, Event.y_root)) #Enables you to right-click the text area
root.config(menu=menu)
filemenu = Menu(menu, tearoff = False, activeforeground = 'red', activebackground = 'white', bg = 'white')
helpmenu = Menu(menu, tearoff = False, activeforeground = 'red', activebackground = 'white', bg = 'white')
actionmenu = Menu(menu, tearoff = False, activeforeground = 'red', activebackground = 'white', bg = 'white')
strengthmenu = Menu(menu, tearoff = False, activeforeground = 'red', activebackground = 'white', bg = 'white')
outputmenu = Menu(menu, tearoff = False, activeforeground = 'red', activebackground = 'white', bg = 'white')
editmenu = Menu(menu, tearoff = False, activeforeground = 'red', activebackground = 'white', bg = 'white')
menu.add_cascade(label = "File", menu = filemenu)
menu.add_cascade(label = "Edit", menu = editmenu)
menu.add_cascade(label = "Action", menu = actionmenu)
menu.add_cascade(label = "Help", menu = helpmenu)
filemenu.add_command(label = "Open Text File    Ctrl+O", command = openFile)
filemenu.add_command(label = "Save Text File    Ctrl+S", command = saveFile)
filemenu.add_separator()
filemenu.add_command(label = "Exit", command = endApp)
helpmenu.add_command(label = "About   F1", command = about)
editmenu.add_command(label = "Copy All", command = copyAll)
editmenu.add_command(label = "Paste",command = lambda:txt.insert((END), root.clipboard_get()))
editmenu.add_command(label = "Paste And Encrypt",command =  pasteE)
editmenu.add_command(label = "Paste And Decrypt",command =  paste)
actionmenu.add_command(label = "Encrypt  Ctrl+E", command = encrypt)
actionmenu.add_command(label = "Decrypt  Ctrl+D", command = decrypt)
actionmenu.add_separator()
actionmenu.add_cascade(label = "Strength", menu = strengthmenu)
actionmenu.add_cascade(label = "Output", menu = outputmenu)
outputmenu.add_radiobutton(label = "Text Only           Alt+T", variable = asciiOnly, value = 1, command = setDictionary)
outputmenu.add_radiobutton(label = "Numeric Only     Alt+N", variable = asciiOnly, value = 0, command = setDictionary)
outputmenu.add_radiobutton(label = "Special Only       Alt+P", variable = asciiOnly, value = 2, command = setDictionary)
outputmenu.add_separator()
outputmenu.add_checkbutton(label = "Compress Output", command = setCompress, variable = compress)
strengthmenu.add_radiobutton(label = "Very Strong         Alt+Z", variable = strength, value = 9999999)
strengthmenu.add_radiobutton(label = "Strong                 Alt+X", variable = strength, value = 500000)
strengthmenu.add_radiobutton(label = "Medium               Alt+C", variable = strength, value = 250000)
strengthmenu.add_radiobutton(label = "Weak                  Alt+V", variable = strength, value = 99999)
strengthmenu.add_radiobutton(label = "Very Weak          Alt+B", variable = strength, value = 5)
strengthmenu.add_radiobutton(label = "Almost Pointless  Alt+N", variable = strength, value = 1)
root.bind("<Alt-n>",  lambda Event:strength.set(1)) #Attempted to use Alt+1, 2, 3, 4 etc. But couldn't figure out how to tell Tk I wasn't talkint about the mouse buttons o.0
root.bind("<Alt-b>",  lambda Event:strength.set(5))
root.bind("<Alt-v>",  lambda Event:strength.set(99999))
root.bind("<Alt-c>",  lambda Event:strength.set(250000))
root.bind("<Alt-x>",  lambda Event:strength.set(500000))
root.bind("<Alt-z>",  lambda Event:strength.set(9999999)) #Number being passed to set() represents the number of possible encryption combinations
root.bind("<F1>",  about)
root.resizable(height = 0, width = 0) #Disables the "Maximize" button
root.protocol("WM_DELETE_WINDOW", endApp) #Use the "fancy" shutdown function no matter how the program is closed
root.mainloop()#GO!!!!

Espero que tenham gostado…

Tópico de discussão no fórum: Python e Criptografia
dev_geral/python/criptografia.txt · Esta página foi modificada pela última vez em: 2018/05/14 21:37 (Edição externa)