Skip to content

Instantly share code, notes, and snippets.

@com4
Last active December 31, 2015 18:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save com4/8026566 to your computer and use it in GitHub Desktop.
Save com4/8026566 to your computer and use it in GitHub Desktop.
pycrypto based, blowfish irc encryption plugin
# -*- coding: utf-8 -*-
"""
enc.py
URL: https://gist.github.com/com4/8026566/
Description: pycrypto based, blowfish irc encryption plugin
Clients
-------
* X-Chat
* Install: Place this file in .config/xchat2 and type /py load enc.py. It will be auto-loaded when X-Chat opens.
Probably Works On
-----------------
* X-Chat
* Ubuntu
* Fedora
* Arch Linux
* OS X & XChat Azure
$ ARCHFLAGS=-Wno-error=unused-command-line-argument-hard-error-in-future sudo pip install pycrypto
$ mv enc.py ~/Library/Containers/org.3rddev.xchatazure/Data/Library/Application\ Support/XChat\ Azure/plugins/ # to autoload
Commands
--------
/listkeys - list current keys
/setkey <#chan|nick> <key> - add <key> for #chan or private messages with <nick>
/delkey <#chan|nick> - remove the key
Changes
--------
0.1.1 - strip out bouncer replay timestamps
0.1 - initial release
"""
# SETTINGS
##############################################################
# A secret phrase used to encrypt the channel key database
KEYPASS='asdf' # CHANGE THIS TO ENCRYPT YOUR KEYS
##############################################################
__module_name__ = "enc"
__module_version__ = "0.1.1"
__module_description__ = "universal blowfish irc plugin"
import base64
import cPickle as pickle
import os
from random import randrange
import re
from Crypto.Cipher.Blowfish import BlowfishCipher as Blowfish
import xchat
encrypted_file = os.path.join(xchat.get_info('xchatdir'), 'enc.secure_pickle')
_mb = Blowfish(KEYPASS)
def pad(s):
pad_bytes = 8 - (len(s) % 8)
for i in range(pad_bytes - 1):
s += chr(randrange(0, 256))
bflag = randrange(6, 248); bflag -= bflag % 8 - pad_bytes
s += chr(bflag)
return s
def depad(s):
pad_bytes = ord(s[-1]) % 8
if not pad_bytes:
pad_bytes = 8
return s[:-pad_bytes]
e = lambda b, s: b.encrypt(pad(s))
e64 = lambda b, s: base64.b64encode(e(b, s))
d = lambda b, s: depad(b.decrypt(s))
d64 = lambda b, s: d(b, base64.b64decode(s))
def map_deflate():
pass
_M = {}
def get_map_obj(key):
try:
return _M[key]
except KeyError:
_M[key] = Blowfish(MAP[key])
return _M[key]
MAP = {}
if os.path.exists(encrypted_file):
with open(encrypted_file, "rb") as f:
s = depad(_mb.decrypt(f.read()))
MAP = pickle.loads(s)
print("loaded your enc keys")
def on_send(word, word_eol, userdata):
# 0 = nick
# 1 = text
mynick = xchat.get_info("nick")
nick = xchat.get_context().get_info("channel")
msg = word_eol[0]
try:
secret_str = e64(get_map_obj(nick), msg)
except KeyError:
return xchat.EAT_NONE
xchat.command('PRIVMSG %s :+OK %s' % (nick, secret_str))
xchat.emit_print("Your Message", "⚷%s" % mynick, d64(get_map_obj(nick), secret_str))
del(msg)
return xchat.EAT_ALL
def on_message(word, word_eol, userdata):
# 0 = nick
# 1 = text
channel = xchat.get_context().get_info("channel")
nick = word[0]
bouncer_match = re.match(r"^(\[\d{2}:\d{2}:\d{2}\] )(.*)", word[1])
if bouncer_match:
raw_text = bouncer_match.groups()[1]
else:
raw_text = word[1]
if raw_text.startswith("+OK "):
enc_str = raw_text.split(" ")[1]
try:
secret_str = d64(get_map_obj(channel), enc_str)
except KeyError:
return xchat.EAT_NONE
if bouncer_match:
secret_str = "%s %s" % (bouncer_match.groups()[0].strip(), secret_str)
xchat.emit_print("Channel Message", "⚷%s" % nick, secret_str, "@")
del(raw_text)
return xchat.EAT_ALL
def unload(userdata):
with open(encrypted_file, 'wb') as f:
f.write(_mb.encrypt(pad(pickle.dumps(MAP))))
print("saved your enc keys")
print("unloaded enc!")
def xsetkey(word, word_eol, userdata):
try:
chan = word[1]
key = word[2]
except KeyError:
print("USAGE: /setkey <#chan|nick> <key>")
return xchat.EAT_NONE
print("Set key for %s") % (chan,)
try:
del(_M[chan])
except KeyError:
pass
MAP[chan] = key
def xdelkey(word, word_eol, userdata):
try:
chan = word[1]
except (KeyError, IndexError):
print("USAGE: /delkey <#chan|nick>")
return xchat.EAT_NONE
print("Removed %s") % (chan,)
del(MAP[chan])
del(_M[chan])
def xlistkeys(word, word_eol, userdata):
print(" %s" % ("-"*63,))
print("| %s| %s|" % ("channel/nick".ljust(20), "key".ljust(40)))
print(" %s" % ("-"*63,))
for k in MAP:
print("| %s| %s|" % (k.ljust(20), MAP[k].ljust(40)))
else:
if len(MAP) < 1:
print("| %s |" % "no keys".center(61))
print(" %s" % ("-"*63,))
xchat.hook_print("Channel Message", on_message)
xchat.hook_print("Private Message", on_message)
xchat.hook_print("Private Message to Dialog", on_message)
xchat.hook_command("", on_send)
xchat.hook_command("setkey", xsetkey)
xchat.hook_command("delkey", xdelkey)
xchat.hook_command("listkeys", xlistkeys)
xchat.hook_unload(unload)
print("loaded enc")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment