Пример #1
0
def test_ecies_decrypt():
    tv = test_values
    from devp2p.crypto import ECCx
    e = ECCx(raw_privkey=tv['receiver_private_key'])
    _dec = e.ecies_decrypt(tv['auth_ciphertext'])
    assert len(_dec) == len(tv['auth_plaintext'])
    assert _dec == tv['auth_plaintext']
Пример #2
0
def test_session():
    initiator = RLPxSession(ECCx(raw_privkey=mk_privkey('secret1')),
                            is_initiator=True)
    initiator_pubk = initiator.ecc.raw_pubkey
    responder = RLPxSession(ECCx(raw_privkey=mk_privkey('secret2')))
    responder_pubk = responder.ecc.raw_pubkey

    auth_msg = initiator.create_auth_message(remote_pubkey=responder_pubk)
    auth_msg_ct = initiator.encrypt_auth_message(auth_msg, responder_pubk)

    responder.decode_authentication(auth_msg_ct)
    auth_ack_msg = responder.create_auth_ack_message()
    auth_ack_msg_ct = responder.encrypt_auth_ack_message(
        auth_ack_msg, initiator_pubk)

    initiator.decode_auth_ack_message(auth_ack_msg_ct)

    initiator.setup_cipher()
    responder.setup_cipher()

    assert responder.ecdhe_shared_secret == initiator.ecdhe_shared_secret
    assert responder.token == initiator.token
    assert responder.aes_secret == initiator.aes_secret
    assert responder.mac_secret == initiator.mac_secret

    assert responder.egress_mac.digest() == initiator.ingress_mac.digest()
    assert responder.egress_mac.digest() == initiator.ingress_mac.digest()
    assert responder.ingress_mac.digest() == initiator.egress_mac.digest()
    assert responder.ingress_mac.digest() == initiator.egress_mac.digest()
    assert responder.mac_secret == initiator.mac_secret

    return initiator, responder
Пример #3
0
 def __init__(self, app):
     super(RNOService, self).__init__(app)
     log.info('Initializing RNO')
     self.config = app.config
     self.interrupt = Event()
     self.tx_queue = Queue()  # thread safe
     self.privkey_hex = self.config['eth']['privkey_hex'].decode('hex')
     self.my_addr = privtoaddr(self.privkey_hex)
     self.eccx = ECCx(None, self.privkey_hex)
Пример #4
0
 def __init__(self,
              ecc,
              is_initiator=False,
              token_by_pubkey=dict(),
              ephemeral_privkey=None):
     self.ecc = ecc
     self.is_initiator = is_initiator
     self.token_by_pubkey = token_by_pubkey
     self.ephemeral_ecc = ECCx(raw_privkey=ephemeral_privkey)
Пример #5
0
def test_auth_ack_is_eip8_for_eip8_auth():
    responder = RLPxSession(ECCx(raw_privkey=eip8_values['key_b']))
    responder.decode_authentication(eip8_handshakes[1]['auth'])
    assert responder.got_eip8_auth

    ack = responder.create_auth_ack_message(version=55)
    ack_ct = responder.encrypt_auth_ack_message(ack)

    initiator = RLPxSession(ECCx(raw_privkey=eip8_values['key_a']),
                            is_initiator=True)
    initiator.decode_auth_ack_message(ack_ct)
    assert initiator.got_eip8_ack
    assert initiator.remote_version == 55
Пример #6
0
    def create_auth_message(self,
                            remote_pubkey,
                            token=None,
                            ephemeral_privkey=None,
                            nonce=None):
        """
        1. initiator generates ecdhe-random and nonce and creates auth
        2. initiator connects to remote and sends auth

        New:
        E(remote-pubk,
            S(ephemeral-privk, ecdh-shared-secret ^ nonce) ||
            H(ephemeral-pubk) || pubk || nonce || 0x0
        )
        Known:
        E(remote-pubk,
            S(ephemeral-privk, token ^ nonce) || H(ephemeral-pubk) || pubk || nonce || 0x1)
        """

        if not token:  # new
            ecdh_shared_secret = self.node.get_ecdh_key(remote_pubkey)
            token = ecdh_shared_secret
            flag = 0x0
        else:
            flag = 0x1

        nonce = nonce or ienc(random.randint(0, 2**256 - 1))
        assert len(nonce) == 32

        token_xor_nonce = sxor(token, nonce)
        assert len(token_xor_nonce) == 32

        # generate session ephemeral key
        if not ephemeral_privkey:
            ephemeral_privkey = sha3(ienc(random.randint(0, 2**256 - 1)))

        self.ephemeral_ecc = ECCx(raw_privkey=ephemeral_privkey)
        ephemeral_pubkey = self.ephemeral_ecc.raw_pubkey

        assert len(ephemeral_pubkey) == 512 / 8
        # S(ephemeral-privk, ecdh-shared-secret ^ nonce)
        S = self.ephemeral_ecc.sign(token_xor_nonce)
        assert len(S) == 65

        # S || H(ephemeral-pubk) || pubk || nonce || 0x0
        auth_message = S + sha3(
            ephemeral_pubkey) + self.node.raw_pubkey + nonce + chr(flag)
        assert len(auth_message) == 65 + 32 + 64 + 32 + 1 == 194
        return auth_message
Пример #7
0
def test_pyelliptic_sig():
    priv_seed = 'test'
    priv_key = mk_privkey(priv_seed)
    my_pubkey = privtopub(priv_key)
    e = ECCx(my_pubkey, priv_key)
    msg = 'a'
    s = pyelliptic.ECC.sign(e, msg)
    assert s == pyelliptic.ECC.sign(e, msg)  # deterministic
Пример #8
0
 def __init__(self, app):
     super(RNOService, self).__init__(app)
     log.info('Initializing RNO')
     self.config = app.config
     self.interrupt = Event()
     self.tx_queue = Queue()  # thread safe
     self.privkey_hex = self.config['eth']['privkey_hex'].decode('hex')
     self.my_addr = privtoaddr(self.privkey_hex)
     self.eccx = ECCx(None, self.privkey_hex)
Пример #9
0
def test_eip8_handshake_messages():
    initiator = RLPxSession(ECCx(raw_privkey=eip8_values['key_a']),
                            is_initiator=True)
    responder = RLPxSession(ECCx(raw_privkey=eip8_values['key_b']))
    for handshake in eip8_handshakes:
        ack_rest = initiator.decode_auth_ack_message(handshake['ack'])
        assert initiator.remote_ephemeral_pubkey == eip8_values['eph_pub_b']
        assert initiator.responder_nonce == eip8_values['nonce_b']
        assert initiator.got_eip8_ack == handshake['eip8_format']
        assert initiator.remote_version == handshake['ack_version']
        assert ack_rest == b''

        auth_rest = responder.decode_authentication(handshake['auth'])
        assert responder.remote_ephemeral_pubkey == eip8_values['eph_pub_a']
        assert responder.initiator_nonce == eip8_values['nonce_a']
        assert responder.remote_pubkey == eip8_values['pub_a']
        assert responder.got_eip8_auth == handshake['eip8_format']
        assert auth_rest == b''
Пример #10
0
def test_pyelliptic_sig():
    priv_seed = 'test'
    priv_key = mk_privkey(priv_seed)
    my_pubkey = privtopub(priv_key)
    e = ECCx(raw_privkey=priv_key)
    msg = 'a'
    s = pyelliptic.ECC.sign(e, msg)
    s2 = pyelliptic.ECC.sign(e, msg)
    assert s != s2  # non deterministic
Пример #11
0
class LocalNode(object):
    def __init__(self, privkey):
        self.ecc = ECCx(raw_privkey=privkey)

    @property
    def pubkey(self):
        return self.ecc.pubkey_x + self.ecc.pubkey_y

    def sign(self, data):
        return self.ecc.sign(data)
Пример #12
0
def test_eip8_key_derivation():
    responder = RLPxSession(ECCx(raw_privkey=eip8_values['key_b']),
                            ephemeral_privkey=eip8_values['eph_key_b'])
    responder.decode_authentication(eip8_handshakes[1]['auth'])
    ack = responder.create_auth_ack_message(nonce=eip8_values['nonce_b'])
    responder.encrypt_auth_ack_message(ack)

    responder.setup_cipher()
    want_aes_secret = decode_hex(
        b'80e8632c05fed6fc2a13b0f8d31a3cf645366239170ea067065aba8e28bac487')
    want_mac_secret = decode_hex(
        b'2ea74ec5dae199227dff1af715362700e989d889d7a493cb0639691efb8e5f98')
    assert responder.aes_secret == want_aes_secret
    assert responder.mac_secret == want_mac_secret

    responder.ingress_mac.update(b'foo')
    mac_digest = responder.ingress_mac.digest()
    want_mac_digest = decode_hex(
        b'0c7ec6340062cc46f5e9f1e3cf86f8c8c403c5a0964f5df0ebd34a75ddc86db5')
    assert mac_digest == want_mac_digest
Пример #13
0
class RLPxSession(object):

    ephemeral_ecc = None
    remote_ephemeral_pubkey = None
    initiator_nonce = None
    responder_nonce = None
    auth_init = None
    auth_ack = None
    aes_secret = None
    token = None
    aes_enc = None
    aes_dec = None
    mac_enc = None
    egress_mac = None
    ingress_mac = None
    is_ready = False
    remote_token_found = False
    remote_pubkey = None
    auth_message_length = 194
    auth_message_ct_length = auth_message_length + ECCx.ecies_encrypt_overhead_length
    auth_ack_message_length = 97
    auth_ack_message_ct_length = auth_ack_message_length + ECCx.ecies_encrypt_overhead_length

    def __init__(self,
                 ecc,
                 is_initiator=False,
                 token_by_pubkey=dict(),
                 ephemeral_privkey=None):
        self.ecc = ecc
        self.is_initiator = is_initiator
        self.token_by_pubkey = token_by_pubkey
        self.ephemeral_ecc = ECCx(raw_privkey=ephemeral_privkey)

    def encrypt(self, header, frame):
        """
        # https://github.com/ethereum/go-ethereum/blob/develop/p2p/rlpx.go
        # https://github.com/ethereum/cpp-ethereum/blob/develop/libp2p/RLPxFrameIO.cpp
        """
        assert self.is_ready is True
        assert len(header) == 16
        assert len(frame) % 16 == 0

        def aes(data=''):
            return self.aes_enc.update(data)

        def mac(data=''):
            self.egress_mac.update(data)
            return self.egress_mac.digest()

        # header
        header_ciphertext = aes(header)
        assert len(header_ciphertext) == 16
        # egress-mac.update(aes(mac-secret,egress-mac) ^ header-ciphertext).digest
        header_mac = mac(sxor(self.mac_enc(mac()[:16]),
                              header_ciphertext))[:16]

        # frame
        frame_ciphertext = aes(frame)
        assert len(frame_ciphertext) == len(frame)
        # egress-mac.update(aes(mac-secret,egress-mac) ^
        # left128(egress-mac.update(frame-ciphertext).digest))
        fmac_seed = mac(frame_ciphertext)
        frame_mac = mac(sxor(self.mac_enc(mac()[:16]), fmac_seed[:16]))[:16]

        return header_ciphertext + header_mac + frame_ciphertext + frame_mac

    def decrypt_header(self, data):
        assert self.is_ready is True
        assert len(data) == 32

        def aes(data=''):
            return self.aes_dec.update(data)

        def mac(data=''):
            self.ingress_mac.update(data)
            return self.ingress_mac.digest()

        header_ciphertext = data[:16]
        header_mac = data[16:32]

        # FIXME: how to restore mac if i received invalid data?

        # ingress-mac.update(aes(mac-secret,ingress-mac) ^ header-ciphertext).digest
        expected_header_mac = mac(
            sxor(self.mac_enc(mac()[:16]), header_ciphertext))[:16]
        # expected_header_mac = self.updateMAC(self.ingress_mac, header_ciphertext)
        if not expected_header_mac == header_mac:
            raise AuthenticationError('invalid header mac')
        return aes(header_ciphertext)

    def decrypt_body(self, data, body_size):
        assert self.is_ready is True

        def aes(data=''):
            return self.aes_dec.update(data)

        def mac(data=''):
            self.ingress_mac.update(data)
            return self.ingress_mac.digest()

        # frame-size: 3-byte integer size of frame, big endian encoded (excludes padding)
        # frame relates to body w/o padding w/o mac

        read_size = ceil16(body_size)
        if not len(data) >= read_size + 16:
            raise FormatError('insufficient body length')

        # FIXME check frame length in header
        # assume datalen == framelen for now
        frame_ciphertext = data[:read_size]
        frame_mac = data[read_size:read_size + 16]
        assert len(frame_mac) == 16

        # ingres-mac.update(aes(mac-secret,ingres-mac) ^
        # left128(ingres-mac.update(frame-ciphertext).digest))
        fmac_seed = mac(frame_ciphertext)
        expected_frame_mac = mac(sxor(self.mac_enc(mac()[:16]),
                                      fmac_seed[:16]))[:16]
        if not frame_mac == expected_frame_mac:
            raise AuthenticationError('invalid frame mac')
        return aes(frame_ciphertext)[:body_size]

    def decrypt(self, data):
        header = self.decrypt_header(data[:32])
        body_size = struct.unpack('>I', '\x00' + header[:3])[0]
        if not len(data) >= 32 + ceil16(body_size) + 16:
            raise FormatError('insufficient body length')
        frame = self.decrypt_body(data[32:], body_size)
        return dict(header=header,
                    frame=frame,
                    bytes_read=32 + ceil16(len(frame)) + 16)

    def create_auth_message(self,
                            remote_pubkey,
                            ephemeral_privkey=None,
                            nonce=None):
        """
        1. initiator generates ecdhe-random and nonce and creates auth
        2. initiator connects to remote and sends auth

        New:
        E(remote-pubk,
            S(ephemeral-privk, ecdh-shared-secret ^ nonce) ||
            H(ephemeral-pubk) || pubk || nonce || 0x0
        )
        Known:
        E(remote-pubk,
            S(ephemeral-privk, token ^ nonce) || H(ephemeral-pubk) || pubk || nonce || 0x1)
        """
        assert self.is_initiator
        if not self.ecc.is_valid_key(remote_pubkey):
            raise InvalidKeyError('invalid remote pubkey')
        self.remote_pubkey = remote_pubkey

        token = self.token_by_pubkey.get(remote_pubkey)
        if not token:  # new
            ecdh_shared_secret = self.ecc.get_ecdh_key(remote_pubkey)
            token = ecdh_shared_secret
            flag = 0x0
        else:
            flag = 0x1

        self.initiator_nonce = nonce or sha3(
            ienc(random.randint(0, 2**256 - 1)))
        assert len(self.initiator_nonce) == 32

        token_xor_nonce = sxor(token, self.initiator_nonce)
        assert len(token_xor_nonce) == 32

        ephemeral_pubkey = self.ephemeral_ecc.raw_pubkey
        assert len(ephemeral_pubkey) == 512 / 8
        if not self.ecc.is_valid_key(ephemeral_pubkey):
            raise InvalidKeyError('invalid ephemeral pubkey')

        # S(ephemeral-privk, ecdh-shared-secret ^ nonce)
        S = self.ephemeral_ecc.sign(token_xor_nonce)
        assert len(S) == 65

        # S || H(ephemeral-pubk) || pubk || nonce || 0x0
        auth_message = S + sha3(ephemeral_pubkey) + self.ecc.raw_pubkey + \
            self.initiator_nonce + chr(flag)
        assert len(auth_message) == 65 + 32 + 64 + 32 + 1 == 194
        return auth_message

    def encrypt_auth_message(self, auth_message, remote_pubkey=None):
        assert self.is_initiator
        remote_pubkey = remote_pubkey or self.remote_pubkey
        self.auth_init = self.ecc.ecies_encrypt(auth_message, remote_pubkey)
        assert len(self.auth_init) == self.auth_message_ct_length
        return self.auth_init

    def encrypt_auth_ack_message(self, auth_message, remote_pubkey=None):
        assert not self.is_initiator
        remote_pubkey = remote_pubkey or self.remote_pubkey
        self.auth_ack = self.ecc.ecies_encrypt(auth_message, remote_pubkey)
        assert len(self.auth_ack) == self.auth_ack_message_ct_length
        return self.auth_ack

    def decode_authentication(self, ciphertext):
        """
        3. optionally, remote decrypts and verifies auth
            (checks that recovery of signature == H(ephemeral-pubk))
        4. remote generates authAck from remote-ephemeral-pubk and nonce
            (authAck = authRecipient handshake)

        optional: remote derives secrets and preemptively sends protocol-handshake (steps 9,11,8,10)
        """
        assert not self.is_initiator

        self.auth_init = ciphertext
        try:
            auth_message = self.ecc.ecies_decrypt(ciphertext)
        except RuntimeError as e:
            raise AuthenticationError(e)

        # S || H(ephemeral-pubk) || pubk || nonce || 0x[0|1]
        assert len(
            auth_message
        ) == 65 + 32 + 64 + 32 + 1 == 194 == self.auth_message_length
        signature = auth_message[:65]
        H_initiator_ephemeral_pubkey = auth_message[65:65 + 32]
        initiator_pubkey = auth_message[65 + 32:65 + 32 + 64]
        if not self.ecc.is_valid_key(initiator_pubkey):
            raise InvalidKeyError('invalid initiator pubkey')
        self.remote_pubkey = initiator_pubkey
        self.initiator_nonce = auth_message[65 + 32 + 64:65 + 32 + 64 + 32]
        known_flag = bool(ord(auth_message[65 + 32 + 64 + 32:]))

        # token or new ecdh_shared_secret
        if known_flag:
            self.remote_token_found = True
            # what todo if remote has token, but local forgot it.
            #   reply with token not found. FIXME!!!
            token = self.token_by_pubkey.get(initiator_pubkey)
            assert token  # FIXME continue session with ecdh_key and send flag in auth_ack
        else:
            token = self.ecc.get_ecdh_key(initiator_pubkey)

        # verify auth
        # S(ephemeral-privk, ecdh-shared-secret ^ nonce)
        signed = sxor(token, self.initiator_nonce)

        # recover initiator ephemeral pubkey
        self.remote_ephemeral_pubkey = ecdsa_recover(signed, signature)
        if not self.ecc.is_valid_key(self.remote_ephemeral_pubkey):
            raise InvalidKeyError('invalid remote ephemeral pubkey')
        if not ecdsa_verify(self.remote_ephemeral_pubkey, signature, signed):
            raise AuthenticationError('could not verify signature')

        # checks that recovery of signature == H(ephemeral-pubk)
        assert H_initiator_ephemeral_pubkey == sha3(
            self.remote_ephemeral_pubkey)

    def create_auth_ack_message(self,
                                ephemeral_pubkey=None,
                                nonce=None,
                                token_found=False):
        """
        authRecipient = E(remote-pubk, remote-ephemeral-pubk || nonce || 0x1) // token found
        authRecipient = E(remote-pubk, remote-ephemeral-pubk || nonce || 0x0) // token not found

        nonce and empehemeral-pubk are local!
        """
        assert not self.is_initiator
        ephemeral_pubkey = ephemeral_pubkey or self.ephemeral_ecc.raw_pubkey
        self.responder_nonce = nonce or sha3(
            ienc(random.randint(0, 2**256 - 1)))

        flag = chr(1 if token_found else 0)
        msg = ephemeral_pubkey + self.responder_nonce + flag
        assert len(msg) == 64 + 32 + 1 == 97 == self.auth_ack_message_length
        return msg

    def decode_auth_ack_message(self, ciphertext):
        assert self.is_initiator
        self.auth_ack = ciphertext
        auth_ack_message = self.ecc.ecies_decrypt(ciphertext)
        assert len(auth_ack_message) == 64 + 32 + 1
        self.remote_ephemeral_pubkey = auth_ack_message[:64]
        if not self.ecc.is_valid_key(self.remote_ephemeral_pubkey):
            raise InvalidKeyError('invalid remote ephemeral pubkey')
        self.responder_nonce = auth_ack_message[64:64 + 32]
        self.remote_token_found = bool(ord(auth_ack_message[-1]))

    def setup_cipher(self):
        # https://github.com/ethereum/cpp-ethereum/blob/develop/libp2p/RLPxFrameIO.cpp#L34
        assert self.responder_nonce
        assert self.initiator_nonce
        assert self.auth_init
        assert self.auth_ack
        assert self.remote_ephemeral_pubkey
        if not self.ecc.is_valid_key(self.remote_ephemeral_pubkey):
            raise InvalidKeyError('invalid remote ephemeral pubkey')

        # derive base secrets from ephemeral key agreement
        # ecdhe-shared-secret = ecdh.agree(ephemeral-privkey, remote-ephemeral-pubk)
        ecdhe_shared_secret = self.ephemeral_ecc.get_ecdh_key(
            self.remote_ephemeral_pubkey)

        # shared-secret = sha3(ecdhe-shared-secret || sha3(nonce || initiator-nonce))
        shared_secret = sha3(ecdhe_shared_secret +
                             sha3(self.responder_nonce + self.initiator_nonce))

        self.ecdhe_shared_secret = ecdhe_shared_secret  # FIXME DEBUG
        self.shared_secret = shared_secret  # FIXME DEBUG

        # token = sha3(shared-secret)
        self.token = sha3(shared_secret)
        self.token_by_pubkey[self.remote_pubkey] = self.token

        # aes-secret = sha3(ecdhe-shared-secret || shared-secret)
        self.aes_secret = sha3(ecdhe_shared_secret + shared_secret)

        # mac-secret = sha3(ecdhe-shared-secret || aes-secret)
        self.mac_secret = sha3(ecdhe_shared_secret + self.aes_secret)

        # setup sha3 instances for the MACs
        # egress-mac = sha3.update(mac-secret ^ recipient-nonce || auth-sent-init)
        mac1 = sha3_256(
            sxor(self.mac_secret, self.responder_nonce) + self.auth_init)
        # ingress-mac = sha3.update(mac-secret ^ initiator-nonce || auth-recvd-ack)
        mac2 = sha3_256(
            sxor(self.mac_secret, self.initiator_nonce) + self.auth_ack)

        if self.is_initiator:
            self.egress_mac, self.ingress_mac = mac1, mac2
        else:
            self.egress_mac, self.ingress_mac = mac2, mac1

        ciphername = 'aes-256-ctr'
        iv = "\x00" * 16
        assert len(iv) == 16
        self.aes_enc = pyelliptic.Cipher(self.aes_secret,
                                         iv,
                                         1,
                                         ciphername=ciphername)
        self.aes_dec = pyelliptic.Cipher(self.aes_secret,
                                         iv,
                                         0,
                                         ciphername=ciphername)
        self.mac_enc = AES.AESCipher(self.mac_secret, AES.MODE_ECB).encrypt

        self.is_ready = True
def test_handshake():
    tv = test_values

    initiator = RLPxSession(ECCx(raw_privkey=tv['initiator_private_key']),
                            is_initiator=True,
                            ephemeral_privkey=tv['initiator_ephemeral_private_key'])
    initiator_pubkey = initiator.ecc.raw_pubkey
    responder = RLPxSession(ECCx(raw_privkey=tv['receiver_private_key']),
                            ephemeral_privkey=tv['receiver_ephemeral_private_key'])
    responder_pubkey = responder.ecc.raw_pubkey

    # test encryption
    _enc = initiator.encrypt_auth_message(tv['auth_plaintext'], responder_pubkey)
    assert len(_enc) == len(tv['auth_ciphertext'])
    assert len(tv['auth_ciphertext']) == 113 + len(tv['auth_plaintext'])  # len

    # test auth_msg plain
    auth_msg = initiator.create_auth_message(remote_pubkey=responder_pubkey,
                                             ephemeral_privkey=tv['initiator_ephemeral_private_key'],
                                             nonce=tv['initiator_nonce'])

    # test auth_msg plain
    assert len(auth_msg) == len(tv['auth_plaintext']) == 194
    assert auth_msg[65:] == tv['auth_plaintext'][65:]  # starts with non deterministic k

    _auth_msg_cipher = initiator.encrypt_auth_message(auth_msg, responder_pubkey)

    # test shared
    responder.ecc.get_ecdh_key(initiator_pubkey) == \
        initiator.ecc.get_ecdh_key(responder_pubkey)

    # test decrypt
    assert auth_msg == responder.ecc.ecies_decrypt(_auth_msg_cipher)

    # check receive
    responder_ephemeral_pubkey = privtopub(tv['receiver_ephemeral_private_key'])
    auth_msg_cipher = tv['auth_ciphertext']
    auth_msg = responder.ecc.ecies_decrypt(auth_msg_cipher)
    assert auth_msg[65:] == tv['auth_plaintext'][65:]  # starts with non deterministic k

    responder.decode_authentication(auth_msg_cipher)
    auth_ack_msg = responder.create_auth_ack_message(responder_ephemeral_pubkey, nonce=tv['receiver_nonce'])
    assert auth_ack_msg == tv['authresp_plaintext']
    auth_ack_msg_cipher = responder.encrypt_auth_ack_message(auth_ack_msg, remote_pubkey=responder.remote_pubkey)

    # set auth ack msg cipher (needed later for mac calculation)
    responder.auth_ack = tv['authresp_ciphertext']

    responder.setup_cipher()
    assert responder.ecdhe_shared_secret == tv['ecdhe_shared_secret']
    assert len(responder.token) == len(tv['token'])
    assert responder.token == tv['token']
    assert responder.aes_secret == tv['aes_secret']
    assert responder.mac_secret == tv['mac_secret']

    assert responder.initiator_nonce == tv['initiator_nonce']
    assert responder.responder_nonce == tv['receiver_nonce']

    assert responder.auth_init == tv['auth_ciphertext']
    assert responder.auth_ack == tv['authresp_ciphertext']

    # test values are from initiator perspective?
    assert responder.ingress_mac.digest() == tv['initial_egress_MAC']
    assert responder.ingress_mac.digest() == tv['initial_egress_MAC']
    assert responder.egress_mac.digest() == tv['initial_ingress_MAC']
    assert responder.egress_mac.digest() == tv['initial_ingress_MAC']

    r = responder.decrypt(tv['initiator_hello_packet'])

    # unpack hello packet
    import struct
    import rlp
    import rlp.sedes as sedes
    from rlp.codec import consume_item

    header = r['header']
    frame_length = struct.unpack(b'>I', b'\x00' + header[:3])[0]

    header_sedes = sedes.List([sedes.big_endian_int, sedes.big_endian_int])
    header_data = rlp.decode(header[3:], strict=False, sedes=header_sedes)
    print('header', repr(header_data))

    # frame
    frame = r['frame']

    # normal: rlp(packet-type) [|| rlp(packet-data)] || padding
    packet_type, end = consume_item(frame, start=0)
    packet_type = rlp.decode(frame, sedes=sedes.big_endian_int, strict=False)
    print('packet_type', repr(packet_type))

    # decode hello body
    _sedes_capabilites_tuple = sedes.List([sedes.binary, sedes.big_endian_int])

    structure = [
        ('version', sedes.big_endian_int),
        ('client_version_string', sedes.big_endian_int),
        ('capabilities', sedes.CountableList(_sedes_capabilites_tuple)),
        ('listen_port', sedes.big_endian_int),
        ('remote_pubkey', sedes.binary)
    ]

    hello_sedes = sedes.List([x[1] for x in structure])
    frame_data = rlp.decode(frame[end:], sedes=hello_sedes)
    frame_data = dict((structure[i][0], x) for i, x in enumerate(frame_data))
    print('frame', frame_data)
Пример #15
0
 def __init__(self, ecc, is_initiator=False, token_by_pubkey=dict(), ephemeral_privkey=None):
     self.ecc = ecc
     self.is_initiator = is_initiator
     self.token_by_pubkey = token_by_pubkey
     self.ephemeral_ecc = ECCx(raw_privkey=ephemeral_privkey)
Пример #16
0
class RLPxSession(object):

    ephemeral_ecc = None
    remote_ephemeral_pubkey = None
    initiator_nonce = None
    responder_nonce = None
    auth_init = None
    auth_ack = None
    aes_secret = None
    token = None
    aes_enc = None
    aes_dec = None
    mac_enc = None
    egress_mac = None
    ingress_mac = None
    is_ready = False
    remote_token_found = False
    remote_pubkey = None
    auth_message_length = 194
    auth_message_ct_length = auth_message_length + ECCx.ecies_encrypt_overhead_length
    auth_ack_message_length = 97
    auth_ack_message_ct_length = auth_ack_message_length + ECCx.ecies_encrypt_overhead_length

    def __init__(self, ecc, is_initiator=False, token_by_pubkey=dict(), ephemeral_privkey=None):
        self.ecc = ecc
        self.is_initiator = is_initiator
        self.token_by_pubkey = token_by_pubkey
        self.ephemeral_ecc = ECCx(raw_privkey=ephemeral_privkey)

    def encrypt(self, header, frame):
        assert self.is_ready is True
        assert len(header) == 16
        assert len(frame) % 16 == 0

        def aes(data=''):
            return self.aes_enc.update(data)

        def mac(data=''):
            self.egress_mac.update(data)
            return self.egress_mac.digest()

        # header
        header_ciphertext = aes(header)
        assert len(header_ciphertext) == 16
        # egress-mac.update(aes(mac-secret,egress-mac) ^ header-ciphertext).digest
        header_mac = mac(sxor(self.mac_enc(mac()[:16]), header_ciphertext))[:16]

        # frame
        frame_ciphertext = aes(frame)
        assert len(frame_ciphertext) == len(frame)
        # egress-mac.update(aes(mac-secret,egress-mac) ^
        # left128(egress-mac.update(frame-ciphertext).digest))
        fmac_seed = mac(frame_ciphertext)
        frame_mac = mac(sxor(self.mac_enc(mac()[:16]), fmac_seed[:16]))[:16]

        return header_ciphertext + header_mac + frame_ciphertext + frame_mac

    def decrypt_header(self, data):
        assert self.is_ready is True
        assert len(data) == 32

        def aes(data=''):
            return self.aes_dec.update(data)

        def mac(data=''):
            self.ingress_mac.update(data)
            return self.ingress_mac.digest()

        header_ciphertext = data[:16]
        header_mac = data[16:32]

        # ingress-mac.update(aes(mac-secret,ingress-mac) ^ header-ciphertext).digest
        expected_header_mac = mac(sxor(self.mac_enc(mac()[:16]), header_ciphertext))[:16]
        # expected_header_mac = self.updateMAC(self.ingress_mac, header_ciphertext)
        if not expected_header_mac == header_mac:
            raise AuthenticationError('invalid header mac')
        return aes(header_ciphertext)

    def decrypt_body(self, data, body_size):
        assert self.is_ready is True

        def aes(data=''):
            return self.aes_dec.update(data)

        def mac(data=''):
            self.ingress_mac.update(data)
            return self.ingress_mac.digest()

        # frame-size: 3-byte integer size of frame, big endian encoded (excludes padding)
        # frame relates to body w/o padding w/o mac

        read_size = ceil16(body_size)
        if not len(data) >= read_size + 16:
            raise FormatError('insufficient body length')

        # FIXME check frame length in header
        # assume datalen == framelen for now
        frame_ciphertext = data[:read_size]
        frame_mac = data[read_size:read_size + 16]
        assert len(frame_mac) == 16

        # ingres-mac.update(aes(mac-secret,ingres-mac) ^
        # left128(ingres-mac.update(frame-ciphertext).digest))
        fmac_seed = mac(frame_ciphertext)
        expected_frame_mac = mac(sxor(self.mac_enc(mac()[:16]), fmac_seed[:16]))[:16]
        if not frame_mac == expected_frame_mac:
            raise AuthenticationError('invalid frame mac')
        return aes(frame_ciphertext)[:body_size]

    def decrypt(self, data):
        header = self.decrypt_header(data[:32])
        body_size = struct.unpack('>I', '\x00' + header[:3])[0]
        if not len(data) >= 32 + ceil16(body_size) + 16:
            raise FormatError('insufficient body length')
        frame = self.decrypt_body(data[32:], body_size)
        return dict(header=header, frame=frame, bytes_read=32 + ceil16(len(frame)) + 16)

    def create_auth_message(self, remote_pubkey, ephemeral_privkey=None, nonce=None):
        """
        1. initiator generates ecdhe-random and nonce and creates auth
        2. initiator connects to remote and sends auth

        New:
        E(remote-pubk,
            S(ephemeral-privk, ecdh-shared-secret ^ nonce) ||
            H(ephemeral-pubk) || pubk || nonce || 0x0
        )
        Known:
        E(remote-pubk,
            S(ephemeral-privk, token ^ nonce) || H(ephemeral-pubk) || pubk || nonce || 0x1)
        """
        assert self.is_initiator
        if not self.ecc.is_valid_key(remote_pubkey):
            raise InvalidKeyError('invalid remote pubkey')
        self.remote_pubkey = remote_pubkey

        token = self.token_by_pubkey.get(remote_pubkey)
        if not token:  # new
            ecdh_shared_secret = self.ecc.get_ecdh_key(remote_pubkey)
            token = ecdh_shared_secret
            flag = 0x0
        else:
            flag = 0x1

        self.initiator_nonce = nonce or sha3(ienc(random.randint(0, 2 ** 256 - 1)))
        assert len(self.initiator_nonce) == 32

        token_xor_nonce = sxor(token, self.initiator_nonce)
        assert len(token_xor_nonce) == 32

        ephemeral_pubkey = self.ephemeral_ecc.raw_pubkey
        assert len(ephemeral_pubkey) == 512 / 8
        if not self.ecc.is_valid_key(ephemeral_pubkey):
            raise InvalidKeyError('invalid ephemeral pubkey')

        # S(ephemeral-privk, ecdh-shared-secret ^ nonce)
        S = self.ephemeral_ecc.sign(token_xor_nonce)
        assert len(S) == 65

        # S || H(ephemeral-pubk) || pubk || nonce || 0x0
        auth_message = S + sha3(ephemeral_pubkey) + self.ecc.raw_pubkey + \
            self.initiator_nonce + chr(flag)
        assert len(auth_message) == 65 + 32 + 64 + 32 + 1 == 194
        return auth_message

    def encrypt_auth_message(self, auth_message, remote_pubkey=None):
        assert self.is_initiator
        remote_pubkey = remote_pubkey or self.remote_pubkey
        self.auth_init = self.ecc.ecies_encrypt(auth_message, remote_pubkey)
        assert len(self.auth_init) == self.auth_message_ct_length
        return self.auth_init

    def encrypt_auth_ack_message(self, auth_message, remote_pubkey=None):
        assert not self.is_initiator
        remote_pubkey = remote_pubkey or self.remote_pubkey
        self.auth_ack = self.ecc.ecies_encrypt(auth_message, remote_pubkey)
        assert len(self.auth_ack) == self.auth_ack_message_ct_length
        return self.auth_ack

    def decode_authentication(self, ciphertext):
        """
        3. optionally, remote decrypts and verifies auth
            (checks that recovery of signature == H(ephemeral-pubk))
        4. remote generates authAck from remote-ephemeral-pubk and nonce
            (authAck = authRecipient handshake)

        optional: remote derives secrets and preemptively sends protocol-handshake (steps 9,11,8,10)
        """
        assert not self.is_initiator

        self.auth_init = ciphertext
        try:
            auth_message = self.ecc.ecies_decrypt(ciphertext)
        except RuntimeError as e:
            raise AuthenticationError(e)

        # S || H(ephemeral-pubk) || pubk || nonce || 0x[0|1]
        assert len(auth_message) == 65 + 32 + 64 + 32 + 1 == 194 == self.auth_message_length
        signature = auth_message[:65]
        H_initiator_ephemeral_pubkey = auth_message[65:65 + 32]
        initiator_pubkey = auth_message[65 + 32:65 + 32 + 64]
        if not self.ecc.is_valid_key(initiator_pubkey):
            raise InvalidKeyError('invalid initiator pubkey')
        self.remote_pubkey = initiator_pubkey
        self.initiator_nonce = auth_message[65 + 32 + 64:65 + 32 + 64 + 32]
        known_flag = bool(ord(auth_message[65 + 32 + 64 + 32:]))

        # token or new ecdh_shared_secret
        if known_flag:
            self.remote_token_found = True
            # what todo if remote has token, but local forgot it.
            #   reply with token not found. FIXME!!!
            token = self.token_by_pubkey.get(initiator_pubkey)
            assert token  # FIXME continue session with ecdh_key and send flag in auth_ack
        else:
            token = self.ecc.get_ecdh_key(initiator_pubkey)

        # verify auth
        # S(ephemeral-privk, ecdh-shared-secret ^ nonce)
        signed = sxor(token, self.initiator_nonce)

        # recover initiator ephemeral pubkey
        self.remote_ephemeral_pubkey = ecdsa_recover(signed, signature)
        if not self.ecc.is_valid_key(self.remote_ephemeral_pubkey):
            raise InvalidKeyError('invalid remote ephemeral pubkey')
        if not ecdsa_verify(self.remote_ephemeral_pubkey, signature, signed):
            raise AuthenticationError('could not verify signature')

        # checks that recovery of signature == H(ephemeral-pubk)
        assert H_initiator_ephemeral_pubkey == sha3(self.remote_ephemeral_pubkey)

    def create_auth_ack_message(self, ephemeral_pubkey=None, nonce=None, token_found=False):
        """
        authRecipient = E(remote-pubk, remote-ephemeral-pubk || nonce || 0x1) // token found
        authRecipient = E(remote-pubk, remote-ephemeral-pubk || nonce || 0x0) // token not found

        nonce and empehemeral-pubk are local!
        """
        assert not self.is_initiator
        ephemeral_pubkey = ephemeral_pubkey or self.ephemeral_ecc.raw_pubkey
        self.responder_nonce = nonce or sha3(ienc(random.randint(0, 2 ** 256 - 1)))

        flag = chr(1 if token_found else 0)
        msg = ephemeral_pubkey + self.responder_nonce + flag
        assert len(msg) == 64 + 32 + 1 == 97 == self.auth_ack_message_length
        return msg

    def decode_auth_ack_message(self, ciphertext):
        assert self.is_initiator
        self.auth_ack = ciphertext
        auth_ack_message = self.ecc.ecies_decrypt(ciphertext)
        assert len(auth_ack_message) == 64 + 32 + 1
        self.remote_ephemeral_pubkey = auth_ack_message[:64]
        if not self.ecc.is_valid_key(self.remote_ephemeral_pubkey):
            raise InvalidKeyError('invalid remote ephemeral pubkey')
        self.responder_nonce = auth_ack_message[64:64 + 32]
        self.remote_token_found = bool(ord(auth_ack_message[-1]))

    def setup_cipher(self):
        assert self.responder_nonce
        assert self.initiator_nonce
        assert self.auth_init
        assert self.auth_ack
        assert self.remote_ephemeral_pubkey
        if not self.ecc.is_valid_key(self.remote_ephemeral_pubkey):
            raise InvalidKeyError('invalid remote ephemeral pubkey')

        # derive base secrets from ephemeral key agreement
        # ecdhe-shared-secret = ecdh.agree(ephemeral-privkey, remote-ephemeral-pubk)
        ecdhe_shared_secret = self.ephemeral_ecc.get_ecdh_key(self.remote_ephemeral_pubkey)

        # shared-secret = sha3(ecdhe-shared-secret || sha3(nonce || initiator-nonce))
        shared_secret = sha3(
            ecdhe_shared_secret + sha3(self.responder_nonce + self.initiator_nonce))

        self.ecdhe_shared_secret = ecdhe_shared_secret  # used in tests
        self.shared_secret = shared_secret   # used in tests

        # token = sha3(shared-secret)
        self.token = sha3(shared_secret)
        self.token_by_pubkey[self.remote_pubkey] = self.token

        # aes-secret = sha3(ecdhe-shared-secret || shared-secret)
        self.aes_secret = sha3(ecdhe_shared_secret + shared_secret)

        # mac-secret = sha3(ecdhe-shared-secret || aes-secret)
        self.mac_secret = sha3(ecdhe_shared_secret + self.aes_secret)

        # setup sha3 instances for the MACs
        # egress-mac = sha3.update(mac-secret ^ recipient-nonce || auth-sent-init)
        mac1 = sha3_256(sxor(self.mac_secret, self.responder_nonce) + self.auth_init)
        # ingress-mac = sha3.update(mac-secret ^ initiator-nonce || auth-recvd-ack)
        mac2 = sha3_256(sxor(self.mac_secret, self.initiator_nonce) + self.auth_ack)

        if self.is_initiator:
            self.egress_mac, self.ingress_mac = mac1, mac2
        else:
            self.egress_mac, self.ingress_mac = mac2, mac1

        ciphername = 'aes-256-ctr'
        iv = "\x00" * 16
        assert len(iv) == 16
        self.aes_enc = pyelliptic.Cipher(self.aes_secret, iv, 1, ciphername=ciphername)
        self.aes_dec = pyelliptic.Cipher(self.aes_secret, iv, 0, ciphername=ciphername)
        self.mac_enc = AES.AESCipher(self.mac_secret, AES.MODE_ECB).encrypt

        self.is_ready = True
Пример #17
0
class RNOService(BaseService):

    # required by BaseService
    name = 'rno'
    default_config = dict(eth=dict(privkey_hex=''))

    # RNO address, where the requests for random number should be addressed to.
    my_addr = None

    # Keeps all transactions not yet processed by loop_body
    tx_queue = None

    # Will be used to a) sign transaction and b) encrypt random number using ECIES
    eccx = None

    privkey_hex = None

    def __init__(self, app):
        super(RNOService, self).__init__(app)
        log.info('Initializing RNO')
        self.config = app.config
        self.interrupt = Event()
        self.tx_queue = Queue()  # thread safe
        self.privkey_hex = self.config['eth']['privkey_hex'].decode('hex')
        self.my_addr = privtoaddr(self.privkey_hex)
        self.eccx = ECCx(None, self.privkey_hex)

    # Process the transaction queue. There is no concurrency problem here since
    # the Queue is thread-safe.
    def loop_body(self):
        log.debug('RNO body', my_addr=self.my_addr)
        while not self.tx_queue.empty():
            tx = self.tx_queue.get()
            if tx.to == self.my_addr:
                self.process_tx(tx)

    # Transactions should be added to a queue so that 'loop_body' process that queue
    # To minimize code dependency and coupling, this method will be called for ALL
    # transactions received.
    # It is called in the loop of eth_service.py -> on_receive_transactions
    def add_transaction(self, tx):
        log.debug('RNO received transaction', tx=tx)
        # All transactions are being queued here to minimize the blocking
        # of caller's thread. Transactions not addressed to RNO are discarded
        # in loop_body.
        self.tx_queue.put(tx)

    # This method is the core of the RNO. Transactions should NOT be processed in the
    # add_transaction otherwise it would block the caller.
    def process_tx(self, tx):
        log.debug('process tx', tx=tx)

        # 2) Extract sender's pubkey from the Electrum-style signature of the tx
        sender_pubkey = self.sender_pubkey_from_tx(tx)
        enc_num = self.generate_encrypted_random_number(sender_pubkey)

        # 5) encrypt RN using reveal host's pubkey (eRN2) (???)
        # this is not specified yet

        # 6) create/send transaction back to tx sender
        self.deliver(enc_num, tx.sender)

        # 7) create/send transaction to reveal host.
        # this is not specified yet

    def sender_pubkey_from_tx(self, tx):
        encoded_signature = _encode_sig(tx.v, tx.r, tx.s)
        message = None  # TODO: find out how to build the data (message) where the signature is applied.
        return recover(message, encoded_signature)

    def generate_encrypted_random_number(self, pubkey):
        # 3) generate the random number
        number = os.urandom(64)

        # 4) encrypt RN using sender's pubkey (eRN1)
        return self.eccx.encrypt(number, pubkey)

    def deliver(self, enc_num, to):
        # nonce = number of transactions already sent by that account
        head = self.app.services.chain.chain.head
        nonce = head.get_nonce(self.my_addr)

        # Took from buterin example:
        # https://blog.ethereum.org/2014/04/10/pyethereum-and-serpent-programming-guide/
        gasprice = 10**12

        # Took from buterin example:
        # https://blog.ethereum.org/2014/04/10/pyethereum-and-serpent-programming-guide/
        startgas = 10000
        value = 0  # It's just a message, don't need to send any value (TODO: confirm that info)

        # data is a json formatted message but has to be 'binary'
        unix_now = int(round(time()))
        payload = {}
        payload['when'] = unix_now
        payload['number'] = enc_num
        payload['publish_on'] = unix_now + 86400  # in 24 hours
        payload['published_at'] = 'http://www.example.com/foo'
        data = json.dumps(payload)

        deliver_tx = Transaction(nonce, gasprice, startgas, to, value, data)
        signed_deliver_tx = deliver_tx.sign(self.privkey_hex)
        success, output = apply_transaction(head, signed_deliver_tx)

    # Sends the reply back to Requester and Reveal Host
    def send_replies(self, number, requester_addr, reveal_host_addr,
                     publish_at, publish_on):
        log.debug('RNO reply', number=number, requester_addr=requester_addr,
                  publish_at=publish_at, publish_on=publish_on)

    # Generates the public address (IPFS?) that will be used by the Reveal Host
    def generate_public_address(self, number):
        address = 'some public address'
        log.debug('RNO pub address', address=address)
        return address

    # This will make the loop_body be executed by RNOService thread.
    def wakeup(self):
        self.interrupt.set()

    # @override BaseService._run (Greenlet._run)
    def _run(self):
        while True:
            self.interrupt.wait()
            self.loop_body()
            self.interrupt.clear()
Пример #18
0
 def __init__(self, privkey):
     self.ecc = ECCx(raw_privkey=privkey)
Пример #19
0
class RNOService(BaseService):

    # required by BaseService
    name = 'rno'
    default_config = dict(eth=dict(privkey_hex=''))

    # RNO address, where the requests for random number should be addressed to.
    my_addr = None

    # Keeps all transactions not yet processed by loop_body
    tx_queue = None

    # Will be used to a) sign transaction and b) encrypt random number using ECIES
    eccx = None

    privkey_hex = None

    def __init__(self, app):
        super(RNOService, self).__init__(app)
        log.info('Initializing RNO')
        self.config = app.config
        self.interrupt = Event()
        self.tx_queue = Queue()  # thread safe
        self.privkey_hex = self.config['eth']['privkey_hex'].decode('hex')
        self.my_addr = privtoaddr(self.privkey_hex)
        self.eccx = ECCx(None, self.privkey_hex)

    # Process the transaction queue. There is no concurrency problem here since
    # the Queue is thread-safe.
    def loop_body(self):
        log.debug('RNO body', my_addr=self.my_addr)
        while not self.tx_queue.empty():
            tx = self.tx_queue.get()
            if tx.to == self.my_addr:
                self.process_tx(tx)

    # Transactions should be added to a queue so that 'loop_body' process that queue
    # To minimize code dependency and coupling, this method will be called for ALL
    # transactions received.
    # It is called in the loop of eth_service.py -> on_receive_transactions
    def add_transaction(self, tx):
        log.debug('RNO received transaction', tx=tx)
        # All transactions are being queued here to minimize the blocking
        # of caller's thread. Transactions not addressed to RNO are discarded
        # in loop_body.
        self.tx_queue.put(tx)

    # This method is the core of the RNO. Transactions should NOT be processed in the
    # add_transaction otherwise it would block the caller.
    def process_tx(self, tx):
        log.debug('process tx', tx=tx)

        # 2) Extract sender's pubkey from the Electrum-style signature of the tx
        sender_pubkey = self.sender_pubkey_from_tx(tx)
        enc_num = self.generate_encrypted_random_number(sender_pubkey)

        # 5) encrypt RN using reveal host's pubkey (eRN2) (???)
        # this is not specified yet

        # 6) create/send transaction back to tx sender
        self.deliver(enc_num, tx.sender)

        # 7) create/send transaction to reveal host.
        # this is not specified yet

    def sender_pubkey_from_tx(self, tx):
        encoded_signature = _encode_sig(tx.v, tx.r, tx.s)
        message = None  # TODO: find out how to build the data (message) where the signature is applied.
        return recover(message, encoded_signature)

    def generate_encrypted_random_number(self, pubkey):
        # 3) generate the random number
        number = os.urandom(64)

        # 4) encrypt RN using sender's pubkey (eRN1)
        return self.eccx.encrypt(number, pubkey)

    def deliver(self, enc_num, to):
        # nonce = number of transactions already sent by that account
        head = self.app.services.chain.chain.head
        nonce = head.get_nonce(self.my_addr)

        # Took from buterin example:
        # https://blog.ethereum.org/2014/04/10/pyethereum-and-serpent-programming-guide/
        gasprice = 10**12

        # Took from buterin example:
        # https://blog.ethereum.org/2014/04/10/pyethereum-and-serpent-programming-guide/
        startgas = 10000
        value = 0  # It's just a message, don't need to send any value (TODO: confirm that info)

        # data is a json formatted message but has to be 'binary'
        unix_now = int(round(time()))
        payload = {}
        payload['when'] = unix_now
        payload['number'] = enc_num
        payload['publish_on'] = unix_now + 86400  # in 24 hours
        payload['published_at'] = 'http://www.example.com/foo'
        data = json.dumps(payload)

        deliver_tx = Transaction(nonce, gasprice, startgas, to, value, data)
        signed_deliver_tx = deliver_tx.sign(self.privkey_hex)
        success, output = apply_transaction(head, signed_deliver_tx)

    # Sends the reply back to Requester and Reveal Host
    def send_replies(self, number, requester_addr, reveal_host_addr,
                     publish_at, publish_on):
        log.debug('RNO reply',
                  number=number,
                  requester_addr=requester_addr,
                  publish_at=publish_at,
                  publish_on=publish_on)

    # Generates the public address (IPFS?) that will be used by the Reveal Host
    def generate_public_address(self, number):
        address = 'some public address'
        log.debug('RNO pub address', address=address)
        return address

    # This will make the loop_body be executed by RNOService thread.
    def wakeup(self):
        self.interrupt.set()

    # @override BaseService._run (Greenlet._run)
    def _run(self):
        while True:
            self.interrupt.wait()
            self.loop_body()
            self.interrupt.clear()
Пример #20
0
class RLPxSession(object):

    ephemeral_ecc = None
    remote_ephemeral_pubkey = None
    initiator_nonce = None
    responder_nonce = None
    auth_init = None
    auth_ack = None
    aes_secret = None
    token = None
    aes_enc = None
    aes_dec = None
    mac_enc = None
    egress_mac = None
    ingress_mac = None
    is_ready = False
    remote_pubkey = None
    remote_version = 0
    got_eip8_auth, got_eip8_ack = False, False

    def __init__(self, ecc, is_initiator=False, ephemeral_privkey=None):
        self.ecc = ecc
        self.is_initiator = is_initiator
        self.ephemeral_ecc = ECCx(raw_privkey=ephemeral_privkey)

    ### frame handling

    def encrypt(self, header, frame):
        assert self.is_ready is True
        assert len(header) == 16
        assert len(frame) % 16 == 0

        def aes(data=''):
            return self.aes_enc.update(data)

        def mac(data=b''):
            data = str_to_bytes(data)
            self.egress_mac.update(data)
            return self.egress_mac.digest()

        # header
        header_ciphertext = aes(header)
        assert len(header_ciphertext) == 16
        # egress-mac.update(aes(mac-secret,egress-mac) ^ header-ciphertext).digest
        header_mac = mac(sxor(self.mac_enc(mac()[:16]),
                              header_ciphertext))[:16]

        # frame
        frame_ciphertext = aes(frame)
        assert len(frame_ciphertext) == len(frame)
        # egress-mac.update(aes(mac-secret,egress-mac) ^
        # left128(egress-mac.update(frame-ciphertext).digest))
        fmac_seed = mac(frame_ciphertext)
        frame_mac = mac(sxor(self.mac_enc(mac()[:16]), fmac_seed[:16]))[:16]

        return header_ciphertext + header_mac + frame_ciphertext + frame_mac

    def decrypt_header(self, data):
        assert self.is_ready is True
        assert len(data) == 32

        def aes(data=''):
            return self.aes_dec.update(data)

        def mac(data=b''):
            data = str_to_bytes(data)
            self.ingress_mac.update(data)
            return self.ingress_mac.digest()

        header_ciphertext = data[:16]
        header_mac = data[16:32]

        # ingress-mac.update(aes(mac-secret,ingress-mac) ^ header-ciphertext).digest
        expected_header_mac = mac(
            sxor(self.mac_enc(mac()[:16]), header_ciphertext))[:16]
        # expected_header_mac = self.updateMAC(self.ingress_mac, header_ciphertext)
        if not expected_header_mac == header_mac:
            raise AuthenticationError('invalid header mac')
        return aes(header_ciphertext)

    def decrypt_body(self, data, body_size):
        assert self.is_ready is True

        def aes(data=''):
            return self.aes_dec.update(data)

        def mac(data=b''):
            data = str_to_bytes(data)
            self.ingress_mac.update(data)
            return self.ingress_mac.digest()

        # frame-size: 3-byte integer size of frame, big endian encoded (excludes padding)
        # frame relates to body w/o padding w/o mac

        read_size = ceil16(body_size)
        if not len(data) >= read_size + 16:
            raise FormatError('insufficient body length')

        # FIXME check frame length in header
        # assume datalen == framelen for now
        frame_ciphertext = data[:read_size]
        frame_mac = data[read_size:read_size + 16]
        assert len(frame_mac) == 16

        # ingres-mac.update(aes(mac-secret,ingres-mac) ^
        # left128(ingres-mac.update(frame-ciphertext).digest))
        fmac_seed = mac(frame_ciphertext)
        expected_frame_mac = mac(sxor(self.mac_enc(mac()[:16]),
                                      fmac_seed[:16]))[:16]
        if not frame_mac == expected_frame_mac:
            raise AuthenticationError('invalid frame mac')
        return aes(frame_ciphertext)[:body_size]

    def decrypt(self, data):
        header = self.decrypt_header(data[:32])
        body_size = struct.unpack(b'>I', b'\x00' + header[:3])[0]
        if not len(data) >= 32 + ceil16(body_size) + 16:
            raise FormatError('insufficient body length')
        frame = self.decrypt_body(data[32:], body_size)
        return dict(header=header,
                    frame=frame,
                    bytes_read=32 + ceil16(len(frame)) + 16)

    ### handshake auth message handling

    def create_auth_message(self,
                            remote_pubkey,
                            ephemeral_privkey=None,
                            nonce=None):
        """
        1. initiator generates ecdhe-random and nonce and creates auth
        2. initiator connects to remote and sends auth

        New:
        E(remote-pubk,
            S(ephemeral-privk, ecdh-shared-secret ^ nonce) ||
            H(ephemeral-pubk) || pubk || nonce || 0x0
        )
        Known:
        E(remote-pubk,
            S(ephemeral-privk, token ^ nonce) || H(ephemeral-pubk) || pubk || nonce || 0x1)
        """
        assert self.is_initiator
        if not self.ecc.is_valid_key(remote_pubkey):
            raise InvalidKeyError('invalid remote pubkey')
        self.remote_pubkey = remote_pubkey

        ecdh_shared_secret = self.ecc.get_ecdh_key(remote_pubkey)
        token = ecdh_shared_secret
        flag = 0x0
        self.initiator_nonce = nonce or sha3(
            ienc(random.randint(0, 2**256 - 1)))
        assert len(self.initiator_nonce) == 32

        token_xor_nonce = sxor(token, self.initiator_nonce)
        assert len(token_xor_nonce) == 32

        ephemeral_pubkey = self.ephemeral_ecc.raw_pubkey
        assert len(ephemeral_pubkey) == 512 / 8
        if not self.ecc.is_valid_key(ephemeral_pubkey):
            raise InvalidKeyError('invalid ephemeral pubkey')

        # S(ephemeral-privk, ecdh-shared-secret ^ nonce)
        S = self.ephemeral_ecc.sign(token_xor_nonce)
        assert len(S) == 65

        # S || H(ephemeral-pubk) || pubk || nonce || 0x0
        auth_message = S + sha3(ephemeral_pubkey) + self.ecc.raw_pubkey + \
            self.initiator_nonce + ascii_chr(flag)
        assert len(auth_message) == 65 + 32 + 64 + 32 + 1 == 194
        return auth_message

    eip8_auth_sedes = sedes.List(
        [
            sedes.Binary(min_length=65, max_length=65),  # sig
            sedes.Binary(min_length=64, max_length=64),  # pubkey
            sedes.Binary(min_length=32, max_length=32),  # nonce
            sedes.BigEndianInt()  # version
        ],
        strict=False)

    def encrypt_auth_message(self, auth_message, remote_pubkey=None):
        assert self.is_initiator
        remote_pubkey = remote_pubkey or self.remote_pubkey
        self.auth_init = self.ecc.ecies_encrypt(auth_message, remote_pubkey)
        assert len(self.auth_init) == 307
        return self.auth_init

    def decode_authentication(self, ciphertext):
        """
        3. optionally, remote decrypts and verifies auth
            (checks that recovery of signature == H(ephemeral-pubk))
        4. remote generates authAck from remote-ephemeral-pubk and nonce
            (authAck = authRecipient handshake)

        optional: remote derives secrets and preemptively sends protocol-handshake (steps 9,11,8,10)
        """
        assert not self.is_initiator
        if len(ciphertext) < 307:
            raise FormatError("Ciphertext too short")
        try:
            (size, sig, initiator_pubkey, nonce,
             version) = self.decode_auth_plain(ciphertext)
        except AuthenticationError:
            (size, sig, initiator_pubkey, nonce,
             version) = self.decode_auth_eip8(ciphertext)
            self.got_eip8_auth = True
        self.auth_init = ciphertext[:size]
        # recover initiator ephemeral pubkey from sig
        #     S(ephemeral-privk, ecdh-shared-secret ^ nonce)
        token = self.ecc.get_ecdh_key(initiator_pubkey)
        self.remote_ephemeral_pubkey = ecdsa_recover(sxor(token, nonce), sig)
        if not self.ecc.is_valid_key(self.remote_ephemeral_pubkey):
            raise InvalidKeyError('invalid remote ephemeral pubkey')
        self.initiator_nonce = nonce
        self.remote_pubkey = initiator_pubkey
        self.remote_version = version
        return ciphertext[size:]

    def decode_auth_plain(self, ciphertext):
        """
        decode legacy pre-EIP-8 auth message format
        """
        try:
            message = self.ecc.ecies_decrypt(ciphertext[:307])
        except RuntimeError as e:
            raise AuthenticationError(e)
        assert len(message) == 194
        signature = message[:65]
        pubkey = message[65 + 32:65 + 32 + 64]
        if not self.ecc.is_valid_key(pubkey):
            raise InvalidKeyError('invalid initiator pubkey')
        nonce = message[65 + 32 + 64:65 + 32 + 64 + 32]
        known_flag = bool(safe_ord(message[65 + 32 + 64 + 32:]))
        assert known_flag == 0
        return (307, signature, pubkey, nonce, 4)

    def decode_auth_eip8(self, ciphertext):
        """
        decode EIP-8 auth message format
        """
        size = struct.unpack('>H', ciphertext[:2])[0] + 2
        if len(ciphertext) < size:
            raise FormatError("Message shorter than specified size")
        try:
            message = self.ecc.ecies_decrypt(ciphertext[2:size],
                                             shared_mac_data=ciphertext[:2])
        except RuntimeError as e:
            raise AuthenticationError(e)
        values = rlp.decode(message, sedes=self.eip8_auth_sedes, strict=False)
        assert len(values) >= 4
        return (size, ) + values[:4]

    ### handshake ack message handling

    def create_auth_ack_message(self,
                                version=supported_rlpx_version,
                                eip8=False,
                                ephemeral_pubkey=None,
                                nonce=None):
        """
        authRecipient = E(remote-pubk, remote-ephemeral-pubk || nonce || 0x1) // token found
        authRecipient = E(remote-pubk, remote-ephemeral-pubk || nonce || 0x0) // token not found

        nonce, ephemeral_pubkey, version are local!
        """
        assert not self.is_initiator
        ephemeral_pubkey = ephemeral_pubkey or self.ephemeral_ecc.raw_pubkey
        self.responder_nonce = nonce or sha3(
            ienc(random.randint(0, 2**256 - 1)))
        if eip8 or self.got_eip8_auth:
            msg = self.create_eip8_auth_ack_message(ephemeral_pubkey,
                                                    self.responder_nonce,
                                                    version)
            assert len(msg) > 97
        else:
            msg = ephemeral_pubkey + self.responder_nonce + b'\x00'
            assert len(msg) == 97
        return msg

    eip8_ack_sedes = sedes.List(
        [
            sedes.Binary(min_length=64, max_length=64),  # ephemeral pubkey
            sedes.Binary(min_length=32, max_length=32),  # nonce
            sedes.BigEndianInt()  # version
        ],
        strict=False)

    def create_eip8_auth_ack_message(self, ephemeral_pubkey, nonce, version):
        data = rlp.encode((ephemeral_pubkey, nonce, version),
                          sedes=self.eip8_ack_sedes)
        pad = os.urandom(random.randint(100, 250))
        return data + pad

    def encrypt_auth_ack_message(self,
                                 ack_message,
                                 eip8=False,
                                 remote_pubkey=None):
        assert not self.is_initiator
        remote_pubkey = remote_pubkey or self.remote_pubkey
        if eip8 or self.got_eip8_auth:
            # The EIP-8 version has an authenticated length prefix.
            prefix = struct.pack(
                '>H',
                len(ack_message) + self.ecc.ecies_encrypt_overhead_length)
            self.auth_ack = self.ecc.ecies_encrypt(ack_message,
                                                   remote_pubkey,
                                                   shared_mac_data=prefix)
            self.auth_ack = prefix + self.auth_ack
        else:
            self.auth_ack = self.ecc.ecies_encrypt(ack_message, remote_pubkey)
            assert len(self.auth_ack) == 210
        return self.auth_ack

    def decode_auth_ack_message(self, ciphertext):
        assert self.is_initiator
        assert len(ciphertext) >= 210
        try:
            (size, eph_pubkey, nonce,
             version) = self.decode_ack_plain(ciphertext)
        except AuthenticationError:
            (size, eph_pubkey, nonce,
             version) = self.decode_ack_eip8(ciphertext)
            self.got_eip8_ack = True
        self.auth_ack = ciphertext[:size]
        self.remote_ephemeral_pubkey = eph_pubkey[:64]
        self.responder_nonce = nonce
        self.remote_version = version
        if not self.ecc.is_valid_key(self.remote_ephemeral_pubkey):
            raise InvalidKeyError('invalid remote ephemeral pubkey')
        return ciphertext[size:]

    def decode_ack_plain(self, ciphertext):
        """
        decode legacy pre-EIP-8 ack message format
        """
        try:
            message = self.ecc.ecies_decrypt(ciphertext[:210])
        except RuntimeError as e:
            raise AuthenticationError(e)
        assert len(message) == 64 + 32 + 1
        eph_pubkey = message[:64]
        nonce = message[64:64 + 32]
        known = safe_ord(message[-1])
        assert known == 0
        return (210, eph_pubkey, nonce, 4)

    def decode_ack_eip8(self, ciphertext):
        """
        decode EIP-8 ack message format
        """
        size = struct.unpack('>H', ciphertext[:2])[0] + 2
        assert len(ciphertext) == size
        try:
            message = self.ecc.ecies_decrypt(ciphertext[2:size],
                                             shared_mac_data=ciphertext[:2])
        except RuntimeError as e:
            raise AuthenticationError(e)
        values = rlp.decode(message, sedes=self.eip8_ack_sedes, strict=False)
        assert len(values) >= 3
        return (size, ) + values[:3]

    ### handshake key derivation

    def setup_cipher(self):
        assert self.responder_nonce
        assert self.initiator_nonce
        assert self.auth_init
        assert self.auth_ack
        assert self.remote_ephemeral_pubkey
        if not self.ecc.is_valid_key(self.remote_ephemeral_pubkey):
            raise InvalidKeyError('invalid remote ephemeral pubkey')

        # derive base secrets from ephemeral key agreement
        # ecdhe-shared-secret = ecdh.agree(ephemeral-privkey, remote-ephemeral-pubk)
        ecdhe_shared_secret = self.ephemeral_ecc.get_ecdh_key(
            self.remote_ephemeral_pubkey)

        # shared-secret = sha3(ecdhe-shared-secret || sha3(nonce || initiator-nonce))
        shared_secret = sha3(ecdhe_shared_secret +
                             sha3(self.responder_nonce + self.initiator_nonce))

        self.ecdhe_shared_secret = ecdhe_shared_secret  # used in tests
        self.shared_secret = shared_secret  # used in tests

        # token = sha3(shared-secret)
        self.token = sha3(shared_secret)

        # aes-secret = sha3(ecdhe-shared-secret || shared-secret)
        self.aes_secret = sha3(ecdhe_shared_secret + shared_secret)

        # mac-secret = sha3(ecdhe-shared-secret || aes-secret)
        self.mac_secret = sha3(ecdhe_shared_secret + self.aes_secret)

        # setup sha3 instances for the MACs
        # egress-mac = sha3.update(mac-secret ^ recipient-nonce || auth-sent-init)
        mac1 = sha3_256(
            sxor(self.mac_secret, self.responder_nonce) + self.auth_init)
        # ingress-mac = sha3.update(mac-secret ^ initiator-nonce || auth-recvd-ack)
        mac2 = sha3_256(
            sxor(self.mac_secret, self.initiator_nonce) + self.auth_ack)

        if self.is_initiator:
            self.egress_mac, self.ingress_mac = mac1, mac2
        else:
            self.egress_mac, self.ingress_mac = mac2, mac1

        ciphername = 'aes-256-ctr'
        iv = "\x00" * 16
        assert len(iv) == 16
        self.aes_enc = pyelliptic.Cipher(self.aes_secret,
                                         iv,
                                         1,
                                         ciphername=ciphername)
        self.aes_dec = pyelliptic.Cipher(self.aes_secret,
                                         iv,
                                         0,
                                         ciphername=ciphername)
        self.mac_enc = AES.new(self.mac_secret, AES.MODE_ECB).encrypt

        self.is_ready = True
Пример #21
0
class RLPxSession(object):

    ephemeral_ecc = None
    nonce = None
    token = None
    aes_secret = None
    aes_enc = None
    aes_dec = None
    egress_mac = None
    ingress_mac = None
    remote_node = None
    _authentication_sent = False
    is_ready = False

    def __init__(self, peer=None):
        # persisted peer data. keys are the nodeid
        # session data
        self.peer = peer
        if peer:
            self.node = peer.local_node.ecc
        else:
            self.node = None

    def __repr__(self):
        return '<RLPxSession (%s)>' % self.address.encode('hex')

    def encrypt(self, header, frame):
        """
        header-mac: right128 of
        egress-mac.update(aes(mac-secret,egress-mac)^header-ciphertext)
        """
        assert self.is_ready is True

        def aes(data):
            return self.aes_enc.update(data)

        def mac(data):
            return self.egress_mac.update(data)

        # header
        assert len(header) == 16  # zero padded to 16 bytes
        header_ciphertext = aes(header)
        assert len(header_ciphertext) <= 32  # must not be larger than mac
        # FIXME mac-secret!?
        header_mac = mac(sxor(aes(mac('')), header_ciphertext))[-16:]
        # frame
        frame_ciphertext = aes(frame)
        frame_mac = self.egress_mac.update(frame_ciphertext)
        return header_ciphertext + header_mac + frame_ciphertext + frame_mac

    def decrypt(self, data):
        assert self.is_ready is True

        def aes(data):
            return self.aes_dec.update(data)

        def mac(data):
            return self.egress_mac.update(data)

        header_ciphertext = data[:16]
        header_mac = data[16:32]

        header = aes(header_ciphertext)
        expected_header_mac = mac(sxor(aes(mac(''), header_ciphertext)))[-16:]
        assert expected_header_mac == header_mac

        # FIXME check frame length in header
        # assume datalen == framelen for now
        frame_mac = self.egress_mac.update(frame_ciphertext)
        data = aes(data[32:])

    def create_auth_message(self,
                            remote_pubkey,
                            token=None,
                            ephemeral_privkey=None,
                            nonce=None):
        """
        1. initiator generates ecdhe-random and nonce and creates auth
        2. initiator connects to remote and sends auth

        New:
        E(remote-pubk,
            S(ephemeral-privk, ecdh-shared-secret ^ nonce) ||
            H(ephemeral-pubk) || pubk || nonce || 0x0
        )
        Known:
        E(remote-pubk,
            S(ephemeral-privk, token ^ nonce) || H(ephemeral-pubk) || pubk || nonce || 0x1)
        """

        if not token:  # new
            ecdh_shared_secret = self.node.get_ecdh_key(remote_pubkey)
            token = ecdh_shared_secret
            flag = 0x0
        else:
            flag = 0x1

        nonce = nonce or ienc(random.randint(0, 2**256 - 1))
        assert len(nonce) == 32

        token_xor_nonce = sxor(token, nonce)
        assert len(token_xor_nonce) == 32

        # generate session ephemeral key
        if not ephemeral_privkey:
            ephemeral_privkey = sha3(ienc(random.randint(0, 2**256 - 1)))

        self.ephemeral_ecc = ECCx(raw_privkey=ephemeral_privkey)
        ephemeral_pubkey = self.ephemeral_ecc.raw_pubkey

        assert len(ephemeral_pubkey) == 512 / 8
        # S(ephemeral-privk, ecdh-shared-secret ^ nonce)
        S = self.ephemeral_ecc.sign(token_xor_nonce)
        assert len(S) == 65

        # S || H(ephemeral-pubk) || pubk || nonce || 0x0
        auth_message = S + sha3(
            ephemeral_pubkey) + self.node.raw_pubkey + nonce + chr(flag)
        assert len(auth_message) == 65 + 32 + 64 + 32 + 1 == 194
        return auth_message

    def encrypt_auth_message(self, auth_message, remote_pubkey):
        return self.node.ecies_encrypt(auth_message, remote_pubkey)

    encrypt_auth_ack_message = encrypt_auth_message

    def send_authentication(self, remote_node, ephermal_privkey=None):
        auth_message = self.create_auth_message(remote_node, ephermal_privkey)
        self.peer.send(auth_message)
        self._authentication_sent = True

    def receive_authentication(self, ciphertext):
        """
        3. optionally, remote decrypts and verifies auth
            (checks that recovery of signature == H(ephemeral-pubk))
        4. remote generates authAck from remote-ephemeral-pubk and nonce
            (authAck = authRecipient handshake)

        optional: remote derives secrets and preemptively sends protocol-handshake (steps 9,11,8,10)
        """
        auth_message = self.node.ecies_decrypt(ciphertext)
        # S || H(ephemeral-pubk) || pubk || nonce || 0x[0|1]
        assert len(auth_message) == 65 + 32 + 64 + 32 + 1 == 194
        signature = auth_message[:65]
        H_remote_ephemeral_pubkey = auth_message[65:65 + 32]
        remote_pubkey = auth_message[65 + 32:65 + 32 + 64]
        nonce = auth_message[65 + 32 + 64:65 + 32 + 64 + 32]
        known_flag = auth_message[65 + 32 + 64 + 32:]

        # token or new ecdh_shared_secret
        token_database = dict()  # FIXME
        token_found = False
        if known_flag == 1:
            token = token_database.get(remote_pubkey)
            if token:
                token_found = True
        else:
            token = ecdh_shared_secret = self.node.get_ecdh_key(remote_pubkey)

        # verify auth
        # S(ephemeral-privk, ecdh-shared-secret ^ nonce)
        ecdh_shared_secret = self.node.get_ecdh_key(remote_pubkey)
        signed = sxor(ecdh_shared_secret, nonce)

        # recover remote ephemeral pubkey
        remote_ephemeral_pubkey = ecdsa_recover(signed, signature)

        assert ecdsa_verify(remote_ephemeral_pubkey, signature, signed)

        # checks that recovery of signature == H(ephemeral-pubk)
        assert H_remote_ephemeral_pubkey == sha3(remote_ephemeral_pubkey)

        return dict(remote_ephemeral_pubkey=remote_ephemeral_pubkey,
                    token=token,
                    token_found=token_found,
                    ecdh_shared_secret=ecdh_shared_secret,
                    remote_pubkey=remote_pubkey,
                    nonce=nonce,
                    known_flag=known_flag)

    def create_auth_ack_message(self,
                                ephemeral_pubkey,
                                nonce,
                                token_found=False):
        """
        authRecipient = E(remote-pubk, remote-ephemeral-pubk || nonce || 0x1) // token found
        authRecipient = E(remote-pubk, remote-ephemeral-pubk || nonce || 0x0) // token not found

        nonce and empehemeral-pubk are local!
        """
        flag = chr(1 if token_found else 0)
        msg = ephemeral_pubkey + nonce + flag
        assert len(msg) == 64 + 32 + 1 == 97
        return msg

    def something():
        ##################

        # send authentication if not yet
        if not self._authentication_sent:
            remote_node = RemoteNode(remote_pubkey)  # FIXME LOOKUP
            self.send_authentication(remote_node)

            # - success -> AcknowledgeAuthentication
            self.acknowledge_authentication(other, remote_pubkey,
                                            remote_ecdhe_pubkey)

        # ecdhe_shared_secret = ecdh.agree(ecdhe-random, ecdhe-random-public)
        # Compute public key with the local private key and return a 512bits shared key
        ecdhe_shared_secret = self.ephemeral_ecc.get_ecdh_key(remote_pubkey)
        ecdhe_pubkey = self.ephemeral_ecc.get_pubkey()
        # shared-secret = sha3(ecdhe-shared-secret || sha3(nonce || remote-nonce))
        shared_secret = sha3(ecdhe_shared_secret +
                             sha3(ienc(self.nonce) + ienc(remote_nonce)))

        self.aes_secret = sha3(ecdhe_shared_secret + shared_secret)
        self.mac_secret = sha3(ecdhe_shared_secret + self.aes_secret)
        # egress-mac = sha3(mac-secret^nonce || auth)
        self.egress_mac = sha3(sxor(self.mac_secret, self.nonce) + ciphertext)
        # ingress-mac = sha3(mac-secret^remote-nonce || auth)
        self.ingress_mac = sha3(
            sxor(self.mac_secret, remote_nonce) + ciphertext)
        self.token = sha3(shared_secret)

        iv = pyelliptic.Cipher.gen_IV('aes-256-ctr')
        self.aes_enc = pyelliptic.Cipher(self.aes_secret,
                                         iv,
                                         1,
                                         ciphername='aes-256-ctr')
        self.aes_dec = pyelliptic.Cipher(self.aes_secret,
                                         iv,
                                         0,
                                         ciphername='aes-256-ctr')

        self.is_ready = True
Пример #22
0
 def __init__(self, ecc, is_initiator=False, ephemeral_privkey=None):
     self.ecc = ecc
     self.is_initiator = is_initiator
     self.ephemeral_ecc = ECCx(raw_privkey=ephemeral_privkey)
Пример #23
0
def test_ecies_decrypt():
    tv = test_values
    e = ECCx(raw_privkey=tv['receiver_private_key'])
    _dec = e.ecies_decrypt(tv['auth_ciphertext'])
    assert len(_dec) == len(tv['auth_plaintext'])
    assert _dec == tv['auth_plaintext']