def doshit(): IV_LENGTH = 16 HMAC_KEY_LENGTH = 32 AES_KEY_LENGTH = 16 HMACKey = mycrypto.strong_random(HMAC_KEY_LENGTH) AESKey = mycrypto.strong_random(AES_KEY_LENGTH) IV = mycrypto.strong_random(IV_LENGTH) state = mycrypto.strong_random(112) aes = AES.new(AESKey, mode=AES.MODE_CBC, IV=IV) encrypted = mycrypto.strong_random(80) cryptedState = aes.encrypt(state) # Authenticate ticket name, IV and the encrypted state. hmac = HMAC.new(HMACKey, IV + \ cryptedState, digestmod=SHA256).digest() ticket = IV + cryptedState + hmac hmac = HMAC.new(HMACKey, ticket, digestmod=SHA256).digest() # Decrypt ticket to obtain state. aes = AES.new(AESKey, mode=AES.MODE_CBC, IV=ticket[0:16]) plainTicket = aes.decrypt(ticket)
def _getSessionTicket(self, circuit): log.debug("Generating new session ticket and master key.") nextMasterKey = mycrypto.strong_random(const.MASTER_KEY_SIZE) ticket = sessionticket.new(nextMasterKey) rawTicket = ticket.issue() return rawTicket, nextMasterKey
def rotateKeys( ): log.debug("Rotating session ticket keys.") global HMACKey global AESKey global creationTime HMACKey = mycrypto.strong_random(HMAC_KEY_LENGTH) AESKey = mycrypto.strong_random(AES_KEY_LENGTH) creationTime = int(time.time()) try: with open(const.DATA_DIRECTORY + const.KEY_STORE, "wb") as fd: pickle.dump([creationTime, HMACKey, AESKey], fd) fd.close() except IOError as e: log.error("Error opening ticket key file: %s." % e)
def rotateKeys(): log.debug("Rotating session ticket keys.") global HMACKey global AESKey global creationTime HMACKey = mycrypto.strong_random(HMAC_KEY_LENGTH) AESKey = mycrypto.strong_random(AES_KEY_LENGTH) creationTime = int(time.time()) try: with open(const.DATA_DIRECTORY + const.KEY_STORE, "wb") as fd: pickle.dump([creationTime, HMACKey, AESKey], fd) fd.close() except IOError as e: log.error("Error opening ticket key file: %s." % e)
def handshake(self, circuit): """This function is invoked after a circuit was established. The server generates a time-lock puzzle and sends it to the client. The client does nothing during the handshake.""" log.debug("Entering handshake().") if self.circuit == None: self.circuit = circuit # Only the server is generating and transmitting a puzzle. if self.weAreServer: # Generate master key and derive client -and server key. masterKey = mycrypto.strong_random(const.MASTER_KEY_SIZE) self._deriveSecrets(masterKey) # Append random padding to obfuscate length and transmit blurb. padding = mycrypto.weak_random(random.randint(0, \ const.MAX_PADDING_LENGTH)) log.debug("Sending puzzle with %d-byte of padding." % len(padding)) puzzle, nonce = timelock.encryptPuzzle( \ timelock.generateRawPuzzle(masterKey)) circuit.downstream.write(nonce + puzzle + padding) log.debug("Switching to state ST_WAIT_FOR_TICKET.") self.state = const.ST_WAIT_FOR_TICKET # Send a session ticket to the server (if we have one). elif self.weAreClient: stop = False try: with open(const.DATA_DIRECTORY + const.TICKET_FILE, "rb") as fd: masterKey = fd.read(const.MASTER_KEY_SIZE) ticket = fd.read(const.TICKET_LENGTH) fd.close() except IOError as e: log.error("Could not read session ticket from \"%s\"." % \ (const.DATA_DIRECTORY + const.TICKET_FILE)) stop = True if not stop: log.debug("Trying to redeem session ticket: 0x%s..." % \ ticket.encode('hex')[:10]) self._deriveSecrets(masterKey) padding = mycrypto.weak_random(random.randint(0, \ const.MAX_PADDING_LENGTH)) circuit.downstream.write(ticket + padding) self.redeemedTicket = True # Now start transmitting cover traffic. self.stopCoverTraffic = False reactor.callLater(0, self._sendCoverTraffic, circuit)
def handshake(self, circuit): """This function is invoked after a circuit was established. The server generates a time-lock puzzle and sends it to the client. The client does nothing during the handshake.""" log.debug("Entering handshake().") if self.circuit == None: self.circuit = circuit # Only the server is generating and transmitting a puzzle. if self.weAreServer: # Generate master key and derive client -and server key. masterKey = mycrypto.strong_random(const.MASTER_KEY_SIZE) self._deriveSecrets(masterKey) # Append random padding to obfuscate length and transmit blurb. padding = mycrypto.weak_random(random.randint(0, const.MAX_PADDING_LENGTH)) log.debug("Sending puzzle with %d-byte of padding." % len(padding)) puzzle, nonce = timelock.encryptPuzzle(timelock.generateRawPuzzle(masterKey)) circuit.downstream.write(nonce + puzzle + padding) log.debug("Switching to state ST_WAIT_FOR_TICKET.") self.state = const.ST_WAIT_FOR_TICKET # Send a session ticket to the server (if we have one). elif self.weAreClient: stop = False try: with open(const.DATA_DIRECTORY + const.TICKET_FILE, "rb") as fd: masterKey = fd.read(const.MASTER_KEY_SIZE) ticket = fd.read(const.TICKET_LENGTH) fd.close() except IOError as e: log.error('Could not read session ticket from "%s".' % (const.DATA_DIRECTORY + const.TICKET_FILE)) stop = True if not stop: log.debug("Trying to redeem session ticket: 0x%s..." % ticket.encode("hex")[:10]) self._deriveSecrets(masterKey) padding = mycrypto.weak_random(random.randint(0, const.MAX_PADDING_LENGTH)) circuit.downstream.write(ticket + padding) self.redeemedTicket = True # Now start transmitting cover traffic. self.stopCoverTraffic = False reactor.callLater(0, self._sendCoverTraffic, circuit)
def encryptPuzzle( rawPuzzle ): """Encrypts the given `rawPuzzle' with a randomly chosen and small key and returns the encrypted puzzle together with the nonce used for AES-CTR.""" assert len(rawPuzzle) == const.PUZZLE_LENGTH log.debug("Encrypting raw %d-byte puzzle." % len(rawPuzzle)) nonce = mycrypto.strong_random(const.PUZZLE_NONCE_LENGTH) cntr = Counter.new(128, initial_value=long(nonce.encode('hex'), 16)) key = const.MIN_16BYTE_VALUE + \ random.randint(0, (2 ** const.PUZZLE_OBFUSCATION_KEYSPACE) - 1) cipher = AES.new(util.dump(key), AES.MODE_CTR, counter=cntr) log.debug("Puzzle key=%x, nonce=%s." % (key, nonce.encode('hex'))) return cipher.encrypt(rawPuzzle), nonce
def encryptPuzzle(rawPuzzle): """Encrypts the given `rawPuzzle' with a randomly chosen and small key and returns the encrypted puzzle together with the nonce used for AES-CTR.""" assert len(rawPuzzle) == const.PUZZLE_LENGTH log.debug("Encrypting raw %d-byte puzzle." % len(rawPuzzle)) nonce = mycrypto.strong_random(const.PUZZLE_NONCE_LENGTH) cntr = Counter.new(128, initial_value=long(nonce.encode('hex'), 16)) key = const.MIN_16BYTE_VALUE + \ random.randint(0, (2 ** const.PUZZLE_OBFUSCATION_KEYSPACE) - 1) cipher = AES.new(util.dump(key), AES.MODE_CTR, counter=cntr) log.debug("Puzzle key=%x, nonce=%s." % (key, nonce.encode('hex'))) return cipher.encrypt(rawPuzzle), nonce
def __init__( self, masterKey ): """Initialize a new session ticket which contains `masterKey'. The parameter `symmTicketKey' is used to encrypt the ticket and `hmacTicketKey' is used to authenticate the ticket when issued.""" assert len(masterKey) == const.MASTER_KEY_SIZE checkKeys() # The random name is used to recognize previously issued tickets. #self.keyName = mycrypto.weak_random(NAME_LENGTH) # Initialization vector for AES-CBC. self.IV = mycrypto.strong_random(IV_LENGTH) # The server's actual (encrypted) protocol state. self.state = ProtocolState(masterKey) # AES and HMAC key to protect the ticket. self.symmTicketKey = AESKey self.hmacTicketKey = HMACKey
def __init__(self, masterKey): """Initialize a new session ticket which contains `masterKey'. The parameter `symmTicketKey' is used to encrypt the ticket and `hmacTicketKey' is used to authenticate the ticket when issued.""" assert len(masterKey) == const.MASTER_KEY_SIZE checkKeys() # The random name is used to recognize previously issued tickets. #self.keyName = mycrypto.weak_random(NAME_LENGTH) # Initialization vector for AES-CBC. self.IV = mycrypto.strong_random(IV_LENGTH) # The server's actual (encrypted) protocol state. self.state = ProtocolState(masterKey) # AES and HMAC key to protect the ticket. self.symmTicketKey = AESKey self.hmacTicketKey = HMACKey