def test_lib_crypto_ecc_exchange(self):
        spvk1 = s_ecc.PriKey.generate()
        spbk1 = spvk1.public()

        spvk2 = s_ecc.PriKey.generate()
        spbk2 = spvk2.public()

        k1 = (spvk1.exchange(spbk2))
        k2 = (spvk2.exchange(spbk1))
        self.eq(k1, k2)

        # Curves must be the same
        _pkd = c_ec.generate_private_key(
            c_ec.SECP192R1(),  # We don't use this curve
            default_backend())
        prkdiff = s_ecc.PriKey(_pkd)
        pbkdiff = prkdiff.public()
        self.raises(BadEccExchange, spvk1.exchange, pbkdiff)
        self.raises(BadEccExchange, prkdiff.exchange, spbk1)

        # Do a demonstrative ephemeral exchange
        epvk1 = s_ecc.PriKey.generate()
        epbk1 = epvk1.public()

        epvk2 = s_ecc.PriKey.generate()
        epbk2 = epvk2.public()

        # assume epbk2 is sent to the owner of pvk1
        z1e = epvk1.exchange(epbk2)
        z1s = spvk1.exchange(spbk2)
        z1 = z1e + z1s

        # assume epbk1 is sent to the owner of pvk2
        z2e = epvk2.exchange(epbk1)
        z2s = spvk2.exchange(spbk1)
        z2 = z2e + z2s

        self.eq(z1, z2)

        # run through kdf
        kdf1 = c_hkdf.HKDF(c_hashes.SHA256(),
                           length=64,
                           salt=None,
                           info=b'test',
                           backend=default_backend())
        k1 = kdf1.derive(z1)
        k1tx, k1rx = k1[32:], k1[:32]

        kdf2 = c_hkdf.HKDF(c_hashes.SHA256(),
                           length=64,
                           salt=None,
                           info=b'test',
                           backend=default_backend())
        k2 = kdf2.derive(z2)
        k2rx, k2tx = k2[32:], k2[:32]

        self.eq(k1tx, k2rx)
        self.eq(k1rx, k2tx)
        self.ne(k1tx, k2tx)
def verify_encrypted_message(message, ephemeral_public_key_bytes, priv_keys):
    ephemeral_public_key = ec.EllipticCurvePublicKey.from_encoded_point(
        ec.SECP256R1(), ephemeral_public_key_bytes)
    for k in priv_keys:
        sharedKey = k.exchange(ec.ECDH(), ephemeral_public_key)

        kdf = hkdf.HKDF(
            algorithm=hashes.SHA256(),
            length=512 // 8,
            salt=b"\0",
            info=b"Google",
            backend=backend,
        )
        sharedKey = kdf.derive(ephemeral_public_key_bytes + sharedKey)

        symmetricEncryptionKey = sharedKey[:256 // 8]
        macKey = sharedKey[256 // 8:]
        encryptedMessage = base64.b64decode(message["encryptedMessage"])

        h = hmac.HMAC(macKey, hashes.SHA256(), backend)
        h.update(encryptedMessage)
        try:
            h.verify(base64.b64decode(message["tag"]))
        except cryptography.exceptions.InvalidSignature:
            continue

        cipher = Cipher(algorithms.AES(symmetricEncryptionKey),
                        modes.CTR(b"\0" * 16), backend)
        decryptor = cipher.decryptor()
        message = decryptor.update(encryptedMessage) + decryptor.finalize()
        return json.loads(message)
    raise GPayError("no private key worked")
Exemple #3
0
    def _ratchet(secret, proxy, salt_ghid):
        ''' Ratchets a key using HKDF-SHA512, using the associated
        address as salt. For dynamic files, this should be the previous
        frame ghid (not the dynamic ghid).
        
        Note: this ratchet is bound to a particular dynamic address. The
        ratchet algorithm is:
        
        new_key = HKDF-SHA512(
            IKM = old_secret, (secret IV/nonce | secret key)
            salt = old_frame_ghid, (entire 65 bytes)
            info = dynamic_ghid, (entire 65 bytes)
            new_key_length = len(IV/nonce) + len(key),
            num_keys = 1,
        )
        '''
        cls = type(secret)
        cipher = secret.cipher
        version = secret.version
        len_seed = len(secret.seed)
        len_key = len(secret.key)
        source = bytes(secret.seed + secret.key)

        instance = hkdf.HKDF(algorithm=hashes.SHA512(),
                             length=len_seed + len_key,
                             salt=bytes(salt_ghid),
                             info=bytes(proxy),
                             backend=CRYPTO_BACKEND)
        ratcheted = instance.derive(source)

        return cls(cipher=cipher,
                   version=version,
                   key=ratcheted[:len_key],
                   seed=ratcheted[len_key:])
Exemple #4
0
def _v1_derive_key(k, n, info):
    h = hkdf.HKDF(
        algorithm=hashes.SHA384(),
        length=32,
        salt=n[:16],
        info=info,
        backend=backends.default_backend(),
    )
    return h.derive(k)
Exemple #5
0
 def stretch_key(self, key, salt):
     kdf = hkdf.HKDF(
         algorithm=hashes.SHA256(),
         length=self.key_size / 8,
         salt=salt,
         info=None,
         backend=backends.default_backend(),
     )
     return kdf.derive(key)
 def _hkdf(self, base_key, info_prefix):
     local_hkdf = hkdf.HKDF(
         algorithm=hashes.SHA384(),
         length=32,
         salt=self.table.encode(),
         info=info_prefix + self.field.encode(),
         backend=openssl_backend,
     )
     output = local_hkdf.derive(base_key)
     return output
Exemple #7
0
def kdf_rfc5869_derive(secret_input_bytes, output_len, m_expand=M_EXPAND_NTOR,
                       t_key=T_KEY_NTOR):
    '''
    Return output_len bytes generated from secret_input_bytes using RFC5869
    with HKDF-SHA256.
    There is no equivalent verification function, as only the nonce part of
    the KDF result is verified directly.
    See https://gitweb.torproject.org/torspec.git/tree/tor-spec.txt#n1026
    '''
    hkdf_sha256 = hkdf.HKDF(algorithm=hashes.SHA256(),
                            length=output_len,
                            info=bytes(m_expand),
                            salt=bytes(t_key),
                            backend=backends.default_backend())
    output_bytes = hkdf_sha256.derive(bytes(secret_input_bytes))
    assert len(output_bytes) == output_len
    return bytearray(output_bytes)
Exemple #8
0
    def _derive_shared(self, partner):
        ''' Derive a shared secret with the partner.
        '''
        # Call the donna25519 exchange method and return bytes
        ecdh = self._exchange_key.do_exchange(partner._exchange_key)

        # Get both of our addresses and then the bitwise XOR of them both
        my_hash = self.ghid.address
        their_hash = partner.ghid.address
        salt = bytes([a ^ b for a, b in zip(my_hash, their_hash)])

        instance = hkdf.HKDF(algorithm=hashes.SHA512(),
                             length=hashes.SHA512.digest_size,
                             salt=salt,
                             info=b'',
                             backend=CRYPTO_BACKEND)
        key = instance.derive(ecdh)
        # Might as well do this immediately, not that it really adds anything
        del ecdh, my_hash, their_hash, salt
        return key
Exemple #9
0
def doECDHE(statprv_u,
            statpub_v,
            ephmprv_u,
            ephmpub_v,
            length=64,
            salt=None,
            info=None):
    '''
    Perform one side of an Ecliptic Curve Diffie Hellman Ephemeral key exchange.

    Args:
        statprv_u (PriKey): Static Private Key for U
        statpub_v (PubKey: Static Public Key for V
        ephmprv_u (PriKey): Ephemeral Private Key for U
        ephmpub_v (PubKey): Ephemeral Public Key for V
        length (int): Number of bytes to return
        salt (bytes): Salt to use when computing the key.
        info (bytes): Additional information to use when computing the key.

    Notes:
        This makes no assumption about the reuse of the Ephemeral keys passed
        to the function. It is the caller's responsibility to destroy the keys
        after they are used for doing key generation. This implementation is
        the dhHybrid1 scheme described in NIST 800-56A Revision 2.

    Returns:
        bytes: The derived key.
    '''
    zs = statprv_u.exchange(statpub_v)
    ze = ephmprv_u.exchange(ephmpub_v)
    z = ze + zs
    kdf = c_hkdf.HKDF(c_hashes.SHA256(),
                      length=length,
                      salt=salt,
                      info=info,
                      backend=default_backend())
    k = kdf.derive(z)
    return k
Exemple #10
0
    def generate_shared_key(my_private, peer_public, salt: bytes = b""):
        """Derive the shared key for file encryption."""

        # Generate or from db
        if salt == b"":
            salt = os.urandom(16)

        # Project public key
        # peer_public_bytes = bytes.fromhex(peer_public)
        # loaded_peer_public = x25519.X25519PublicKey.from_public_bytes(peer_public_bytes)

        # Generate shared key and derive encryption key with salt
        shared_key = (my_private).exchange(peer_public_key=peer_public)
        derived_shared_key = hkdf.HKDF(
            algorithm=hashes.SHA256(),
            length=32,
            salt=salt,
            info=b"",
            backend=backends.default_backend(),
        ).derive(shared_key)

        LOG.debug(f"Salt: {salt}")
        return derived_shared_key, salt.hex().upper()
Exemple #11
0
def keyderivation(private, peer, salt, info):
    private = x25519.X25519PrivateKey._from_private_bytes(private)
    public = x25519.X25519PublicKey.from_public_bytes(peer)
    shared = private.exchange(public)
    return hkdf.HKDF(hashes.BLAKE2b(64), 32, salt, info,
                     default_backend()).derive(shared)
Exemple #12
0
    def initialize_session_key(self, address, actions):
        # asks for a challenge
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        message = "{\"type\" : \"ask_challenge\"," + "\n"
        message += "\"username\" : \"" + self.username + "\"" + "\n"
        message += "}"
        sock.sendto(base64.b64encode(message.encode("utf-8")), address)

        # receives the challenge
        data, server = sock.recvfrom(utils_app.SOCKET_BYTES)
        decoded_message = base64.b64decode(data)
        sock.close()
        message = json.loads(decoded_message, strict=False)
        challenge = message["challenge"]

        # Our parameters
        parameters = dh.generate_parameters(generator=5,
                                            key_size=utils_app.DH_KEY_SIZE,
                                            backend=default_backend())
        # Our private key and public key from DH
        private_key = parameters.generate_private_key()
        public_key = private_key.public_key()

        pickled_params = codecs.encode(
            pickle.dumps(
                parameters.parameter_bytes(encoding=Encoding.PEM,
                                           format=ParameterFormat.PKCS3)),
            "base64").decode()

        message = "{\"type\" : \"session_key\"," + "\n"
        message += "\"params\" : \"" + pickled_params + "\"," + "\n"
        message += "\"username\" : \"" + self.username + "\"," + "\n"
        message += "\"pk\" : \"" + public_key.public_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PublicFormat.SubjectPublicKeyInfo).decode(
                'utf-8') + "\",\n"

        message += "\"public\" : \"" + self.public_key.public_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PublicFormat.SubjectPublicKeyInfo).decode(
                'utf-8') + "\","

        inner_message = actions.trust_server(self, challenge=challenge)
        enc_json_message = None
        server_pub = None
        if address == utils_app.AM_ADDRESS:
            server_pub = self.server_public_key_manager
        else:
            server_pub = self.server_public_key_repository

        enc_json_message = utilities.encrypt_message_complete(
            base64.b64encode(inner_message.encode("utf-8")), "", server_pub)
        key = enc_json_message[0]
        iv = enc_json_message[2]
        data = enc_json_message[1]
        rsa_kg = RSAKGen()
        random_key = Fernet.generate_key()
        hmac = HMAC_Conf.integrity_control(data.encode(), random_key)
        random_key = rsa_kg.cipher_public_key(server_pub, random_key)
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        message += "\"message\" : \"" + data + "\",\n"
        message += "\"Key\" : \"" + str(base64.b64encode(key),
                                        'utf-8') + "\",\n"
        message += "\"hmac\" : \"" + str(base64.b64encode(hmac),
                                         'utf-8') + "\", \n"
        message += "\"random_key\" : \"" + str(base64.b64encode(random_key),
                                               'utf-8') + "\", \n"
        message += "\"iv\" : \"" + str(base64.b64encode(iv), 'utf-8') + "\"\n"
        message += "}"
        sock.sendto(base64.b64encode(message.encode("utf-8")), address)
        #print(message)

        ##### Sent the parameters with all the information #####
        ###########################################################################################################

        # Receive response
        data, server = sock.recvfrom(utils_app.SOCKET_BYTES)
        decoded_data = base64.b64decode(data).decode()
        json_message = json.loads(decoded_data, strict=False)
        if json_message["type"] == "No valid signature":
            print("No valid signature")
            sys.exit(0)
        elif json_message["type"] == "No valid certificate":
            print("No valid signature")
            sys.exit(0)

        # 'type', 'pk' -> public dh_key , 'info' -> handshake data, 'server_key'

        peer_pk = serialization.load_pem_public_key(
            json_message["pk"].encode('utf-8'), default_backend())
        shared_secret = private_key.exchange(peer_pk)

        derived_key = hkdf.HKDF(algorithm=hashes.SHA256(), length=utils_app.DH_HKDF_KEY, salt=None,
                                info=json_message["info"].encode('utf-8'), backend=default_backend())\
            .derive(shared_secret)

        if address == utils_app.AM_ADDRESS:
            self.session_key_manager = derived_key
        else:
            self.session_key_repository = derived_key

        ### Recieved the key from the server and created the public key ####
        ############################################################################################################
        sock.close()