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
9987-embargoing 19 import logging
genesis 20 pp = pprint.PrettyPrinter(indent=4)
genesis 21
genesis 22 PACKET_SIZE = 496
genesis 23 MAX_SPEAKER_SIZE = 32
genesis 24 TS_ACCEPTABLE_SKEW = 60 * 15
genesis 25 BLACK_PACKET_FORMAT = "<448s48s"
genesis 26 RED_PACKET_FORMAT = "<16sBBxB428s"
genesis 27 RED_PACKET_LENGTH_WITH_PADDING = 448
genesis 28 MESSAGE_PACKET_FORMAT = "<q32s32s32s324s"
genesis 29 MAX_MESSAGE_LENGTH = 428
genesis 30 MAX_BOUNCES = 3
9991-improved-log... 31 STALE_PACKET = 0
9991-improved-log... 32 DUPLICATE_PACKET = 1
9991-improved-log... 33 MALFORMED_PACKET = 2
9991-improved-log... 34 INVALID_SIGNATURE = 3
9990-keep-ephemer... 35 IGNORED = 4
genesis 36
genesis 37 class Infosec(object):
9987-embargoing 38 def __init__(self, state=None):
9987-embargoing 39 self.state = state
genesis 40
9987-embargoing 41 def message(self, message):
9987-embargoing 42
9987-embargoing 43 if message.timestamp == None:
9987-embargoing 44 message.original = True
9987-embargoing 45 message.timestamp = int(time.time())
9987-embargoing 46 else:
9987-embargoing 47 message.original = False
9987-embargoing 48
9987-embargoing 49 target_peer = (self.state.get_peer_by_handle(message.handle)
9987-embargoing 50 if message.command == DIRECT
9987-embargoing 51 else None)
9987-embargoing 52
9987-embargoing 53 if target_peer and not target_peer.get_key():
9987-embargoing 54 logging.debug("No key for peer associated with %s" % message.handle)
9987-embargoing 55 return
9987-embargoing 56
9987-embargoing 57 if message.command == DIRECT and target_peer == None:
9987-embargoing 58 logging.debug("Aborting message: unknown handle: %s" % message.handle)
9987-embargoing 59 return
9987-embargoing 60
9986-rebroadcast-... 61 if message.message_bytes == None:
9986-rebroadcast-... 62 message_bytes = self.get_message_bytes(message, target_peer)
9986-rebroadcast-... 63 else:
9986-rebroadcast-... 64 message_bytes = message.message_bytes
9986-rebroadcast-... 65
9987-embargoing 66 if message.command != IGNORE:
9987-embargoing 67 message_hash = binascii.hexlify(hashlib.sha256(message_bytes).digest())
9987-embargoing 68 logging.debug("generated message_hash: %s" % message_hash)
9987-embargoing 69 self.state.add_to_dedup_queue(message_hash)
9987-embargoing 70 self.state.log(message.speaker, message_bytes, target_peer)
9987-embargoing 71
9987-embargoing 72 if message.command == DIRECT:
9987-embargoing 73 signed_packet_bytes = self.pack(target_peer, message, message_bytes)
9987-embargoing 74 target_peer.send(signed_packet_bytes)
9987-embargoing 75 elif message.command == BROADCAST or message.command == IGNORE:
9986-rebroadcast-... 76
9986-rebroadcast-... 77 if message.message_bytes and message_bytes != message_bytes:
9986-rebroadcast-... 78 logging.debug("aborting send: message modified by station!")
9986-rebroadcast-... 79 return
9986-rebroadcast-... 80
9987-embargoing 81 for peer in self.state.get_keyed_peers():
9987-embargoing 82
9987-embargoing 83
9987-embargoing 84 if message.peer and (peer.peer_id == message.peer.peer_id):
9986-rebroadcast-... 85 continue
9987-embargoing 86
9987-embargoing 87 signed_packet_bytes = self.pack(peer, message, message_bytes)
9987-embargoing 88 peer.send(signed_packet_bytes)
genesis 89 else:
9987-embargoing 90 pass
9987-embargoing 91
9987-embargoing 92 def get_message_bytes(self, message, peer=None):
9987-embargoing 93 timestamp = message.timestamp
9987-embargoing 94 command = message.command
9987-embargoing 95 speaker = self._pad(message.speaker, MAX_SPEAKER_SIZE)
genesis 96
genesis 97
genesis 98
genesis 99
9990-keep-ephemer... 100 if message.original:
genesis 101 if command == DIRECT:
9987-embargoing 102 self_chain = self.state.get_last_message_hash(message.speaker, peer.peer_id)
genesis 103 elif command == BROADCAST:
9987-embargoing 104 self_chain = self.state.get_last_message_hash(message.speaker)
9990-keep-ephemer... 105 elif command == IGNORE:
9990-keep-ephemer... 106 self_chain = "\x00" * 32
genesis 107 net_chain = "\x00" * 32
genesis 108 else:
9990-keep-ephemer... 109 self_chain = message.self_chain
9990-keep-ephemer... 110 net_chain = message.net_chain
genesis 111
genesis 112
genesis 113
9987-embargoing 114 if message.command != IGNORE:
9987-embargoing 115 logging.debug("packing message bytes: %s" % message.body)
9987-embargoing 116 else:
9987-embargoing 117 logging.debug("packing rubbish message bytes: %s" % binascii.hexlify(message.body))
9987-embargoing 118
9987-embargoing 119 message_bytes = struct.pack(MESSAGE_PACKET_FORMAT, message.timestamp, self_chain, net_chain, speaker, message.body)
9988-hash-dedup 120 return message_bytes
genesis 121
9987-embargoing 122 def pack(self, peer, message, message_bytes):
9988-hash-dedup 123 key_bytes = base64.b64decode(peer.get_key())
9988-hash-dedup 124 signing_key = key_bytes[:32]
9988-hash-dedup 125 cipher_key = key_bytes[32:]
genesis 126
genesis 127
genesis 128
genesis 129 nonce = self._generate_nonce(16)
9990-keep-ephemer... 130 bounces = message.bounces
genesis 131 version = 0xfe
9988-hash-dedup 132 red_packet_bytes = struct.pack(RED_PACKET_FORMAT, nonce, bounces, version, message.command, self._pad(message_bytes, MAX_MESSAGE_LENGTH))
genesis 133
genesis 134
genesis 135
genesis 136 serpent = Serpent(cipher_key)
genesis 137 black_packet_bytes = serpent_cbc_encrypt(cipher_key, red_packet_bytes)
genesis 138
genesis 139
genesis 140
genesis 141 signature_bytes = hmac.new(signing_key, black_packet_bytes, hashlib.sha384).digest()
genesis 142
genesis 143
genesis 144
genesis 145 signed_packet_bytes = struct.pack(BLACK_PACKET_FORMAT, black_packet_bytes, signature_bytes)
genesis 146
genesis 147 return signed_packet_bytes
genesis 148
genesis 149 def unpack(self, peer, black_packet):
genesis 150
genesis 151
genesis 152 key_bytes = base64.b64decode(peer.get_key())
genesis 153 signing_key = key_bytes[:32]
genesis 154 cipher_key = key_bytes[32:]
genesis 155
genesis 156 try:
genesis 157 black_packet_bytes, signature_bytes = struct.unpack(BLACK_PACKET_FORMAT, black_packet)
genesis 158 except:
9987-embargoing 159 logging.error("Discarding malformed black packet from %s" % peer.get_key())
9987-embargoing 160 return Message({ "error_code": MALFORMED_PACKET })
genesis 161
genesis 162
genesis 163
genesis 164 signature_check_bytes = hmac.new(signing_key, black_packet_bytes, hashlib.sha384).digest()
genesis 165
genesis 166 if(signature_check_bytes != signature_bytes):
9987-embargoing 167 return Message({ "error_code": INVALID_SIGNATURE })
genesis 168
genesis 169
genesis 170
genesis 171 serpent = Serpent(cipher_key)
genesis 172 red_packet_bytes = serpent_cbc_decrypt(cipher_key, black_packet_bytes)
genesis 173
genesis 174
genesis 175
genesis 176 nonce, bounces, version, command, message_bytes = struct.unpack(RED_PACKET_FORMAT, red_packet_bytes)
genesis 177
9987-embargoing 178
9987-embargoing 179
9987-embargoing 180 message_hash = binascii.hexlify(hashlib.sha256(message_bytes).digest())
9987-embargoing 181
genesis 182
genesis 183
9987-embargoing 184 int_ts, self_chain, net_chain, speaker, body = struct.unpack(MESSAGE_PACKET_FORMAT, message_bytes)
9987-embargoing 185
9987-embargoing 186
9987-embargoing 187
9987-embargoing 188 for index, byte in enumerate(speaker):
9987-embargoing 189 if byte == '\x00':
9987-embargoing 190 speaker = speaker[0:index]
9987-embargoing 191 break
9987-embargoing 192
9987-embargoing 193
9987-embargoing 194
9987-embargoing 195 for index, byte in enumerate(body):
9987-embargoing 196 if byte == '\x00':
9987-embargoing 197 body = body[0:index]
9987-embargoing 198 break
9989-show-wot-nicks 199
9989-show-wot-nicks 200
9989-show-wot-nicks 201
9989-show-wot-nicks 202 if command == IGNORE:
9989-show-wot-nicks 203 return Message({"speaker": speaker, "error_code": IGNORED})
9989-show-wot-nicks 204
genesis 205
genesis 206
genesis 207 if(int_ts not in self._ts_range()):
9987-embargoing 208 return Message({ "error_code": STALE_PACKET })
genesis 209
genesis 210
genesis 211
genesis 212 if command == DIRECT:
9987-embargoing 213 self_chain_check = self.state.get_last_message_hash(speaker, peer.peer_id)
genesis 214 elif command == BROADCAST:
9987-embargoing 215 self_chain_check = self.state.get_last_message_hash(speaker)
genesis 216
genesis 217 self_chain_valid = (self_chain_check == self_chain)
genesis 218
genesis 219
genesis 220
9987-embargoing 221 self.state.log(speaker, message_bytes, peer if (command == DIRECT) else None)
genesis 222
9987-embargoing 223
genesis 224
9987-embargoing 225 message = Message({
9990-keep-ephemer... 226 "peer": peer,
9987-embargoing 227 "body": body.rstrip(),
9990-keep-ephemer... 228 "timestamp": int_ts,
9990-keep-ephemer... 229 "command": command,
9990-keep-ephemer... 230 "speaker": speaker,
9990-keep-ephemer... 231 "bounces": bounces,
9990-keep-ephemer... 232 "self_chain": self_chain,
9990-keep-ephemer... 233 "net_chain": net_chain,
9990-keep-ephemer... 234 "self_chain_valid": self_chain_valid,
9986-rebroadcast-... 235 "message_hash": message_hash,
9986-rebroadcast-... 236 "message_bytes": message_bytes
9987-embargoing 237 })
9987-embargoing 238
9987-embargoing 239
9987-embargoing 240
9987-embargoing 241 if(self.state.is_duplicate_message(message_hash)):
9987-embargoing 242 message.error_code = DUPLICATE_PACKET
9987-embargoing 243 return message
9987-embargoing 244
9987-embargoing 245 return message
genesis 246
genesis 247 def _pad(self, text, size):
9987-embargoing 248 return text.ljust(size, "\x00")
genesis 249
genesis 250 def _ts_range(self):
genesis 251 current_ts = int(time.time())
genesis 252 return range(current_ts - TS_ACCEPTABLE_SKEW, current_ts + TS_ACCEPTABLE_SKEW)
genesis 253
genesis 254 def _generate_nonce(self, length=8):
genesis 255 """Generate pseudorandom number."""
genesis 256 return ''.join([str(random.randint(0, 9)) for i in range(length)])
9990-keep-ephemer... 257
9990-keep-ephemer... 258 def gen_rubbish_body(self):
9990-keep-ephemer... 259 return os.urandom(MAX_MESSAGE_LENGTH)