|
|
@@ -33,16 +33,6 @@ The entire Blowfish() class (excluding verify_key()) is by Michael Gilfix |
|
|
|
|
|
|
|
Blowfish.verify_key(), exception classes, encrypt() and decrypt() wrappers, and |
|
|
|
interactive mode are by Ben Kurtovic <ben.kurtovic@verizon.net>. |
|
|
|
|
|
|
|
Map of exceptions: |
|
|
|
* BlowfishError |
|
|
|
* BlockSizeError |
|
|
|
* KeyLengthError |
|
|
|
* KeyTooShortError |
|
|
|
* KeyTooLongError |
|
|
|
* DecryptionError |
|
|
|
* IncorrectKeyError |
|
|
|
* BadCyphertextError |
|
|
|
""" |
|
|
|
|
|
|
|
class BlowfishError(Exception): |
|
|
@@ -53,22 +43,12 @@ class BlockSizeError(BlowfishError): |
|
|
|
"""Attempted to handle a block not 8 bytes in length.""" |
|
|
|
|
|
|
|
class KeyLengthError(BlowfishError): |
|
|
|
"""Base class for invalid key length exceptions.""" |
|
|
|
|
|
|
|
class KeyTooShortError(KeyLengthError): |
|
|
|
"""The given key is too short: it is less than 8 bytes (64 bits).""" |
|
|
|
|
|
|
|
class KeyTooLongError(KeyLengthError): |
|
|
|
"""The given key is too long: it is more than 56 bytes (448 bits.""" |
|
|
|
"""Attempted to use a key that is either less than 8 bytes or more than 56 |
|
|
|
bytes in length.""" |
|
|
|
|
|
|
|
class DecryptionError(BlowfishError): |
|
|
|
"""Base class for exceptions that occur during decryption only.""" |
|
|
|
|
|
|
|
class IncorrectKeyError(DecryptionError): |
|
|
|
"""Attempted to decrypt something with the wrong key.""" |
|
|
|
|
|
|
|
class BadCyphertextError(DecryptionError): |
|
|
|
"""The given cyphertext is malformed and cannot be decrypted.""" |
|
|
|
"""Attempted to decrypt malformed cyphertext (e.g., not evenly divisible |
|
|
|
into 8-byte blocks) or attempted to decrypt using a bad key.""" |
|
|
|
|
|
|
|
class Blowfish(object): |
|
|
|
"""Blowfish encryption Scheme |
|
|
@@ -462,7 +442,8 @@ class Blowfish(object): |
|
|
|
|
|
|
|
def encrypt(self, data): |
|
|
|
if not len(data) == 8: |
|
|
|
raise BlockSizeError("{0} != 8".format(len(data))) |
|
|
|
raise BlockSizeError("blocks must be 8 bytes long, but tried to " + |
|
|
|
"encrypt one {0} bytes long".format(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) |
|
|
@@ -477,7 +458,8 @@ class Blowfish(object): |
|
|
|
|
|
|
|
def decrypt(self, data): |
|
|
|
if not len(data) == 8: |
|
|
|
raise BlockSizeError("{0} != 8".format(len(data))) |
|
|
|
raise BlockSizeError("blocks must be 8 bytes long, but tried to " + |
|
|
|
"decrypt one {0} bytes long".format(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) |
|
|
@@ -503,11 +485,13 @@ class Blowfish(object): |
|
|
|
"""Make sure our key is not too short or too long; if there's a |
|
|
|
problem, raise KeyTooShortError() or KeyTooLongError().""" |
|
|
|
if not key: |
|
|
|
raise KeyTooShortError("no key given") |
|
|
|
raise KeyLengthError("no key given") |
|
|
|
if len(key) < 8: |
|
|
|
raise KeyTooShortError("{0} < 8".format(len(key))) |
|
|
|
raise KeyLengthError(("key is {0} bytes long, but it must be at " + |
|
|
|
"least 8").format(len(key))) |
|
|
|
if len(key) > 56: |
|
|
|
raise KeyTooLongError("{0} > 56".format(len(key))) |
|
|
|
raise KeyLengthError(("key is {0} bytes long, but it must be " + |
|
|
|
"less than 56").format(len(key))) |
|
|
|
|
|
|
|
def encrypt(key, plaintext): |
|
|
|
"""Encrypt any length of plaintext using a given key that must be between |
|
|
@@ -534,18 +518,20 @@ def decrypt(key, cyphertext): |
|
|
|
|
|
|
|
try: |
|
|
|
cyphertext = cyphertext.decode("hex") |
|
|
|
except TypeError as e: |
|
|
|
raise BadCyphertextError(e) |
|
|
|
except TypeError as error: |
|
|
|
e = error.message |
|
|
|
raise DecryptionError("cyphertext could not be decoded: " + e.lower()) |
|
|
|
|
|
|
|
if len(cyphertext) % 8 > 0: |
|
|
|
raise BadCyphertextError("cyphertext cannot be broken into " + |
|
|
|
"8-byte blocks evenly") |
|
|
|
raise DecryptionError("cyphertext cannot be broken into " + |
|
|
|
"8-byte blocks evenly") |
|
|
|
|
|
|
|
blocks = [cyphertext[f:f+8] for f in range(0, len(cyphertext), 8)] |
|
|
|
msg = ''.join(map(cypher.decrypt, blocks)) |
|
|
|
|
|
|
|
if not msg.startswith("TRUE"): # sanity check to ensure valid decryption |
|
|
|
raise IncorrectKeyError() |
|
|
|
raise DecryptionError("the given key is incorrect, or part of the " + |
|
|
|
"cyphertext is malformed") |
|
|
|
|
|
|
|
size, msg = msg[4:].split("|", 1) |
|
|
|
while len(msg) > int(size): |
|
|
|