hydrus/include/HydrusEncryption.py

230 lines
5.4 KiB
Python
Raw Normal View History

2013-05-01 17:21:53 +00:00
import Crypto.Cipher.AES
import Crypto.Cipher.PKCS1_OAEP
import Crypto.PublicKey.RSA
import HydrusConstants as HC
2017-01-04 22:48:23 +00:00
import OpenSSL
2013-05-01 17:21:53 +00:00
import os
2017-01-11 22:31:30 +00:00
import stat
2013-05-01 17:21:53 +00:00
import traceback
2016-12-14 21:19:07 +00:00
AES_KEY_LENGTH = 32
AES_BLOCK_SIZE = 16
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
def DecryptAES( aes_key, encrypted_message ):
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
iv = encrypted_message[:AES_BLOCK_SIZE]
enciphered_message = encrypted_message[AES_BLOCK_SIZE:]
2013-05-01 17:21:53 +00:00
aes_cipher = Crypto.Cipher.AES.new( aes_key, Crypto.Cipher.AES.MODE_CFB, iv )
2016-12-14 21:19:07 +00:00
padded_message = aes_cipher.decrypt( enciphered_message )
2013-05-01 17:21:53 +00:00
message = UnpadAES( padded_message )
return message
2016-12-14 21:19:07 +00:00
def DecryptAESStream( aes_key, stream_in, stream_out ):
iv = stream_in.read( AES_BLOCK_SIZE )
2013-05-01 17:21:53 +00:00
aes_cipher = Crypto.Cipher.AES.new( aes_key, Crypto.Cipher.AES.MODE_CFB, iv )
2016-12-14 21:19:07 +00:00
next_block = stream_in.read( HC.READ_BLOCK_SIZE )
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
while True:
block = next_block
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
next_block = stream_in.read( HC.READ_BLOCK_SIZE )
decrypted_block = aes_cipher.decrypt( block )
if next_block == '':
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
decrypted_block = UnpadAES( decrypted_block )
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
stream_out.write( decrypted_block )
if next_block == '':
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
break
2013-05-01 17:21:53 +00:00
def DecryptPKCS( private_key, encrypted_message ):
rsa_cipher = Crypto.Cipher.PKCS1_OAEP.new( private_key )
message = rsa_cipher.decrypt( encrypted_message )
return message
2016-12-14 21:19:07 +00:00
def DeserialiseRSAKey( text ):
return Crypto.PublicKey.RSA.importKey( text )
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
def EncryptAES( aes_key, message ):
iv = GenerateIV()
2013-05-01 17:21:53 +00:00
padded_message = PadAES( message )
aes_cipher = Crypto.Cipher.AES.new( aes_key, Crypto.Cipher.AES.MODE_CFB, iv )
2016-12-14 21:19:07 +00:00
enciphered_message = aes_cipher.encrypt( padded_message )
encrypted_message = iv + enciphered_message
2013-05-01 17:21:53 +00:00
return encrypted_message
2016-12-14 21:19:07 +00:00
def EncryptAESStream( aes_key, stream_in, stream_out ):
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
iv = GenerateIV()
stream_out.write( iv )
2013-05-01 17:21:53 +00:00
aes_cipher = Crypto.Cipher.AES.new( aes_key, Crypto.Cipher.AES.MODE_CFB, iv )
2016-12-14 21:19:07 +00:00
next_block = stream_in.read( HC.READ_BLOCK_SIZE )
while True:
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
block = next_block
next_block = stream_in.read( HC.READ_BLOCK_SIZE )
if next_block == '':
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
block = PadAES( block )
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
encrypted_block = aes_cipher.encrypt( block )
2015-11-18 22:44:07 +00:00
2016-12-14 21:19:07 +00:00
stream_out.write( encrypted_block )
if next_block == '':
break
2015-11-18 22:44:07 +00:00
2013-05-01 17:21:53 +00:00
def EncryptPKCS( public_key, message ):
rsa_cipher = Crypto.Cipher.PKCS1_OAEP.new( public_key )
# my understanding is that I don't have to manually pad this, cause OAEP does it for me.
encrypted_message = rsa_cipher.encrypt( message )
return encrypted_message
2016-12-14 21:19:07 +00:00
def GenerateAESKey():
return os.urandom( AES_KEY_LENGTH )
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
def GenerateIV():
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
return os.urandom( AES_BLOCK_SIZE )
2013-05-01 17:21:53 +00:00
def GenerateFilteredRandomBytes( byte_to_exclude, num_bytes ):
bytes = []
while len( bytes ) < num_bytes:
new_byte = os.urandom( 1 )
2017-03-29 19:39:34 +00:00
if new_byte != byte_to_exclude:
bytes.append( new_byte )
2013-05-01 17:21:53 +00:00
return ''.join( bytes )
2017-01-04 22:48:23 +00:00
def GenerateOpenSSLCertAndKeyFile( cert_path, key_path ):
key = OpenSSL.crypto.PKey()
key.generate_key( OpenSSL.crypto.TYPE_RSA, 2048 )
# create a self-signed cert
cert = OpenSSL.crypto.X509()
2017-03-29 19:39:34 +00:00
cert.get_subject().countryName = 'HN'
cert.get_subject().organizationName = 'hydrus network'
cert.get_subject().organizationalUnitName = os.urandom( 32 ).encode( 'hex' )
2017-01-04 22:48:23 +00:00
cert.set_serial_number( 1 )
cert.gmtime_adj_notBefore( 0 )
cert.gmtime_adj_notAfter( 10*365*24*60*60 )
cert.set_issuer( cert.get_subject() )
cert.set_pubkey( key )
cert.sign( key, 'sha256' )
cert_text = OpenSSL.crypto.dump_certificate( OpenSSL.crypto.FILETYPE_PEM, cert )
with open( cert_path, 'wt' ) as f:
f.write( cert_text )
2017-01-11 22:31:30 +00:00
os.chmod( cert_path, stat.S_IREAD )
2017-01-04 22:48:23 +00:00
key_text = OpenSSL.crypto.dump_privatekey( OpenSSL.crypto.FILETYPE_PEM, key )
with open( key_path, 'wt' ) as f:
f.write( key_text )
2017-01-11 22:31:30 +00:00
os.chmod( key_path, stat.S_IREAD )
2016-12-14 21:19:07 +00:00
def GenerateRSAKeyPair():
2013-05-01 17:21:53 +00:00
2016-12-14 21:19:07 +00:00
private_key = Crypto.PublicKey.RSA.generate( 2048 )
2013-05-01 17:21:53 +00:00
public_key = private_key.publickey()
2016-12-14 21:19:07 +00:00
return ( private_key, public_key )
2013-05-01 17:21:53 +00:00
def PadAES( message ):
2016-12-14 21:19:07 +00:00
block_size = AES_BLOCK_SIZE
2013-05-01 17:21:53 +00:00
# get last byte
# add random gumpf (except for last byte), then add last byte again
last_byte = message[-1]
num_bytes_to_add = block_size - ( len( message ) % block_size )
pad = GenerateFilteredRandomBytes( last_byte, num_bytes_to_add - 1 ) + last_byte
return message + pad
2016-12-14 21:19:07 +00:00
def SerialiseRSAKey( key ):
return key.exportKey()
2013-05-01 17:21:53 +00:00
def UnpadAES( message ):
2016-12-14 21:19:07 +00:00
block_size = AES_BLOCK_SIZE
2013-05-01 17:21:53 +00:00
# check last byte, jump back to previous instance of that byte
last_byte = message[-1]
i = 2
while True:
if message[-i] == last_byte: break
i += 1
index_of_correct_end = len( message ) - i
return message[:index_of_correct_end + 1]
2013-11-13 21:30:38 +00:00