Esempio n. 1
0
    def blake2b(self, data, addr, server=False):
        # ECDH_AED_accept = None
        addrStr = sts_utility.addrToString(addr)
        proposeResp = sts_utility.deconstructPropose(data)
        # print(STS.STSConnectionStates)
        # if addrStr in STS.STSConnectionStates.keys():
        myECDHPK, myECDHSK = STS.STSConnectionStates[addrStr]['keys']
        # TODO verification
        scalarmult_q = pysodium.crypto_scalarmult_curve25519(
            myECDHSK, proposeResp['K'])
        genericHash = pysodium.crypto_generichash_init(outlen=64)
        genericHash = pysodium.crypto_generichash_update(
            genericHash, scalarmult_q)
        if not server:
            genericHash = pysodium.crypto_generichash_update(
                genericHash, myECDHPK)
            genericHash = pysodium.crypto_generichash_update(
                genericHash, proposeResp['K'])
        else:
            genericHash = pysodium.crypto_generichash_update(
                genericHash, proposeResp['K'])
            genericHash = pysodium.crypto_generichash_update(
                genericHash, myECDHPK)

        genericHash = pysodium.crypto_generichash_final(genericHash, outlen=64)

        STS.STSConnectionStates[addrStr]['session_key'] = genericHash
        # STS.STSConnectionStates[addrStr]['phase'] = 1
        STS.STSConnectionStates[addrStr]['time'] = int(time.time())
Esempio n. 2
0
    def constructSTSResponse(self, mType, addr, exchangeData):
        data = None
        addrStr = sts_utility.addrToString(addr)
        if addrStr in STS.STSConnectionStates.keys():

            if STS.STSConnectionStates[addrStr][
                    'cSuite'] == 1 or STS.STSConnectionStates[addrStr][
                        'cSuite'] == 4:
                nonce = pysodium.randombytes(
                    pysodium.crypto_aead_chacha20poly1305_ietf_NONCEBYTES)
                m = struct.pack('>B', mType) + struct.pack('>I', len(nonce))
                # T = struct.pack('>Q', int(time.time()))
                encrypData = pysodium.crypto_aead_chacha20poly1305_ietf_encrypt(
                    exchangeData, m, nonce,
                    STS.STSConnectionStates[addrStr]['session_key'][:32])
                data = m + nonce + encrypData

            elif STS.STSConnectionStates[addrStr][
                    'cSuite'] == 2 or STS.STSConnectionStates[addrStr][
                        'cSuite'] == 5:
                nonce = pysodium.randombytes(
                    pysodium.crypto_aead_chacha20poly1305_NONCEBYTES)
                m = struct.pack('>B', mType) + struct.pack('>I', len(nonce))
                # T = struct.pack('>Q', int(time.time()))
                encrypData = pysodium.crypto_aead_chacha20poly1305_encrypt(
                    exchangeData, m, nonce,
                    STS.STSConnectionStates[addrStr]['session_key'][:32])
                data = m + nonce + encrypData
        # print(binascii.hexlify(T))
        # print(binascii.hexlify(pysodium.crypto_aead_chacha20poly1305_ietf_decrypt(encrypData, m, nonce, myTX[:32])))
        return data
Esempio n. 3
0
    def send(self, addr, cSuite, nodeData):
        try:
            addrStr = sts_utility.addrToString(addr)
            if addrStr in STS.STSConnectionStates.keys():
                if STS.STSConnectionStates[addrStr]['phase'] == 2:
                    print('send data with the existing session')
                    ECDH_DATA_EX = self.constructSTSResponse(2, addr, nodeData)
                    self.sock.sendto(ECDH_DATA_EX, addr)
                    # self.receive()
                else:
                    self.terminate(addr)

            else:
                print('send data with the new session')
                # myCert, myCertStatus = sts_utility.decodeMyCertificate(self.sock, self.endpoint_address)
                # myEncrypKey, mySignKey = sts_utility.decodeSecretKey()
                if cSuite in [1, 2, 6]:
                    # print('sending ECDH')
                    myECDHPK, myECDHSK = pysodium.crypto_kx_keypair()
                    propose = self.generateProposeECDH(cSuite, myECDHPK,
                                                       self.mySignKey,
                                                       self.myCert,
                                                       self.myCertStatus)
                    STS.STSConnectionStates[addrStr] = {
                        'session_key': None,
                        'phase': 0,
                        'init': True,
                        'data': nodeData,
                        'keys': (myECDHPK, myECDHSK),
                        'cSuite': cSuite,
                        'time': int(time.time())
                    }
                    print('sending PROPOSE')
                    sts_utility.decodeSTSMessage(propose)
                    self.sock.sendto(propose, addr)
                elif cSuite in [3, 4, 5]:
                    propose = self.generateProposeECDH(cSuite, (0).to_bytes(
                        32, byteorder='big'), self.mySignKey, self.myCert,
                                                       self.myCertStatus)
                    STS.STSConnectionStates[addrStr] = {
                        'session_key': None,
                        'phase': 0,
                        'init': True,
                        'data': nodeData,
                        'keys': None,
                        'cSuite': cSuite,
                        'time': int(time.time())
                    }
                    print('sending PROPOSE')
                    sts_utility.decodeSTSMessage(propose)
                    self.sock.sendto(propose, addr)
                # while not STS.STSConnectionStates[addrStr]['phase'] == 2:
                #     self.receive()
                # ECDH_DATA_EX = self.constructSTSResponse(2, addr, nodeData)
                # self.sock.sendto(ECDH_DATA_EX, addr)
                # self.receive()
        except:
            return None
Esempio n. 4
0
    def send(self, addr, cSuite, nodeData):
        try:
            addrStr = sts_utility.addrToString(addr)
            if addrStr in STS.STSConnectionStates.keys():
                if STS.STSConnectionStates[addrStr]['phase'] == 2:
                    print('send data with the existing session')
                    ECDH_DATA_EX = self.constructSTSResponse(2, addr, nodeData)
                    self.sock.sendto(ECDH_DATA_EX, addr)
                    # self.receive()
                else:
                    self.terminate(addr)

            else:
                print('send data with the new session')

                if cSuite in [1, 2]:

                    myECDHPK, myECDHSK = pysodium.crypto_kx_keypair()
                    propose = self.generateProposeECDH(cSuite, myECDHPK,
                                                       self.mySignKey,
                                                       self.myCert,
                                                       self.myCertStatus)
                    STS.STSConnectionStates[addrStr] = {
                        'session_key': None,
                        'phase': 0,
                        'init': True,
                        'data': nodeData,
                        'keys': (myECDHPK, myECDHSK),
                        'cSuite': cSuite,
                        'time': int(time.time())
                    }
                    self.sock.sendto(propose, addr)
                elif cSuite in [3, 4, 5]:
                    propose = self.generateProposeECDH(3, (0).to_bytes(
                        32, byteorder='big'), self.mySignKey, self.myCert,
                                                       self.myCertStatus)
                    STS.STSConnectionStates[addrStr] = {
                        'session_key': None,
                        'phase': 0,
                        'init': True,
                        'data': nodeData,
                        'keys': None,
                        'cSuite': cSuite,
                        'time': int(time.time())
                    }
                    self.sock.sendto(propose, addr)

        except:
            return None
Esempio n. 5
0
 def terminate(self, addr):
     print('=== SEND TERMINATE ===', addr)
     addrStr = sts_utility.addrToString(addr)
     if addrStr not in STS.STSConnectionStates.keys():
         terminate = struct.pack(
             '>BI', 3, len((0).to_bytes(
                 8, byteorder='big'))) + (0).to_bytes(8, byteorder='big')
         self.sock.sendto(terminate, addr)
     elif STS.STSConnectionStates[addrStr]['session_key'] is not None:
         terminate = self.constructSTSResponse(
             3, addr, sts_utility.timestampPacked())
         self.sock.sendto(terminate, addr)
         STS.STSConnectionStates.pop(addrStr)
     else:
         terminate = struct.pack(
             '>BI', 3, len((0).to_bytes(
                 8, byteorder='big'))) + (0).to_bytes(8, byteorder='big')
         self.sock.sendto(terminate, addr)
         STS.STSConnectionStates.pop(addrStr)
Esempio n. 6
0
    def deconstructSTSResponse(self, data, addr):
        # TODO verification
        # m = None
        decrypData = None
        addrStr = sts_utility.addrToString(addr)
        if addrStr in STS.STSConnectionStates.keys():
            cp = 0
            m = struct.pack('>B', data[cp])
            # if data[cp] == 2:
            cp += 1
            nonce_length = data[cp:cp + 4]
            length = struct.unpack('>I', nonce_length)[0]
            m += nonce_length
            cp += 4
            nonce = data[cp:cp + length]
            cp += length
            encrypData = data[cp:]
            if STS.STSConnectionStates[addrStr][
                    'cSuite'] == 1 or STS.STSConnectionStates[addrStr][
                        'cSuite'] == 4:
                try:
                    decrypData = pysodium.crypto_aead_chacha20poly1305_ietf_decrypt(
                        encrypData, m, nonce,
                        STS.STSConnectionStates[addrStr]['session_key'][:32])
                except:
                    decrypData = None

            # TODO suites 2 or 5
            elif STS.STSConnectionStates[addrStr][
                    'cSuite'] == 2 or STS.STSConnectionStates[addrStr][
                        'cSuite'] == 5:
                try:
                    decrypData = pysodium.crypto_aead_chacha20poly1305_decrypt(
                        encrypData, m, nonce,
                        STS.STSConnectionStates[addrStr]['session_key'][:32])
                except:
                    decrypData = None

        return decrypData
Esempio n. 7
0
 def sendBlake2bResp(self, data, addr, cSuite):
     addrStr = sts_utility.addrToString(addr)
     # myCert, myCertStatus = sts_utility.decodeMyCertificate(self.sock, self.endpoint_address)
     # myEncrypKey, mySignKey = sts_utility.decodeSecretKey()
     if cSuite in [1, 2]:
         # print('sending ECDH')
         myECDHPK, myECDHSK = pysodium.crypto_kx_keypair()
         propose = self.generateProposeECDH(cSuite, myECDHPK,
                                            self.mySignKey, self.myCert,
                                            self.myCertStatus)
         # STS.STSConnectionStates[addrStr] = {'session_key': None, 'phase': 0, 'init': True,
         #                                     'keys': (myECDHPK, myECDHSK),
         #                                     'cSuite': cSuite, 'time': int(time.time())}
         STS.STSConnectionStates[addrStr]['keys'] = (myECDHPK, myECDHSK)
         self.blake2b(data, addr, server=True)
         self.sock.sendto(propose, addr)
     elif cSuite == 0:
         myECDHPK, myECDHSK = pysodium.crypto_kx_keypair()
         STS.STSConnectionStates[addrStr]['keys'] = (myECDHPK, myECDHSK)
         propose = self.generateProposeECDH(1, myECDHPK, self.mySignKey,
                                            self.myCert, self.myCertStatus)
         self.sock.sendto(propose, addr)
Esempio n. 8
0
    def receive(self):
        # print(STS.STSConnectionStates)
        data, addr = self.sock.recvfrom(1500)
        print('received STS message')
        sts_utility.decodeSTSMessage(data)
        # TODO Clean STSConnectionStates
        # TODO VALIDATE SUITE DOWNGRADE
        addrStr = sts_utility.addrToString(addr)
        # Received propose
        # Reply propose for actual suite when 0/3 used
        try:
            if addr == self.endpoint_address:
                self.setCertificateStatus(data)

            elif data[0] == 0:
                # propose received as server
                # print(self.verifySTSResponse(data, addr))
                # CLIENT PROPOSE / MULTIPLE PROPOSE
                if addrStr in STS.STSConnectionStates.keys():
                    if self.verifyPropose(data, addr):
                        if STS.STSConnectionStates[addrStr]['phase'] != 0:
                            # pprint.pprint(STS.STSConnectionStates)
                            self.terminate(addr)
                        elif data[1] < STS.STSConnectionStates[addrStr][
                                'cSuite']:
                            self.terminate(addr)
                        elif STS.STSConnectionStates[addrStr]['phase'] == 0:
                            # TODO UPGRADE SUITE IS VALID, NEED TO FIX BELOW
                            # if STS.STSConnectionStates[addrStr]['cSuite'] in [1, 2] and data[1] in [3, 4, 5]:
                            #     self.terminate(addr)
                            if STS.STSConnectionStates[addrStr]['init']:
                                if STS.STSConnectionStates[addrStr][
                                        'cSuite'] in [1, 2]:
                                    # LOWER SUITE CHECKED BEFORE
                                    if STS.STSConnectionStates[addrStr][
                                            'cSuite'] != data[1]:
                                        data = STS.STSConnectionStates[
                                            addrStr]['data']
                                        STS.STSConnectionStates.pop(addrStr)
                                        self.send(addr, data[1], data)
                                        return None, None

                                elif STS.STSConnectionStates[addrStr][
                                        'cSuite'] == 3 and data[1] == 3:
                                    self.terminate(addr)
                            else:
                                if STS.STSConnectionStates[addrStr][
                                        'cSuite'] in [1, 2] and data[1] in [
                                            3, 4, 5
                                        ]:
                                    self.terminate(addr)
                                # if STS.STSConnectionStates[addrStr]['cSuite'] in [1 ,2]:
                                #     if STS.STSConnectionStates[addrStr]['cSuite'] != data[1]:
                                #         self.terminate(addr)

                        else:
                            STS.STSConnectionStates[addrStr]['cSuite'] = data[
                                1]
                            STS.STSConnectionStates[addrStr]['time'] = int(
                                time.time())
                    else:
                        print('=== VERIFICATION FAILED ===', addr)
                        self.terminate(addr)

                # SERVER RECEIVE
                else:
                    if self.verifyPropose(data, addr):
                        # if data[1] == 0:
                        # TODO PROPOSE EXPECTED SUITE

                        if addrStr not in STS.STSConnectionStates.keys():
                            STS.STSConnectionStates[addrStr] = {
                                'session_key': None,
                                'phase': data[0],
                                'init': False,
                                'keys': None,
                                'cSuite': data[1],
                                'time': int(time.time())
                            }
                    else:
                        print('=== VERIFICATION FAILED ===', addr)
                        self.terminate(addr)
                self.negotiate(data, addr)

            elif data[0] == 1:
                if addrStr not in STS.STSConnectionStates.keys():
                    self.terminate(addr)
                elif not self.deconstructSTSResponse(data, addr):
                    self.terminate(addr)
                else:
                    if STS.STSConnectionStates[addrStr]['init']:
                        if STS.STSConnectionStates[addrStr]['phase'] == 1:
                            STS.STSConnectionStates[addrStr]['phase'] = 2
                            ECDH_DATA_EX = self.constructSTSResponse(
                                2, addr,
                                STS.STSConnectionStates[addrStr]['data'])
                            self.sock.sendto(ECDH_DATA_EX, addr)
                        else:
                            self.terminate(addr)

                    else:
                        if STS.STSConnectionStates[addrStr][
                                'phase'] == 0 and STS.STSConnectionStates[
                                    addrStr]['cSuite'] in [1, 2]:
                            STS.STSConnectionStates[addrStr]['phase'] = 1
                            self.negotiate(data, addr)
                        elif STS.STSConnectionStates[addrStr][
                                'phase'] == 0 and STS.STSConnectionStates[
                                    addrStr]['cSuite'] in [4, 5]:
                            STS.STSConnectionStates[addrStr]['phase'] = 1
                            self.negotiate(data, addr)
                        else:
                            self.terminate(addr)

            elif data[0] == 2:
                # TODO VALID DATA EXCHANGE
                if addrStr not in STS.STSConnectionStates.keys():
                    self.terminate(addr)
                elif not self.deconstructSTSResponse(data, addr):
                    self.terminate(addr)
                else:
                    if addrStr in STS.STSConnectionStates.keys():
                        if STS.STSConnectionStates[addrStr]['init']:
                            if STS.STSConnectionStates[addrStr]['phase'] == 2:
                                data_ex_resp = self.deconstructSTSResponse(
                                    data, addr)
                                sts_utility.decodeDHTMessage(data_ex_resp)
                                return data_ex_resp, addr
                            else:
                                self.terminate(addr)
                        else:
                            if STS.STSConnectionStates[addrStr]['phase'] == 2:
                                date_ex_resp = self.deconstructSTSResponse(
                                    data, addr)
                                response = packet.pingResponse(date_ex_resp)
                                ECDH_DATA_EX = self.constructSTSResponse(
                                    2, addr, response)
                                self.sock.sendto(ECDH_DATA_EX, addr)
                    else:
                        self.terminate(addr)

            elif data[0] == 3:
                print('=== TERMINATE RECEIVED ===', addr)
                sts_utility.decodeSTSMessage(data)
                if addrStr in STS.STSConnectionStates.keys():
                    STS.STSConnectionStates.pop(addrStr)
        except:
            self.terminate(addr)
            return None, None

        return None, None
Esempio n. 9
0
    def negotiate(self, data, addr):
        addrStr = sts_utility.addrToString(addr)
        if addrStr in STS.STSConnectionStates.keys():
            # SERVER LOGIC
            if not STS.STSConnectionStates[addrStr]['init']:
                if STS.STSConnectionStates[addrStr]['cSuite'] in [
                        0, 1, 2
                ] and STS.STSConnectionStates[addrStr]['phase'] == 0:
                    self.sendBlake2bResp(
                        data, addr, STS.STSConnectionStates[addrStr]['cSuite'])
                elif STS.STSConnectionStates[addrStr]['cSuite'] in [
                        1, 2
                ] and STS.STSConnectionStates[addrStr]['phase'] == 1:
                    # TODO verify accept
                    # ACCEPT Verify
                    ECDH_AED_accept = self.constructSTSResponse(
                        1, addr, sts_utility.timestampPacked())
                    sts_utility.decodeSTSMessage(ECDH_AED_accept)
                    STS.STSConnectionStates[addrStr]['phase'] = 2
                    self.sock.sendto(ECDH_AED_accept, addr)
                    # self.receive()

                elif STS.STSConnectionStates[addrStr]['cSuite'] in [
                        3, 4, 5
                ] and STS.STSConnectionStates[addrStr]['phase'] == 0:
                    # print('=== GEN PROPOSE SALSA 4 ===')
                    # print(binascii.hexlify(proposeResp['C']['K_E']))
                    salsaMsg = self.salsa20poly1305(data, addr, server=True)
                    if not salsaMsg:
                        self.terminate(addr)
                    else:
                        sts_utility.decodeSTSMessage(salsaMsg)
                        # print(mySalsaSession)
                        self.sock.sendto(salsaMsg, addr)
                        # self.receive()

                elif STS.STSConnectionStates[addrStr]['cSuite'] in [
                        4, 5
                ] and STS.STSConnectionStates[addrStr]['phase'] == 1:
                    STS.STSConnectionStates[addrStr]['phase'] = 2
                    SALSA_AED_accept = self.constructSTSResponse(
                        1, addr, sts_utility.timestampPacked())
                    sts_utility.decodeSTSMessage(SALSA_AED_accept)
                    self.sock.sendto(SALSA_AED_accept, addr)
                    # self.receive()
                else:
                    self.terminate(addr)

            # CLIENT LOGIC
            else:
                if STS.STSConnectionStates[addrStr]['cSuite'] in [
                        1, 2
                ] and STS.STSConnectionStates[addrStr]['phase'] == 0:
                    if STS.STSConnectionStates[addrStr]['session_key'] is None:
                        self.blake2b(data, addr)
                        ECDH_AED_accept = self.constructSTSResponse(
                            1, addr, sts_utility.timestampPacked())
                        print('Sending Accept')
                        sts_utility.decodeSTSMessage(ECDH_AED_accept)
                        STS.STSConnectionStates[addrStr]['phase'] = 1
                        self.sock.sendto(ECDH_AED_accept, addr)
                        # self.receive()

                elif STS.STSConnectionStates[addrStr]['cSuite'] in [3, 4, 5]:
                    # print('=== GEN PROPOSE SALSA 4 ===')
                    # print(binascii.hexlify(proposeResp['C']['K_E']))
                    salsaMsg = self.salsa20poly1305(data, addr)
                    sts_utility.decodeSTSMessage(salsaMsg)
                    # print(mySalsaSession)
                    self.sock.sendto(salsaMsg, addr)
                    # self.receive()
                else:
                    self.terminate(addr)
Esempio n. 10
0
    def salsa20poly1305(self, data, addr, server=False):
        salsaMsg = None
        addrStr = sts_utility.addrToString(addr)
        # myCert, myCertStatus = sts_utility.decodeMyCertificate(self.sock, self.endpoint_address)
        # myEncrypKey, mySignKey = sts_utility.decodeSecretKey()
        if not server:
            if STS.STSConnectionStates[addrStr]['cSuite'] == 3:
                mySalsaSession = pysodium.randombytes(32)
                proposeResp = sts_utility.deconstructPropose(data)
                salsaMsg = self.genProposeSalsa(proposeResp['P'],
                                                proposeResp['C']['K_E'],
                                                mySalsaSession,
                                                self.myEncrypKey,
                                                self.mySignKey, self.myCert,
                                                self.myCertStatus)
                STS.STSConnectionStates[addrStr][
                    'session_key'] = mySalsaSession
                STS.STSConnectionStates[addrStr]['cSuite'] = proposeResp['P']
                STS.STSConnectionStates[addrStr]['time'] = int(time.time())

            elif STS.STSConnectionStates[addrStr]['cSuite'] in [4, 5]:
                STS.STSConnectionStates[addrStr]['phase'] = 1
                salsaMsg = self.constructSTSResponse(
                    1, addr, sts_utility.timestampPacked())
        else:
            proposeReq = sts_utility.deconstructPropose(data)
            if STS.STSConnectionStates[addrStr][
                    'cSuite'] == 3 and STS.STSConnectionStates[addrStr][
                        'phase'] == 0:
                # mySalsaSession = pysodium.randombytes(32)

                salsaMsg = self.genProposeSalsa(4, proposeReq['C']['K_E'],
                                                (0).to_bytes(32,
                                                             byteorder='big'),
                                                self.myEncrypKey,
                                                self.mySignKey, self.myCert,
                                                self.myCertStatus)
                STS.STSConnectionStates[addrStr]['session_key'] = (0).to_bytes(
                    32, byteorder='big')
                STS.STSConnectionStates[addrStr]['cSuite'] = 4
                STS.STSConnectionStates[addrStr]['time'] = int(time.time())
            elif STS.STSConnectionStates[addrStr]['cSuite'] in [
                    4, 5
            ] and STS.STSConnectionStates[addrStr]['phase'] == 0:
                session_key = self.decryptSalsaSession(proposeReq,
                                                       self.myEncrypKey)
                if not session_key:
                    salsaMsg = self.genProposeSalsa(
                        STS.STSConnectionStates[addrStr]['cSuite'],
                        proposeReq['C']['K_E'], (0).to_bytes(32,
                                                             byteorder='big'),
                        self.myEncrypKey, self.mySignKey, self.myCert,
                        self.myCertStatus)
                    STS.STSConnectionStates[addrStr]['session_key'] = (
                        0).to_bytes(32, byteorder='big')
                    STS.STSConnectionStates[addrStr][
                        'cSuite'] = STS.STSConnectionStates[addrStr]['cSuite']
                    STS.STSConnectionStates[addrStr]['time'] = int(time.time())
                else:
                    STS.STSConnectionStates[addrStr][
                        'session_key'] = session_key
                    # STS.STSConnectionStates[addrStr]['phase'] = 1
                    salsaMsg = self.genProposeSalsa(
                        4, proposeReq['C']['K_E'],
                        (0).to_bytes(32, byteorder='big'), self.myEncrypKey,
                        self.mySignKey, self.myCert, self.myCertStatus)
                    STS.STSConnectionStates[addrStr]['cSuite'] = proposeReq[
                        'P']
                    # STS.STSConnectionStates[addrStr]['phase'] = 1
                    STS.STSConnectionStates[addrStr]['time'] = int(time.time())
            # elif STS.STSConnectionStates[addrStr]['cSuite'] in [4, 5] and STS.STSConnectionStates[addrStr][
            #     'phase'] == 1:
            #     STS.STSConnectionStates[addrStr]['phase'] = 2
            #     salsaMsg = self.constructSTSResponse(1, addr, sts_utility.timestampPacked())
            # salsaMsg = self.constructSTSResponse(1, addr, sts_utility.timestampPacked())

        return salsaMsg