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