IRC blowfish encryption mode?

2019-07-31 16:37发布

问题:

I've been doing some tests with this tool : http://crypto.hurlant.com/demo/CryptoDemo.swf and been trying to match blowfish results obtained from Mirc + blowfish (from what used to be fish.secure.us v1.30). I cannot for the life of me find what mode it is using... Nothing matches.. Does anyone know what mode it uses ??

回答1:

It simply uses ECB mode, but the base64 encoding is done in an odd way - each block of 32 bits of ciphertext is independently encoded into 6 base64 characters.



回答2:

Blowfish plugins for IRC seem to use the MODE_ECB (electronic code book), which is probably the least secure of the blowfish algorithms.

For encryption, they break the plaintext up into 8-byte chunks (the Blowfish ECB blocksize). They then encrypt each 8-byte block separately, and take the output of each encrypted block, and chunk that into (2) 4-byte longs, and base64encode each long, padding them to length of 6 base64 characters.

For decryption, this process is reversed, but because it's somewhat confusing I'll also describe that. Take 12 of the ciphertext bytes, decoding each 6-byte representation as a long ('>L'), so that you now have 8 bytes, which you then pass to the blowfish decryption algo.

import struct, string
from Crypto.Cipher import Blowfish

def blow(key, plaintext):
    if not isinstance(plaintext, str):
        raise TypeError('Plaintext must be str')
    else:
        if len(plaintext) % 8 != 0:
            plaintext += "\0" * (8-(len(plaintext)%8))

        cipher = Blowfish.new(key, Blowfish.MODE_ECB)

        ciphertext = ''
        charset = list('./' + string.digits + string.ascii_lowercase + string.ascii_uppercase)
        for j in range(0,len(plaintext),8):
            block = cipher.encrypt(plaintext[j:j+8])
            (low, high) = struct.unpack('>LL', block)

            while high:
                ciphertext += charset[high%64]
                high //= 64
            if len(ciphertext) % 6 != 0:
                ciphertext += charset[0] * (6-len(ciphertext)%6)

            while low:
                ciphertext += charset[low%64]
                low //= 64
            if len(ciphertext) % 6 != 0:
                ciphertext += charset[0] * (6-len(ciphertext)%6)

        assert len(ciphertext) % 12 == 0
        return ciphertext

def unblow(key, ciphertext):
    if not isinstance(ciphertext, str):
        raise TypeError('Ciphertext must be str')
    else:
        assert len(ciphertext) % 12 == 0
        cipher = Blowfish.new(key, Blowfish.MODE_ECB)
        plaintext = bytearray()

        charset = list('./' + string.digits + string.ascii_lowercase + string.ascii_uppercase)
        for j in range(0,len(ciphertext),12):
            high = 0
            for k in range(6):
                high |= charset.index(ciphertext[j+k]) << (k*6)
            low = 0
            for k in range(6):
                low |= charset.index(ciphertext[j+k+6]) << (k*6)
            plaintext += cipher.decrypt(struct.pack('>LL', low, high))

        return plaintext.decode('utf8').rstrip("\0")


回答3:

IRC does not support any modes for encryption, everything is transferred as plain text except if you are using SSL. Blowfish is an encryption algorithm which will be translating your messages (on mIRC) or any client you are using.

Without blowfish messages will be sent to the server as:

PRIVMSG #Channel :YourMessage

With blowfish messages will be sent to the server as:

PRIVMSG #Channel :w8e09w8e09q8eqiwoqweqweqweqwueqwehwqheqywgBlowFishEncryption