Example #1
0
def checkKeys(srvState):
    """
    Check whether the key material for session tickets must be rotated.

    The key material (i.e., AES and HMAC keys for session tickets) contained in
    `srvState' is checked if it needs to be rotated.  If so, the old keys are
    stored and new ones are created.
    """

    assert (srvState.hmacKey is not None) and \
           (srvState.aesKey is not None) and \
           (srvState.keyCreation is not None)

    if (int(time.time()) - srvState.keyCreation) > const.KEY_ROTATION_TIME:
        log.info("Rotating server key material for session tickets.")

        # Save expired keys to be able to validate old tickets.
        srvState.oldAesKey = srvState.aesKey
        srvState.oldHmacKey = srvState.hmacKey

        # Create new key material...
        srvState.aesKey = mycrypto.strongRandom(const.TICKET_AES_KEY_LENGTH)
        srvState.hmacKey = mycrypto.strongRandom(const.TICKET_HMAC_KEY_LENGTH)
        srvState.keyCreation = int(time.time())

        # ...and save it to disk.
        srvState.writeState()
Example #2
0
    def genState( self ):
        """
        Populate all the local variables with values.
        """

        log.info("Generating parameters for the server's state file.")

        # PRNG seed for the client to reproduce the packet and IAT morpher.
        self.prngSeed = mycrypto.strongRandom(const.PRNG_SEED_LENGTH)

        # HMAC and AES key used to encrypt and authenticate tickets.
        self.hmacKey = mycrypto.strongRandom(const.TICKET_HMAC_KEY_LENGTH)
        self.aesKey = mycrypto.strongRandom(const.TICKET_AES_KEY_LENGTH)
        self.keyCreation = int(time.time())

        # The previous HMAC and AES keys.
        self.oldHmacKey = None
        self.oldAesKey = None

        # Replay dictionary for both authentication mechanisms.
        self.replayTracker = replay.Tracker()

        # Distributions for packet lengths and inter arrival times.
        prng = random.Random(self.prngSeed)
        self.pktDist = probdist.new(lambda: prng.randint(const.HDR_LENGTH,
                                                         const.MTU),
                                    seed=self.prngSeed)
        self.iatDist = probdist.new(lambda: prng.random() %
                                    const.MAX_PACKET_DELAY,
                                    seed=self.prngSeed)

        self.writeState()
Example #3
0
def checkKeys( srvState ):
    """
    Check whether the key material for session tickets must be rotated.

    The key material (i.e., AES and HMAC keys for session tickets) contained in
    `srvState' is checked if it needs to be rotated.  If so, the old keys are
    stored and new ones are created.
    """

    assert (srvState.hmacKey is not None) and \
           (srvState.aesKey is not None) and \
           (srvState.keyCreation is not None)

    if (int(time.time()) - srvState.keyCreation) > const.KEY_ROTATION_TIME:
        log.info("Rotating server key material for session tickets.")

        # Save expired keys to be able to validate old tickets.
        srvState.oldAesKey = srvState.aesKey
        srvState.oldHmacKey = srvState.hmacKey

        # Create new key material...
        srvState.aesKey = mycrypto.strongRandom(const.TICKET_AES_KEY_LENGTH)
        srvState.hmacKey = mycrypto.strongRandom(const.TICKET_HMAC_KEY_LENGTH)
        srvState.keyCreation = int(time.time())

        # ...and save it to disk.
        srvState.writeState()
Example #4
0
    def genState(self):
        """
        Populate all the local variables with values.
        """

        log.info("Generating parameters for the server's state file.")

        # PRNG seed for the client to reproduce the packet and IAT morpher.
        self.prngSeed = mycrypto.strongRandom(const.PRNG_SEED_LENGTH)

        # HMAC and AES key used to encrypt and authenticate tickets.
        self.hmacKey = mycrypto.strongRandom(const.TICKET_HMAC_KEY_LENGTH)
        self.aesKey = mycrypto.strongRandom(const.TICKET_AES_KEY_LENGTH)
        self.keyCreation = int(time.time())

        # The previous HMAC and AES keys.
        self.oldHmacKey = None
        self.oldAesKey = None

        # Replay dictionary for both authentication mechanisms.
        self.replayTracker = replay.Tracker()

        # Distributions for packet lengths and inter arrival times.
        prng = random.Random(self.prngSeed)
        self.pktDist = probdist.new(
            lambda: prng.randint(const.HDR_LENGTH, const.MTU),
            seed=self.prngSeed)
        self.iatDist = probdist.new(
            lambda: prng.random() % const.MAX_PACKET_DELAY, seed=self.prngSeed)

        # Fallback UniformDH shared secret.  Only used if the bridge operator
        # did not set `ServerTransportOptions'.
        self.fallbackPassword = os.urandom(const.SHARED_SECRET_LENGTH)

        self.writeState()
Example #5
0
    def createHandshake(self):
        """
        Create and return a ready-to-be-sent UniformDH handshake.

        The returned handshake data includes the public key, pseudo-random
        padding, the mark and the HMAC.  If a UniformDH object has not been
        initialised yet, a new instance is created.
        """

        assert self.sharedSecret is not None

        log.debug("Creating UniformDH handshake message.")

        if self.udh is None:
            self.udh = obfs3_dh.UniformDH()
        publicKey = self.udh.get_public()

        assert (const.MAX_PADDING_LENGTH - const.PUBLIC_KEY_LENGTH) >= 0

        # Subtract the length of the public key to make the handshake on
        # average as long as a redeemed ticket.  That should thwart statistical
        # length-based attacks.
        padding = mycrypto.strongRandom(
            random.randint(0,
                           const.MAX_PADDING_LENGTH - const.PUBLIC_KEY_LENGTH))

        # Add a mark which enables efficient location of the HMAC.
        mark = mycrypto.HMAC_SHA256_128(self.sharedSecret, publicKey)

        # Authenticate the handshake including the current approximate epoch.
        mac = mycrypto.HMAC_SHA256_128(
            self.sharedSecret, publicKey + padding + mark + util.getEpoch())

        return publicKey + padding + mark + mac
Example #6
0
    def createHandshake( self ):
        """
        Create and return a ready-to-be-sent UniformDH handshake.

        The returned handshake data includes the public key, pseudo-random
        padding, the mark and the HMAC.  If a UniformDH object has not been
        initialised yet, a new instance is created.
        """

        assert self.sharedSecret is not None

        log.debug("Creating UniformDH handshake message.")

        if self.udh is None:
            self.udh = obfs3_dh.UniformDH()
        publicKey = self.udh.get_public()

        assert (const.MAX_PADDING_LENGTH - const.PUBLIC_KEY_LENGTH) >= 0

        # Subtract the length of the public key to make the handshake on
        # average as long as a redeemed ticket.  That should thwart statistical
        # length-based attacks.
        padding = mycrypto.strongRandom(random.randint(0,
                                        const.MAX_PADDING_LENGTH -
                                        const.PUBLIC_KEY_LENGTH))

        # Add a mark which enables efficient location of the HMAC.
        mark = mycrypto.HMAC_SHA256_128(self.sharedSecret, publicKey)

        # Authenticate the handshake including the current approximate epoch.
        mac = mycrypto.HMAC_SHA256_128(self.sharedSecret,
                                       publicKey + padding + mark +
                                       util.getEpoch())

        return publicKey + padding + mark + mac
Example #7
0
File: state.py Project: 0xa-cc/pupy
	def genState( self ):
		"""
		Populate all the local variables with values.
		"""

		log.info("Generating parameters for the server's state file.")

		# PRNG seed for the client to reproduce the packet and IAT morpher.
		self.prngSeed = mycrypto.strongRandom(const.PRNG_SEED_LENGTH)

		# HMAC and AES key used to encrypt and authenticate tickets.
		self.hmacKey = mycrypto.strongRandom(const.TICKET_HMAC_KEY_LENGTH)
		self.aesKey = mycrypto.strongRandom(const.TICKET_AES_KEY_LENGTH)
		self.keyCreation = int(time.time())

		# The previous HMAC and AES keys.
		self.oldHmacKey = None
		self.oldAesKey = None

		# Replay dictionary for both authentication mechanisms.
		self.replayTracker = replay.Tracker()

		# Distributions for packet lengths and inter arrival times.
		prng = random.Random(self.prngSeed)
		self.pktDist = probdist.new(lambda: prng.randint(const.HDR_LENGTH,
														 const.MTU),
									seed=self.prngSeed)
		self.iatDist = probdist.new(lambda: prng.random() %
									const.MAX_PACKET_DELAY,
									seed=self.prngSeed)

		# Fallback UniformDH shared secret.  Only used if the bridge operator
		# did not set `ServerTransportOptions'.
		self.fallbackPassword = os.urandom(const.SHARED_SECRET_LENGTH)

		# Unauthenticated connections are closed after having received the
		# following amount of bytes.
		self.closingThreshold = prng.randint(const.MAX_HANDSHAKE_LENGTH,
											 const.MAX_HANDSHAKE_LENGTH * 5)

		self.writeState()
Example #8
0
def issueTicketAndKey(srvState):
    """
    Issue a new session ticket and append it to the according master key.

    The parameter `srvState' contains the key material and is passed on to
    `SessionTicket'.  The returned ticket and key are ready to be wrapped into
    a protocol message with the flag FLAG_NEW_TICKET set.
    """

    log.info("Issuing new session ticket and master key.")
    masterKey = mycrypto.strongRandom(const.MASTER_KEY_LENGTH)
    newTicket = (SessionTicket(masterKey, srvState)).issue()

    return masterKey + newTicket
Example #9
0
def issueTicketAndKey( srvState ):
    """
    Issue a new session ticket and append it to the according master key.

    The parameter `srvState' contains the key material and is passed on to
    `SessionTicket'.  The returned ticket and key are ready to be wrapped into
    a protocol message with the flag FLAG_NEW_TICKET set.
    """

    log.info("Issuing new session ticket and master key.")
    masterKey = mycrypto.strongRandom(const.MASTER_KEY_LENGTH)
    newTicket = (SessionTicket(masterKey, srvState)).issue()

    return masterKey + newTicket
Example #10
0
    def __init__(self):
        # Generate private key
        self.priv_str = mycrypto.strongRandom(self.group_len)
        self.priv = int(binascii.hexlify(self.priv_str), 16)

        # Make the private key even
        flip = self.priv % 2
        self.priv -= flip

        # Generate public key
        self.pub = util.powMod(self.g, self.priv, self.mod)
        if flip == 1:
            self.pub = self.mod - self.pub
        self.pub_str = int_to_bytes(self.pub, self.group_len)

        self.shared_secret = None
Example #11
0
    def createHandshake(self, srvState=None):
        """
        Create and return a ready-to-be-sent UniformDH handshake.

        The returned handshake data includes the public key, pseudo-random
        padding, the mark and the HMAC.  If a UniformDH object has not been
        initialised yet, a new instance is created.
        """

        assert self.sharedSecret is not None

        log.debug("Creating UniformDH handshake message.")

        if self.udh is None:
            self.udh = obfs3_dh.UniformDH()
        publicKey = self.udh.get_public()

        assert (const.MAX_PADDING_LENGTH - const.PUBLIC_KEY_LENGTH) >= 0

        # Subtract the length of the public key to make the handshake on
        # average as long as a redeemed ticket.  That should thwart statistical
        # length-based attacks.
        padding = mycrypto.strongRandom(
            random.randint(0,
                           const.MAX_PADDING_LENGTH - const.PUBLIC_KEY_LENGTH))

        # Add a mark which enables efficient location of the HMAC.
        mark = mycrypto.HMAC_SHA256_128(self.sharedSecret, publicKey)

        if self.echoEpoch is None:
            epoch = util.getEpoch()
        else:
            epoch = self.echoEpoch
            log.debug("Echoing epoch rather than recreating it.")

        # Authenticate the handshake including the current approximate epoch.
        mac = mycrypto.HMAC_SHA256_128(self.sharedSecret,
                                       publicKey + padding + mark + epoch)

        if self.weAreServer and (srvState is not None):
            log.debug("Adding the HMAC authenticating the server's UniformDH "
                      "message to the replay table: %s." % mac.encode('hex'))
            srvState.registerKey(mac)

        return publicKey + padding + mark + mac
Example #12
0
    def createHandshake( self, srvState=None ):
        """
        Create and return a ready-to-be-sent UniformDH handshake.

        The returned handshake data includes the public key, pseudo-random
        padding, the mark and the HMAC.  If a UniformDH object has not been
        initialised yet, a new instance is created.
        """

        assert self.sharedSecret is not None

        log.debug("Creating UniformDH handshake message.")

        if self.udh is None:
            self.udh = obfs3_dh.UniformDH()
        publicKey = self.udh.get_public()

        assert (const.MAX_PADDING_LENGTH - const.PUBLIC_KEY_LENGTH) >= 0

        # Subtract the length of the public key to make the handshake on
        # average as long as a redeemed ticket.  That should thwart statistical
        # length-based attacks.
        padding = mycrypto.strongRandom(random.randint(0,
                                        const.MAX_PADDING_LENGTH -
                                        const.PUBLIC_KEY_LENGTH))

        # Add a mark which enables efficient location of the HMAC.
        mark = mycrypto.HMAC_SHA256_128(self.sharedSecret, publicKey)

        if self.echoEpoch is None:
            epoch = util.getEpoch()
        else:
            epoch = self.echoEpoch
            log.debug("Echoing epoch rather than recreating it.")

        # Authenticate the handshake including the current approximate epoch.
        mac = mycrypto.HMAC_SHA256_128(self.sharedSecret,
                                       publicKey + padding + mark + epoch)

        if self.weAreServer and (srvState is not None):
            log.debug("Adding the HMAC authenticating the server's UniformDH "
                      "message to the replay table: %s." % mac.encode('hex'))
            srvState.registerKey(mac)

        return publicKey + padding + mark + mac
Example #13
0
def createTicketMessage(rawTicket, HMACKey):
    """
    Create and return a ready-to-be-sent ticket authentication message.

    Pseudo-random padding and a mark are added to `rawTicket' and the result is
    then authenticated using `HMACKey' as key for a HMAC.  The resulting
    authentication message is then returned.
    """

    assert len(rawTicket) == const.TICKET_LENGTH
    assert len(HMACKey) == const.TICKET_HMAC_KEY_LENGTH

    # Subtract the length of the ticket to make the handshake on
    # average as long as a UniformDH handshake message.
    padding = mycrypto.strongRandom(
        random.randint(0, const.MAX_PADDING_LENGTH - const.TICKET_LENGTH))

    mark = mycrypto.HMAC_SHA256_128(HMACKey, rawTicket)
    hmac = mycrypto.HMAC_SHA256_128(
        HMACKey, rawTicket + padding + mark + util.getEpoch())

    return rawTicket + padding + mark + hmac
Example #14
0
    def __init__(self, masterKey, srvState):
        """
        The constructor of the `SessionTicket()' class.

        The class variables are initialised and the validity of the symmetric
        keys for the session tickets is checked.
        """

        assert (masterKey is not None) and \
               len(masterKey) == const.MASTER_KEY_LENGTH

        checkKeys(srvState)

        # Initialisation vector for AES-CBC.
        self.IV = mycrypto.strongRandom(const.TICKET_AES_CBC_IV_LENGTH)

        # The server's (encrypted) protocol state.
        self.state = ProtocolState(masterKey)

        # AES and HMAC keys to encrypt and authenticate the ticket.
        self.symmTicketKey = srvState.aesKey
        self.hmacTicketKey = srvState.hmacKey
Example #15
0
    def __init__( self, masterKey, srvState ):
        """
        The constructor of the `SessionTicket()' class.

        The class variables are initialised and the validity of the symmetric
        keys for the session tickets is checked.
        """

        assert (masterKey is not None) and \
               len(masterKey) == const.MASTER_KEY_LENGTH

        checkKeys(srvState)

        # Initialisation vector for AES-CBC.
        self.IV = mycrypto.strongRandom(const.TICKET_AES_CBC_IV_LENGTH)

        # The server's (encrypted) protocol state.
        self.state = ProtocolState(masterKey)

        # AES and HMAC keys to encrypt and authenticate the ticket.
        self.symmTicketKey = srvState.aesKey
        self.hmacTicketKey = srvState.hmacKey
Example #16
0
def createTicketMessage( rawTicket, HMACKey ):
    """
    Create and return a ready-to-be-sent ticket authentication message.

    Pseudo-random padding and a mark are added to `rawTicket' and the result is
    then authenticated using `HMACKey' as key for a HMAC.  The resulting
    authentication message is then returned.
    """

    assert len(rawTicket) == const.TICKET_LENGTH
    assert len(HMACKey) == const.TICKET_HMAC_KEY_LENGTH

    # Subtract the length of the ticket to make the handshake on
    # average as long as a UniformDH handshake message.
    padding = mycrypto.strongRandom(random.randint(0,
                                    const.MAX_PADDING_LENGTH -
                                    const.TICKET_LENGTH))

    mark = mycrypto.HMAC_SHA256_128(HMACKey, rawTicket)

    hmac = mycrypto.HMAC_SHA256_128(HMACKey, rawTicket + padding +
                                    mark + util.getEpoch())

    return rawTicket + padding + mark + hmac
Example #17
0
 def test4_CSPRNG( self ):
     self.failIf(mycrypto.strongRandom(10) == mycrypto.strongRandom(10))
     self.failIf(len(mycrypto.strongRandom(100)) != 100)
Example #18
0
    parser = argparse.ArgumentParser()
    parser.add_argument("ip_addr",
                        type=str,
                        help="The IPv4 address of the "
                        "%s server." % const.TRANSPORT_NAME)
    parser.add_argument("tcp_port",
                        type=int,
                        help="The TCP port of the %s "
                        "server." % const.TRANSPORT_NAME)
    parser.add_argument("ticket_file",
                        type=str,
                        help="The file, the newly "
                        "issued ticket is written to.")
    args = parser.parse_args()

    print "[+] Loading server state file."
    serverState = state.load()

    print "[+] Generating new session ticket."
    masterKey = mycrypto.strongRandom(const.MASTER_KEY_LENGTH)
    ticket = SessionTicket(masterKey, serverState).issue()

    print "[+] Writing new session ticket to `%s'." % args.ticket_file
    tickets = dict()
    server = IPv4Address('TCP', args.ip_addr, args.tcp_port)
    tickets[str(server)] = [int(time.time()), masterKey, ticket]

    util.writeToFile(yaml.dump(tickets), args.ticket_file)

    print "[+] Success."
Example #19
0
# Give ScrambleSuit server operators a way to manually issue new session
# tickets for out-of-band distribution.
if __name__ == "__main__":

    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("ip_addr", type=str, help="The IPv4 address of the "
                        "%s server." % const.TRANSPORT_NAME)
    parser.add_argument("tcp_port", type=int, help="The TCP port of the %s "
                        "server." % const.TRANSPORT_NAME)
    parser.add_argument("ticket_file", type=str, help="The file, the newly "
                        "issued ticket is written to.")
    args = parser.parse_args()

    print "[+] Loading server state file."
    serverState = state.load()

    print "[+] Generating new session ticket."
    masterKey = mycrypto.strongRandom(const.MASTER_KEY_LENGTH)
    ticket = SessionTicket(masterKey, serverState).issue()

    print "[+] Writing new session ticket to `%s'." % args.ticket_file
    tickets = dict()
    server = IPv4Address('TCP', args.ip_addr, args.tcp_port)
    tickets[str(server)] = [int(time.time()), masterKey, ticket]

    util.writeToFile(yaml.dump(tickets), args.ticket_file)

    print "[+] Success."