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