def verify_client_auth(self, client_auth):
        """
        verify the client auth crypto envelope. this operation is performed
        by the server when it receives a client auth message.
        """
        scalar = crypto_scalarmult(bytes(self.local_ephemeral_key.private_key),
                                   bytes(self._remote_ephemeral_pub_key))
        scalar_remote_longterm = crypto_scalarmult(
            bytes(self.local_signing_key.private_key.to_curve25519_private_key(
            )), bytes(self._remote_ephemeral_pub_key))

        hasher = hashlib.sha256()
        hasher.update(self.application_key + scalar + scalar_remote_longterm)
        box_secret = hasher.digest()

        nonce = b"\x00" * 24
        message = crypto_box_open_afternm(client_auth, nonce, box_secret)
        self._client_vouch = message
        self.remote_longterm_pub_key = VerifyKey(message[:32])
        signature = message[32:]

        hasher = hashlib.sha256()
        scalar = crypto_scalarmult(bytes(self.local_ephemeral_key.private_key),
                                   bytes(self._remote_ephemeral_pub_key))
        hasher.update(scalar)
        hashed_value = hasher.digest()

        signed_message = self.application_key + bytes(
            self.local_signing_key.public_key) + hashed_value
        self.remote_longterm_pub_key.verify(signed_message,
                                            signature=signature)
    def create_client_auth(self):
        """
        this is the client authentication  cryptographic envelope
        which the client sends to the server. it's mathematical
        representation is as follows:

        Box_{box_secret}(data_to_box)

        where:
        box_secret = hash([K | crypto_scalarmult(a_priv, b_pub) | crypto_scalarmult(a_priv, B_pub)])
        data_to_box = A_pub | Sign_A_priv( K | B_pub | hash(crypto_scalarmult(a_priv, b_pub)))
        K = <<this is the application key>>
        """

        hasher = hashlib.sha256()
        scalar = crypto_scalarmult(bytes(self.local_ephemeral_key.private_key),
                                   bytes(self._remote_ephemeral_pub_key))
        hasher.update(scalar)
        hashed_value = hasher.digest()
        signed_message = self.local_signing_key.private_key.sign(
            self.application_key + bytes(self.remote_longterm_pub_key) +
            bytes(hashed_value))
        message_to_box = bytes(
            self.local_signing_key.public_key) + signed_message.signature
        self._client_auth = message_to_box
        scalar_remote_longterm = crypto_scalarmult(
            bytes(self.local_ephemeral_key.private_key),
            bytes(self.remote_longterm_pub_key.to_curve25519_public_key()))

        hasher = hashlib.sha256()  # XXX
        hasher.update(self.application_key + scalar + scalar_remote_longterm)
        box_secret = hasher.digest()

        nonce = b"\x00" * 24
        return crypto_box_afternm(message_to_box, nonce, box_secret)
    def create_server_accept(self):
        """
        create a server accept crypto envelope.
        this envelope is sent from the server to the client.
        it's math representation is the following:

        Box_{box_secret}(data_to_box)

        where:
        data_to_box = Sign_B( K | H | hash(crypto_scalarmult(b_priv, a_pub))
        box_secret = hash([ K | crypto_scalarmult(b_priv, a_pub) | crypto_scalarmult(B_priv, a_pub) | crypto_scalarmult(b_priv, A_pub) ])
        H = A_pub | Sign_A_priv( K | B_pub | hash(crypto_scalarmult(b_priv, a_pub)))
        K = <<this is the application key>>
        """
        message_to_sign = self.application_key + self._client_vouch + self._hashed_secret
        signed_message = self.local_signing_key.private_key.sign(
            message_to_sign)
        message_to_box = signed_message.signature
        local_longterm_sharedsecret = crypto_scalarmult(
            bytes(self.local_signing_key.private_key.to_curve25519_private_key(
            )), bytes(self._remote_ephemeral_pub_key))
        remote_longterm_sharedsecret = crypto_scalarmult(
            bytes(self.local_ephemeral_key.private_key),
            bytes(self.remote_longterm_pub_key.to_curve25519_public_key()))

        to_hash = self.application_key + self._secret + local_longterm_sharedsecret + remote_longterm_sharedsecret
        hasher = hashlib.sha256()
        hasher.update(to_hash)
        box_secret = hasher.digest()
        self._shared_secret = box_secret
        nonce = b"\x00" * 24
        return crypto_box_afternm(message_to_box, nonce, box_secret)
def init(prefs, the_ephemeral_key, has=False):
    encrypted_prefs = []
    for pref in prefs:
        if not has:
            hashed_reciprocal_pref = sha256(reciprocal_map[pref])
            want_pref = c.crypto_scalarmult(the_ephemeral_key, hashed_reciprocal_pref)
            encrypted_prefs.append(want_pref)
        else:
            hashed_pref = sha256(pref)
            have_pref = c.crypto_scalarmult(the_ephemeral_key, hashed_pref)
            encrypted_prefs.append(have_pref)
    return encrypted_prefs
def init(prefs, the_ephemeral_key, has=False):
    encrypted_prefs = []
    for pref in prefs:
        if not has:
            hashed_reciprocal_pref = sha256(reciprocal_map[pref])
            want_pref = c.crypto_scalarmult(the_ephemeral_key,
                                            hashed_reciprocal_pref)
            encrypted_prefs.append(want_pref)
        else:
            hashed_pref = sha256(pref)
            have_pref = c.crypto_scalarmult(the_ephemeral_key, hashed_pref)
            encrypted_prefs.append(have_pref)
    return encrypted_prefs
def bob(network):
    # Bob sends his haves
    bobs_prefs = map(lambda x: x.strip(), file("bob.txt").readlines())
    bobs_ephemeral_key = nacl.utils.random(32)
    bobs_encrypted_haves = init(bobs_prefs, bobs_ephemeral_key, True)
    # negotiate set size
    bobs_prefs_count = len(bobs_prefs)
    alices_prefs_count = network.recv()
    if bobs_prefs_count > alices_prefs_count:
        bobs_prefs_count = alices_prefs_count
    network.send(bobs_prefs_count)
    # compare prefs
    alices_encrypted_wants = []
    for i in range(0, bobs_prefs_count):
        # receive Alice's point and encrypt it
        alices_encrypted_want = c.crypto_scalarmult(bobs_ephemeral_key, network.recv())
        if alices_encrypted_want in alices_encrypted_wants:
            print "Bob feels somebody is cheating"
            return
        alices_encrypted_wants.append(alices_encrypted_want)
        # test if we are still interested
        if len(set.intersection(set(bobs_encrypted_haves), set(alices_encrypted_wants))) < i/10:
            print "Bob feels like this is going nowhere"
        # send encrypted point back
        network.send(alices_encrypted_wants[-1])
        # send bobs point
        network.send(bobs_encrypted_haves[i])
        # get it back encrypted
        bobs_encrypted_haves[i] = network.recv()
    for i in compare(bobs_encrypted_haves, alices_encrypted_wants, bobs_prefs):
        print "Bob learned:", i
def alice(network):
    # Alice sends her wants
    alices_prefs = map(lambda x: x.strip(), file("alice.txt").readlines())
    alices_ephemeral_key = nacl.utils.random(32)
    alices_encrypted_wants = init(alices_prefs, alices_ephemeral_key, False)
    # negotiate set size
    alices_prefs_count = len(alices_prefs)
    network.send(alices_prefs_count)
    bobs_prefs_count = network.recv()
    if alices_prefs_count > bobs_prefs_count:
        alices_prefs_count = bobs_prefs_count
    # compare prefs
    bobs_encrypted_haves = []
    for i in range(0, alices_prefs_count):
        # send Alice's point
        network.send(alices_encrypted_wants[i])
        # get it back encrypted
        alices_encrypted_wants[i] = network.recv()
        # get Bob's point and encrypt it
        bobs_encrypted_have = c.crypto_scalarmult(alices_ephemeral_key, network.recv())
        if bobs_encrypted_have in bobs_encrypted_haves:
            print "Alice feels somebody is cheating"
            return
        bobs_encrypted_haves.append(bobs_encrypted_have)
        # test if we are still interested
        if len(set.intersection(set(bobs_encrypted_haves), set(alices_encrypted_wants))) < i/10:
            print "Alice feels like this is going nowhere"
        network.send(bobs_encrypted_haves[-1])
    for i in compare(alices_encrypted_wants, bobs_encrypted_haves, alices_prefs):
        print "Alice learned:", i
Exemple #8
0
    def verify_server_accept(self, data):
        """Verify that the server's accept message is sane"""
        curve_lkey = self.local_key.to_curve25519_private_key()
        # b_alice is (A * b)
        b_alice = crypto_scalarmult(bytes(curve_lkey),
                                    self.remote_ephemeral_key)
        self.b_alice = b_alice
        # this is hash(K | a * b | a * B | A * b)
        self.box_secret = hashlib.sha256(self.application_key +
                                         self.shared_secret + self.a_bob +
                                         b_alice).digest()

        nonce = b"\x00" * 24

        try:
            # let's use the box secret to unbox our encrypted message
            signature = crypto_box_open_afternm(data, nonce, self.box_secret)
        except CryptoError:
            raise SHSError('Error decrypting server acceptance message')

        # we should have received sign(B)[K | H | hash(a * b)]
        # let's see if that signature can verify the reconstructed data on our side
        self.remote_pub_key.verify(
            self.application_key + self.hello + self.shared_hash, signature)
        return True
def alice(network):
    # Alice sends her wants
    alices_prefs = map(lambda x: x.strip(), file("alice.txt").readlines())
    alices_ephemeral_key = nacl.utils.random(32)
    alices_encrypted_wants = init(alices_prefs, alices_ephemeral_key, False)
    # negotiate set size
    alices_prefs_count = len(alices_prefs)
    network.send(alices_prefs_count)
    bobs_prefs_count = network.recv()
    if alices_prefs_count > bobs_prefs_count:
        alices_prefs_count = bobs_prefs_count
    # compare prefs
    bobs_encrypted_haves = []
    for i in range(0, alices_prefs_count):
        # send Alice's point
        network.send(alices_encrypted_wants[i])
        # get it back encrypted
        alices_encrypted_wants[i] = network.recv()
        # get Bob's point and encrypt it
        bobs_encrypted_have = c.crypto_scalarmult(alices_ephemeral_key,
                                                  network.recv())
        if bobs_encrypted_have in bobs_encrypted_haves:
            print "Alice feels somebody is cheating"
            return
        bobs_encrypted_haves.append(bobs_encrypted_have)
        # test if we are still interested
        if len(
                set.intersection(set(bobs_encrypted_haves),
                                 set(alices_encrypted_wants))) < i / 10:
            print "Alice feels like this is going nowhere"
        network.send(bobs_encrypted_haves[-1])
    for i in compare(alices_encrypted_wants, bobs_encrypted_haves,
                     alices_prefs):
        print "Alice learned:", i
Exemple #10
0
def encrypt_for_node(identity: Identity, public_key: str,
                     payload: Union[str, bytes]) -> str:
    """
    encrypt payload using a nacl.SecretBox with a shared key derived from the public key of the node and private key of the user

    Args:
      identity(Identity): the identity object that contains the key pair of the user
      public_key(str): public key of the node, hex-encoded
      payload(Union[str, bytes]): any data you want to encrypt

    Returns:
      str: hex-encoded encrypted data. you can use this safely into your reservation data

    """
    user_private = identity.nacl.signing_key.to_curve25519_private_key(
    ).encode()

    node_verify_bin = binascii.unhexlify(public_key)
    node_public = VerifyKey(node_verify_bin).to_curve25519_public_key()
    node_public = node_public.encode()

    shared_secret = crypto_scalarmult(user_private, node_public)
    h = blake2b(shared_secret, digest_size=32)
    key = h.digest()

    if isinstance(payload, str):
        payload = payload.encode()

    box = SecretBox(key)
    encrypted = box.encrypt(payload)
    return binascii.hexlify(encrypted)
def bob(network):
    # Bob sends his haves
    bobs_prefs = map(lambda x: x.strip(), file("bob.txt").readlines())
    bobs_ephemeral_key = nacl.utils.random(32)
    bobs_encrypted_haves = init(bobs_prefs, bobs_ephemeral_key, True)
    # negotiate set size
    bobs_prefs_count = len(bobs_prefs)
    alices_prefs_count = network.recv()
    if bobs_prefs_count > alices_prefs_count:
        bobs_prefs_count = alices_prefs_count
    network.send(bobs_prefs_count)
    # compare prefs
    alices_encrypted_wants = []
    for i in range(0, bobs_prefs_count):
        # receive Alice's point and encrypt it
        alices_encrypted_want = c.crypto_scalarmult(bobs_ephemeral_key,
                                                    network.recv())
        if alices_encrypted_want in alices_encrypted_wants:
            print "Bob feels somebody is cheating"
            return
        alices_encrypted_wants.append(alices_encrypted_want)
        # test if we are still interested
        if len(
                set.intersection(set(bobs_encrypted_haves),
                                 set(alices_encrypted_wants))) < i / 10:
            print "Bob feels like this is going nowhere"
        # send encrypted point back
        network.send(alices_encrypted_wants[-1])
        # send bobs point
        network.send(bobs_encrypted_haves[i])
        # get it back encrypted
        bobs_encrypted_haves[i] = network.recv()
    for i in compare(bobs_encrypted_haves, alices_encrypted_wants, bobs_prefs):
        print "Bob learned:", i
Exemple #12
0
    def verify_client_auth(self, data):
        assert len(data) == 112
        a_bob = crypto_scalarmult(bytes(self.local_key.to_curve25519_private_key()), self.remote_ephemeral_key)
        box_secret = hashlib.sha256(self.application_key + self.shared_secret + a_bob).digest()
        self.hello = crypto_box_open_afternm(data, b'\x00' * 24, box_secret)
        signature, public_key = self.hello[:64], self.hello[64:]
        signed = self.application_key + bytes(self.local_key.verify_key) + self.shared_hash
        pkey = VerifyKey(public_key)

        # will raise an exception if verification fails
        pkey.verify(signed, signature)
        self.remote_pub_key = pkey
        b_alice = crypto_scalarmult(bytes(self.local_ephemeral_key),
                                    bytes(self.remote_pub_key.to_curve25519_public_key()))
        self.box_secret = hashlib.sha256(self.application_key + self.shared_secret + a_bob + b_alice).digest()[:32]
        return True
Exemple #13
0
def x25519_scalarmult(secret_scalar: ECScalar, point: ECPoint) -> ECPoint:
    """Scalar multiplication of ``point`` with (secret) ``scalar``

    :param secret_scalar: Scalar (integer) `n`, in byte representation (:class:`ECScalar`)
    :param point: Point on curve `P`, in byte representation (:class:`ECPoint`)
    :returns: New point on curve: :math:`nP = P + P + P + P + P + \\text{...}` (`n` times)
    """

    k = crypto_scalarmult(secret_scalar, point)
    assert any(k), "All-zeros-check failed (see RFC 7748, section 6.1)"
    return ECPoint(k)
Exemple #14
0
def _EXP(n, p):
    '''
    .. note:: See tor-spec Section 5.1.4 for why this is an adequate
    replacement for checking that none of the EXP() operations produced
    the point at infinity.

    :returns: **str** result
    '''
    ret = bindings.crypto_scalarmult(bytes(n), bytes(PublicKey(p)))
    bad = util.constantStrAllZero(ret)
    return (ret, bad)
    def verify_server_accept(self, server_accept_envelope):
        """
        this is used by the client to verify the server accept envelope
        """
        remote_longterm_sharedsecret = crypto_scalarmult(
            bytes(self.local_ephemeral_key.private_key),
            bytes(self.remote_longterm_pub_key.to_curve25519_public_key()))
        local_longterm_sharedsecret = crypto_scalarmult(
            bytes(self.local_signing_key.private_key.to_curve25519_private_key(
            )), bytes(self._remote_ephemeral_pub_key))

        to_hash = self.application_key + self._secret + remote_longterm_sharedsecret + local_longterm_sharedsecret
        hasher = hashlib.sha256()
        hasher.update(to_hash)
        box_secret = hasher.digest()
        self._shared_secret = box_secret
        nonce = b"\x00" * 24
        signature = crypto_box_open_afternm(server_accept_envelope, nonce,
                                            box_secret)
        message = self.application_key + self._client_auth + self._hashed_secret
        self.remote_longterm_pub_key.verify(message, signature)
Exemple #16
0
def test_scalarmult():
    x, xpub = secret_scalar()
    assert len(x) == 32
    y, ypub = secret_scalar()
    # the Curve25519 base point (generator)
    base = unhexlify(b"09" + b"00" * 31)

    bx1 = c.crypto_scalarmult_base(x)
    bx2 = c.crypto_scalarmult(x, base)
    assert tohex(bx1) == tohex(bx2)
    assert tohex(bx1) == tohex(xpub)

    xby = c.crypto_scalarmult(x, c.crypto_scalarmult_base(y))
    ybx = c.crypto_scalarmult(y, c.crypto_scalarmult_base(x))
    assert tohex(xby) == tohex(ybx)

    z = unhexlify(b"10" * 32)
    bz1 = c.crypto_scalarmult_base(z)
    assert tohex(bz1) == ("781faab908430150daccdd6f9d6c5086"
                          "e34f73a93ebbaa271765e5036edfc519")
    bz2 = c.crypto_scalarmult(z, base)
    assert tohex(bz1) == tohex(bz2)
Exemple #17
0
def test_scalarmult():
    x, xpub = secret_scalar()
    assert len(x) == 32
    y, ypub = secret_scalar()
    # the Curve25519 base point (generator)
    base = unhexlify(b"09" + b"00" * 31)

    bx1 = c.crypto_scalarmult_base(x)
    bx2 = c.crypto_scalarmult(x, base)
    assert tohex(bx1) == tohex(bx2)
    assert tohex(bx1) == tohex(xpub)

    xby = c.crypto_scalarmult(x, c.crypto_scalarmult_base(y))
    ybx = c.crypto_scalarmult(y, c.crypto_scalarmult_base(x))
    assert tohex(xby) == tohex(ybx)

    z = unhexlify(b"10" * 32)
    bz1 = c.crypto_scalarmult_base(z)
    assert tohex(bz1) == ("781faab908430150daccdd6f9d6c5086"
                          "e34f73a93ebbaa271765e5036edfc519")
    bz2 = c.crypto_scalarmult(z, base)
    assert tohex(bz1) == tohex(bz2)
 def is_server_challenge_verified(self, challenge):
     """
     this is used by the client side to verify
     a challenge from the server.
     if verified returns True, otherwise returns False.
     """
     assert len(challenge) == 64
     mac = challenge[:32]
     remote_ephemeral_pub_key = challenge[32:64]
     scalar_val = crypto_scalarmult(
         bytes(self.local_ephemeral_key.private_key),
         bytes(remote_ephemeral_pub_key))
     hmac_key = self.application_key[:32] + scalar_val
     h = hmac.HMAC(hmac_key, hashes.SHA512(), backend=default_backend())
     h.update(bytes(remote_ephemeral_pub_key))
     new_hmac = h.finalize()[:32]
     ok = new_hmac == mac
     self._remote_ephemeral_pub_key = PublicKey(remote_ephemeral_pub_key)
     self._remote_app_mac = mac
     self._secret = crypto_scalarmult(
         bytes(self.local_ephemeral_key.private_key),
         remote_ephemeral_pub_key)
     self._hashed_secret = hashlib.sha256(self._secret).digest()
     return ok
Exemple #19
0
    def _scalarMult(self, base):
        '''Perform base**self._secret_key.

        Set self.is_bad if the result is all zeros.

        .. note:: See tor-spec Section 5.1.4 for why this is an adequate
        replacement for checking that none of the EXP() operations produced
        the point at infinity.

        :returns: **str** result
        '''
        # args are: exponent, base
        ret = bindings.crypto_scalarmult(bytes(self._secret_key),
                                         bytes(PublicKey(base)))
        self.is_bad |= util.constantStrAllZero(ret)
        return ret
Exemple #20
0
    def verify_challenge(self, data):
        """Verify the correctness of challenge sent from the client."""
        assert len(data) == 64
        sent_hmac, remote_ephemeral_key = data[:32], data[32:]

        h = hmac.new(self.application_key, remote_ephemeral_key, digestmod='sha512')
        self.remote_app_hmac = h.digest()[:32]
        ok = self.remote_app_hmac == sent_hmac

        if ok:
            # this is (a * b)
            self.shared_secret = crypto_scalarmult(bytes(self.local_ephemeral_key), remote_ephemeral_key)
            self.remote_ephemeral_key = remote_ephemeral_key
            # this is hash(a * b)
            self.shared_hash = hashlib.sha256(self.shared_secret).digest()
        return ok
Exemple #21
0
    def verify_server_challenge(self, data):
        """Verify the correctness of challenge sent from the server."""
        assert super(SHSClientCrypto, self).verify_challenge(data)
        curve_pkey = self.remote_pub_key.to_curve25519_public_key()

        # a_bob is (a * B)
        a_bob = crypto_scalarmult(bytes(self.local_ephemeral_key), bytes(curve_pkey))
        self.a_bob = a_bob
        # this shall be hash(K | a * b | a * B)
        self.box_secret = hashlib.sha256(self.application_key + self.shared_secret + a_bob).digest()

        # and message_to_box will correspond to H = sign(A)[K | Bp | hash(a * b)] | Ap
        signed_message = self.local_key.sign(self.application_key + bytes(self.remote_pub_key) + self.shared_hash)
        message_to_box = signed_message.signature + bytes(self.local_key.verify_key)
        self.hello = message_to_box
        return True
Exemple #22
0
    def _scalarMult(self, base):
        '''Perform base**self._secret_key.

        Set self.is_bad if the result is all zeros.

        .. note:: See tor-spec Section 5.1.4 for why this is an adequate
        replacement for checking that none of the EXP() operations produced
        the point at infinity.

        :returns: **str** result
        '''
        # args are: exponent, base
        ret = bindings.crypto_scalarmult(bytes(self._secret_key),
                                         bytes(PublicKey(base)))
        self.is_bad |= util.constantStrAllZero(ret)
        return ret
    def create_server_challenge(self):
        """
        this is the challenge envelope that the server sends to the client.
        this envelope's crypto math representation:

        b_pub, hmac_{[ K | crypto_scalarmult(b_priv, a_pub) ]}(b_pub)

        where:
        K = <<this is the application key>>
        """
        scalar = crypto_scalarmult(bytes(self.local_ephemeral_key.private_key),
                                   bytes(self._remote_ephemeral_pub_key))
        hmac_key = self.application_key + scalar
        h = hmac.HMAC(hmac_key, hashes.SHA512(), backend=default_backend())
        h.update(bytes(self.local_ephemeral_key.public_key))
        _hmac = h.finalize()
        return _hmac[:32] + bytes(self.local_ephemeral_key.public_key)
Exemple #24
0
def _put_key(pubkeyb64, eph_secret, file_key):
    """This method encrypts file key using X25519 and returns X25519 line
    argument list.

    Args:
        pubkeyb64: target base64url-encode X25519 public key.

        eph_secret: 32-bytes ephemeral secret.

        file_key: file key to encrypt using X25519.

    Returns:
        X25519 line argument list.

    It raises ValueError whether some issue is detected.

    """
    # compute ephemeral public key
    try:
        eph_pub_key = crypto_scalarmult_base(eph_secret)
    except NaclRuntimeError:
        raise ValueError('Libsodium prevented all-zeros X25519 output.')
    # decode static public key
    static_pub_key = encoding._decode(pubkeyb64)
    # compute shared key
    try:
        shared_key = crypto_scalarmult(eph_secret, static_pub_key)
    except NaclRuntimeError:
        raise ValueError('Libsodium prevented all-zeros X25519 output.')
    # compute key encryption key
    kek = HKDF(algorithm=hashes.SHA256(),
               length=32,
               salt=eph_pub_key + static_pub_key,
               info=b'age-tool.com X25519',
               backend=default_backend()).derive(shared_key)
    # encrypt file key
    enc_file_key = symencrypt._encrypt_key(kek, file_key)
    # build and return X25519 line argument list
    argl = [encoding._encode(eph_pub_key), encoding._encode(enc_file_key)]
    return argl
    def is_client_challenge_verified(self, challenge):
        """
        this is used by the server side.
        if i can verify the challenge then return True
        otherwise return False
        """
        assert len(challenge) == 64
        mac = challenge[:32]
        remote_ephemeral_pub_key = challenge[32:64]

        h = hmac.HMAC(self.application_key[:32],
                      hashes.SHA512(),
                      backend=default_backend())
        h.update(bytes(remote_ephemeral_pub_key))
        new_hash = h.finalize()[:32]
        ok = new_hash == mac
        self._remote_ephemeral_pub_key = PublicKey(remote_ephemeral_pub_key)
        self._remote_app_mac = mac
        self._secret = crypto_scalarmult(
            bytes(self.local_ephemeral_key.private_key),
            remote_ephemeral_pub_key)
        self._hashed_secret = hashlib.sha256(self._secret).digest()
        return ok
Exemple #26
0
def _get_key(argl, pubkeyb64, privkeyb64):
    """This method decrypts file key from X25519 line arguments.

    Args:
        argl: X25519 line argument list.

        pubkeyb64: base64url-encode X25519 public key.

        privkeyb64: base64url-encode X25519 private key.

    Returns:
        File key.

    It raises ValueError whether some issue is detected.

    """
    # decode ephemeral public key
    eph_pub_key = encoding._decode(argl[0])
    # decode encrypted file key
    enc_file_key = encoding._decode(argl[1])
    # decode static public key
    static_pub_key = encoding._decode(pubkeyb64)
    # decode static private key
    priv_key = encoding._decode(privkeyb64)
    # compute shared key
    try:
        shared_key = crypto_scalarmult(priv_key, eph_pub_key)
    except NaclRuntimeError:
        raise ValueError('Libsodium prevented all-zeros X25519 output.')
    # compute key encryption key
    kek = HKDF(algorithm=hashes.SHA256(),
               length=32,
               salt=eph_pub_key + static_pub_key,
               info=b'age-tool.com X25519',
               backend=default_backend()).derive(shared_key)
    # decrypt and return file key
    return symencrypt._decrypt_key(kek, enc_file_key)
Exemple #27
0
 def expon_base(self, exp):
     base = crypto_scalarmult_base(exp[0])        
     for f in exp[1:]:
         base = crypto_scalarmult(f, base)
     return base
Exemple #28
0
    def tls_response(self):
        while True:
            head = yield from iofree.read(5)
            assert head[
                1:3] == b"\x03\x03", f"bad legacy_record_version {head[1:3]}"
            length = int.from_bytes(head[3:], "big")
            content = memoryview((yield from iofree.read(length)))
            if head[0] == ContentType.alert:
                level = AlertLevel.from_value(content[0])
                description = AlertDescription.from_value(content[1])
                raise Alert(level, description)
            elif head[0] == ContentType.handshake:
                self.peer_handshake = self.unpack_handshake(content)
                assert (self.peer_handshake.handshake_type ==
                        HandshakeType.server_hello), "expect server hello"
                peer_pk = self.peer_handshake.extensions[
                    ExtensionType.key_share].key_exchange
                shared_key = crypto_scalarmult(bytes(self.private_key),
                                               peer_pk)
                TLSCipher = self.peer_handshake.cipher_suite
                key_scheduler = TLSCipher.tls_hash.scheduler(shared_key)
                secret = key_scheduler.server_handshake_traffic_secret(
                    self.get_context())
                # server handshake cipher
                self.peer_cipher = TLSCipher(secret)
                client_handshake_traffic_secret = key_scheduler.client_handshake_traffic_secret(
                    self.get_context())
            elif head[0] == ContentType.application_data:
                plaintext = self.peer_cipher.decrypt(content,
                                                     head).rstrip(b"\x00")
                content_type = ContentType.from_value(plaintext[-1])
                if content_type == ContentType.handshake:
                    self.unpack_handshake(plaintext[:-1])
                    if self.server_finished:
                        # client handshake cipher
                        self.cipher = TLSCipher(
                            client_handshake_traffic_secret)
                        context = b"".join(self.handshake_context)
                        client_finished = self.cipher.verify_data(context)
                        inner_plaintext = HandshakeType.finished.tls_inner_plaintext(
                            client_finished)
                        record = self.cipher.tls_ciphertext(inner_plaintext)
                        change_cipher_spec = ContentType.change_cipher_spec.tls_plaintext(
                            b"\x01")
                        yield from iofree.write(change_cipher_spec + record)
                        # server application cipher
                        server_secret = key_scheduler.server_application_traffic_secret_0(
                            self.get_context())
                        self.peer_cipher = TLSCipher(server_secret)
                        self.server_finished = False

                        # client application cipher
                        client_secret = key_scheduler.client_application_traffic_secret_0(
                            self.get_context())
                        self.cipher = TLSCipher(client_secret)

                elif content_type == ContentType.application_data:
                    yield from iofree.write(plaintext[:-1])
                elif content_type == ContentType.alert:
                    level = AlertLevel.from_value(plaintext[0])
                    description = AlertDescription.from_value(plaintext[1])
                    raise Alert(level, description)
                elif content_type == ContentType.invalid:
                    raise Exception("invalid content type")
                else:
                    raise Exception(f"unexpected content type {content_type}")
            elif head[0] == ContentType.change_cipher_spec:
                assert content == b"\x01", "change_cipher should be 0x01"
            else:
                raise Exception(f"Unknown content type: {head[0]}")
Exemple #29
0
 def ecdh(self, other_public_key):
     return crypto_scalarmult(self.private_key, other_public_key)
Exemple #30
0
 def expon(self, base, exp):
     return crypto_scalarmult(bytes(exp), bytes(base))
Exemple #31
0
 def mix_dh(self, priv, pub):
     # XXX unfortunately this fails for public keys such as 0 and 1 because
     # libsodium ref10 implementation rejects some small-order points.
     sk, pk = _to_bytes(priv), _to_bytes(pub)
     secret = crypto_scalarmult(sk, pk)
     self.ck, self.k = hkdf(self.ck, secret, 2)
Exemple #32
0
def get_session_keys(conn, pairing_data):
    """
    Perform a pair verify operation as described in chapter 4.8 page 47 ff.

    :param conn: the http connection to the target accessory
    :param pairing_data: the paring data as returned by perform_pair_setup
    :returns: tuple of the session keys (controller_to_accessory_key and
              accessory_to_controller_key)
    """
    headers = {
        'Content-Type': 'application/pairing+tlv8'
    }

    # Step #1 ios --> accessory (send verify start request) (page 47)
    ios_key = PrivateKey.generate()

    request_tlv = TLV.encode_dict({
        TLV.kTLVType_State: TLV.M1,
        TLV.kTLVType_PublicKey: bytes(ios_key.public_key),
    })

    try:
        conn.request('POST', '/pair-verify', request_tlv, headers)
        resp = conn.getresponse()
    except (TimeoutError, HTTPException, OSError):
        return None

    response_tlv = TLV.decode_bytes(resp.read())

    # Step #3 ios --> accessory (send SRP verify request)  (page 49)
    if TLV.kTLVType_State not in response_tlv:
        return None

    if response_tlv[TLV.kTLVType_State] != TLV.M2:
        return None

    if TLV.kTLVType_PublicKey not in response_tlv:
        return None

    if TLV.kTLVType_EncryptedData not in response_tlv:
        return None

    # 1) generate shared secret
    accessorys_session_pub_key_bytes = \
        bytes(response_tlv[TLV.kTLVType_PublicKey])
    shared_secret = crypto_scalarmult(
        bytes(ios_key),
        bytes(PublicKey(accessorys_session_pub_key_bytes)))

    # 2) derive session key
    hkdf_inst = hkdf.Hkdf('Pair-Verify-Encrypt-Salt'.encode(),
                          shared_secret,
                          hash=hashlib.sha512)
    session_key = hkdf_inst.expand('Pair-Verify-Encrypt-Info'.encode(), 32)

    # 3) verify authtag on encrypted data and 4) decrypt
    encrypted = response_tlv[TLV.kTLVType_EncryptedData]
    decrypted = crypto_aead_chacha20poly1305_ietf_decrypt(
        bytes(encrypted),
        bytes(),
        bytes([0, 0, 0, 0]) + 'PV-Msg02'.encode(),
        session_key)

    if not decrypted:
        return None

    d1 = TLV.decode_bytes(decrypted)

    if TLV.kTLVType_Identifier not in d1:
        return None

    if TLV.kTLVType_Signature not in d1:
        return None

    # 5) look up pairing by accessory name
    accessory_name = d1[TLV.kTLVType_Identifier].decode()

    if pairing_data['AccessoryPairingID'] != accessory_name:
        return None

    accessory_ltpk = VerifyKey(bytes.fromhex(pairing_data['AccessoryLTPK']))

    # 6) verify accessory's signature
    accessory_sig = d1[TLV.kTLVType_Signature]
    accessory_session_pub_key_bytes = response_tlv[TLV.kTLVType_PublicKey]
    accessory_info = accessory_session_pub_key_bytes + \
        accessory_name.encode() + bytes(ios_key.public_key)
    try:
        accessory_ltpk.verify(bytes(accessory_info), bytes(accessory_sig))
    except BadSignatureError:
        return None

    # 7) create iOSDeviceInfo
    ios_device_info = bytes(ios_key.public_key) + \
        pairing_data['iOSPairingID'].encode() + \
        accessorys_session_pub_key_bytes

    # 8) sign iOSDeviceInfo with long term secret key
    ios_device_ltsk_h = pairing_data['iOSDeviceLTSK']
    ios_device_ltsk = SigningKey(bytes.fromhex(ios_device_ltsk_h))
    ios_device_signature = ios_device_ltsk.sign(ios_device_info).signature

    # 9) construct sub tlv
    sub_tlv = TLV.encode_dict({
        TLV.kTLVType_Identifier: pairing_data['iOSPairingID'].encode(),
        TLV.kTLVType_Signature: ios_device_signature
    })

    # 10) encrypt and sign
    ciphertext = crypto_aead_chacha20poly1305_ietf_encrypt(
        bytes(sub_tlv),
        bytes(),
        bytes([0, 0, 0, 0]) + 'PV-Msg03'.encode(),
        session_key)
    tmp = ciphertext

    # 11) create tlv
    request_tlv = TLV.encode_dict({
        TLV.kTLVType_State: TLV.M3,
        TLV.kTLVType_EncryptedData: tmp
    })

    # 12) send to accessory
    try:
        conn.request('POST', '/pair-verify', request_tlv, headers)
        resp = conn.getresponse()
    except (TimeoutError, HTTPException, OSError):
        return None

    response_tlv = TLV.decode_bytes(resp.read())

    # Post Step #4 verification (page 51)
    if TLV.kTLVType_State not in response_tlv:
        return None

    if response_tlv[TLV.kTLVType_State] != TLV.M4:
        return None

    if TLV.kTLVType_Error in response_tlv:
        return None

    # calculate session keys
    hkdf_inst = hkdf.Hkdf('Control-Salt'.encode(),
                          shared_secret,
                          hash=hashlib.sha512)
    controller_to_accessory_key = \
        hkdf_inst.expand('Control-Write-Encryption-Key'.encode(), 32)

    hkdf_inst = hkdf.Hkdf('Control-Salt'.encode(),
                          shared_secret,
                          hash=hashlib.sha512)
    accessory_to_controller_key = \
        hkdf_inst.expand('Control-Read-Encryption-Key'.encode(), 32)

    return controller_to_accessory_key, accessory_to_controller_key
 def expon_base(self, exp):
     assert len(exp) > 0
     base = crypto_scalarmult_base(_expand32(exp[0]))   
     for f in exp[1:]:
         base = crypto_scalarmult(_expand32(f), base)
     return base
Exemple #34
0
def generate_shared_secret_key(our_private_key: PrivateKey,
                               peer_public_key: PublicKey) -> SecretKey:
    return SecretKey(
        crypto_scalarmult(our_private_key.encode(), peer_public_key.encode()))
Exemple #35
0
 def expon(self, base, exp):        
     for f in exp:
         base = crypto_scalarmult(f, base)
     return base