raw
genesis                 1 import hashlib
genesis 2 import lib.serpent
genesis 3 from lib.serpent import Serpent
genesis 4 from lib.serpent import serpent_cbc_encrypt
genesis 5 from lib.serpent import serpent_cbc_decrypt
genesis 6 from commands import BROADCAST
genesis 7 from commands import DIRECT
9990-keep-ephemer... 8 from commands import IGNORE
9990-keep-ephemer... 9 from lib.message import Message
genesis 10 import base64
genesis 11 import binascii
genesis 12 import time
genesis 13 import struct
genesis 14 import sys
genesis 15 import hmac
genesis 16 import random
9990-keep-ephemer... 17 import os
genesis 18 import pprint
genesis 19 pp = pprint.PrettyPrinter(indent=4)
genesis 20
genesis 21 PACKET_SIZE = 496
genesis 22 MAX_SPEAKER_SIZE = 32
genesis 23 TS_ACCEPTABLE_SKEW = 60 * 15
genesis 24 BLACK_PACKET_FORMAT = "<448s48s"
genesis 25 RED_PACKET_FORMAT = "<16sBBxB428s"
genesis 26 RED_PACKET_LENGTH_WITH_PADDING = 448
genesis 27 MESSAGE_PACKET_FORMAT = "<q32s32s32s324s"
genesis 28 MAX_MESSAGE_LENGTH = 428
genesis 29 MAX_BOUNCES = 3
9991-improved-log... 30 STALE_PACKET = 0
9991-improved-log... 31 DUPLICATE_PACKET = 1
9991-improved-log... 32 MALFORMED_PACKET = 2
9991-improved-log... 33 INVALID_SIGNATURE = 3
9990-keep-ephemer... 34 IGNORED = 4
genesis 35
genesis 36 class Infosec(object):
genesis 37 def __init__(self, server=None):
genesis 38 self.server = server
genesis 39
9988-hash-dedup 40 def get_message_bytes(self, message, peer=None):
genesis 41 try:
9990-keep-ephemer... 42 timestamp = message.timestamp
genesis 43 except:
genesis 44 timestamp = None
9990-keep-ephemer... 45 command = message.command
9990-keep-ephemer... 46 speaker = self._pad(message.speaker, MAX_SPEAKER_SIZE)
genesis 47
genesis 48 # if we are rebroadcasting we need to use the original timestamp
genesis 49
genesis 50 if(timestamp == None):
genesis 51 int_ts = int(time.time())
genesis 52 else:
genesis 53 int_ts = timestamp
genesis 54
genesis 55 # let's generate the self_chain value from the last message or set it to zero if
genesis 56 # there this is the first message
genesis 57
9990-keep-ephemer... 58 if message.original:
genesis 59 if command == DIRECT:
9990-keep-ephemer... 60 self_chain = self.server.state.get_last_message_hash(message.speaker, peer.peer_id)
genesis 61 elif command == BROADCAST:
9990-keep-ephemer... 62 self_chain = self.server.state.get_last_message_hash(message.speaker)
9990-keep-ephemer... 63 elif command == IGNORE:
9990-keep-ephemer... 64 self_chain = "\x00" * 32
genesis 65 net_chain = "\x00" * 32
genesis 66 else:
9990-keep-ephemer... 67 self_chain = message.self_chain
9990-keep-ephemer... 68 net_chain = message.net_chain
genesis 69
genesis 70 # pack message bytes
genesis 71
9990-keep-ephemer... 72 message_bytes = struct.pack(MESSAGE_PACKET_FORMAT, int_ts, self_chain, net_chain, speaker, message.body)
9988-hash-dedup 73 return message_bytes
genesis 74
9988-hash-dedup 75 def pack(self, peer, message):
9988-hash-dedup 76 key_bytes = base64.b64decode(peer.get_key())
9988-hash-dedup 77 signing_key = key_bytes[:32]
9988-hash-dedup 78 cipher_key = key_bytes[32:]
genesis 79
9988-hash-dedup 80 message_bytes = self.get_message_bytes(message, peer)
genesis 81
genesis 82 # pack packet bytes
genesis 83
genesis 84 nonce = self._generate_nonce(16)
9990-keep-ephemer... 85 bounces = message.bounces
genesis 86 version = 0xfe
9988-hash-dedup 87 red_packet_bytes = struct.pack(RED_PACKET_FORMAT, nonce, bounces, version, message.command, self._pad(message_bytes, MAX_MESSAGE_LENGTH))
genesis 88
genesis 89 # encrypt packet
genesis 90
genesis 91 serpent = Serpent(cipher_key)
genesis 92 black_packet_bytes = serpent_cbc_encrypt(cipher_key, red_packet_bytes)
genesis 93
genesis 94 # sign packet
genesis 95
genesis 96 signature_bytes = hmac.new(signing_key, black_packet_bytes, hashlib.sha384).digest()
genesis 97
genesis 98 # pack the signed black packet
genesis 99
genesis 100 signed_packet_bytes = struct.pack(BLACK_PACKET_FORMAT, black_packet_bytes, signature_bytes)
genesis 101
genesis 102 return signed_packet_bytes
genesis 103
genesis 104 def unpack(self, peer, black_packet):
genesis 105 # unpack the black packet
genesis 106
genesis 107 key_bytes = base64.b64decode(peer.get_key())
genesis 108 signing_key = key_bytes[:32]
genesis 109 cipher_key = key_bytes[32:]
genesis 110
genesis 111 try:
genesis 112 black_packet_bytes, signature_bytes = struct.unpack(BLACK_PACKET_FORMAT, black_packet)
genesis 113 except:
genesis 114 self.server.print_error("Discarding malformed black packet from %s" % peer.get_key())
9990-keep-ephemer... 115 return Message({ "error_code": MALFORMED_PACKET }, self.server)
genesis 116
genesis 117 # check signature
genesis 118
genesis 119 signature_check_bytes = hmac.new(signing_key, black_packet_bytes, hashlib.sha384).digest()
genesis 120
genesis 121 if(signature_check_bytes != signature_bytes):
9990-keep-ephemer... 122 return Message({ "error_code": INVALID_SIGNATURE }, self.server)
genesis 123
genesis 124 # try to decrypt black packet
genesis 125
genesis 126 serpent = Serpent(cipher_key)
genesis 127 red_packet_bytes = serpent_cbc_decrypt(cipher_key, black_packet_bytes)
genesis 128
genesis 129 # unpack red packet
genesis 130
genesis 131 nonce, bounces, version, command, message_bytes = struct.unpack(RED_PACKET_FORMAT, red_packet_bytes)
genesis 132
genesis 133 # unpack message
genesis 134
genesis 135 int_ts, self_chain, net_chain, speaker, message = struct.unpack(MESSAGE_PACKET_FORMAT, message_bytes)
genesis 136 speaker = speaker.strip()
9989-show-wot-nicks 137
9989-show-wot-nicks 138 # nothing to be done for an IGNORE command
9989-show-wot-nicks 139
9989-show-wot-nicks 140 if command == IGNORE:
9989-show-wot-nicks 141 return Message({"speaker": speaker, "error_code": IGNORED})
9989-show-wot-nicks 142
genesis 143 # check timestamp
genesis 144
genesis 145 if(int_ts not in self._ts_range()):
9990-keep-ephemer... 146 return Message({ "error_code": STALE_PACKET }, self.server)
genesis 147
9988-hash-dedup 148 # check for duplicates
9988-hash-dedup 149
9988-hash-dedup 150 message_hash = binascii.hexlify(hashlib.sha256(message_bytes).digest())
9988-hash-dedup 151 if(self.server.state.is_duplicate_message(message_hash)):
9990-keep-ephemer... 152 return Message({ "error_code": DUPLICATE_PACKET }, self.server)
genesis 153 else:
9988-hash-dedup 154 self.server.state.add_to_dedup_queue(message_hash)
genesis 155
genesis 156 # check self_chain
genesis 157
genesis 158 if command == DIRECT:
genesis 159 self_chain_check = self.server.state.get_last_message_hash(speaker, peer.peer_id)
genesis 160 elif command == BROADCAST:
genesis 161 self_chain_check = self.server.state.get_last_message_hash(speaker)
genesis 162
genesis 163 self_chain_valid = (self_chain_check == self_chain)
genesis 164
genesis 165 # log this message for use in the self_chain check
genesis 166
genesis 167 self.server.state.log(speaker, message_bytes, peer.peer_id if (command == DIRECT) else None)
genesis 168
genesis 169 # remove padding from message bytes
genesis 170
genesis 171 for index, byte in enumerate(message):
genesis 172 if binascii.hexlify(byte) == "00":
genesis 173 unpadded_message = message[0:index]
genesis 174 break
genesis 175
9990-keep-ephemer... 176 return Message({
9990-keep-ephemer... 177 "peer": peer,
9990-keep-ephemer... 178 "body": unpadded_message.rstrip(),
9990-keep-ephemer... 179 "timestamp": int_ts,
9990-keep-ephemer... 180 "command": command,
9990-keep-ephemer... 181 "speaker": speaker,
9990-keep-ephemer... 182 "bounces": bounces,
9990-keep-ephemer... 183 "self_chain": self_chain,
9990-keep-ephemer... 184 "net_chain": net_chain,
9990-keep-ephemer... 185 "self_chain_valid": self_chain_valid,
9990-keep-ephemer... 186 "error_code": None
9990-keep-ephemer... 187 },
9990-keep-ephemer... 188 self.server)
genesis 189
genesis 190 def _pad(self, text, size):
genesis 191 return text.ljust(size)
genesis 192
genesis 193 def _ts_range(self):
genesis 194 current_ts = int(time.time())
genesis 195 return range(current_ts - TS_ACCEPTABLE_SKEW, current_ts + TS_ACCEPTABLE_SKEW)
genesis 196
genesis 197 def _generate_nonce(self, length=8):
genesis 198 """Generate pseudorandom number."""
genesis 199 return ''.join([str(random.randint(0, 9)) for i in range(length)])
9990-keep-ephemer... 200
9990-keep-ephemer... 201 def gen_rubbish_body(self):
9990-keep-ephemer... 202 return os.urandom(MAX_MESSAGE_LENGTH)