Derives shared key (DH,ECDH,VKO 34.10). Requires
        private key available

        @param peerkey - other key (may be public only)

        Keyword parameters are algorithm-specific

def derive(self, peerkey, **kwargs):
        """
        Derives shared key (DH,ECDH,VKO 34.10). Requires
        private key available

        @param peerkey - other key (may be public only)

        Keyword parameters are algorithm-specific
        """
        if not self.cansign:
            raise ValueError("No private key available")
        ctx = libcrypto.EVP_PKEY_CTX_new(self.key, None)
        if ctx is None:
            raise PKeyError("Initailizing derive context")
        if libcrypto.EVP_PKEY_derive_init(ctx) < 1:
            raise PKeyError("derive_init")

        # This is workaround around missing functionality in GOST engine
        # it provides only numeric control command to set UKM, not
        # string one.
        self._configure_context(ctx, kwargs, ["ukm"])
        if libcrypto.EVP_PKEY_derive_set_peer(ctx, peerkey.key) <= 0:
            raise PKeyError("Cannot set peer key")
        if "ukm" in kwargs:
            # We just hardcode numeric command to set UKM here
            if libcrypto.EVP_PKEY_CTX_ctrl(ctx, -1, 1 << 10, 8, 8,
                                           kwargs["ukm"]) <= 0:
                raise PKeyError("Cannot set UKM")
        keylen = c_long(0)
        if libcrypto.EVP_PKEY_derive(ctx, None, byref(keylen)) <= 0:
            raise PKeyError("computing shared key length")
        buf = create_string_buffer(keylen.value)
        if libcrypto.EVP_PKEY_derive(ctx, buf, byref(keylen)) <= 0:
            raise PKeyError("computing actual shared key")
        libcrypto.EVP_PKEY_CTX_free(ctx)
        return buf.raw[:int(keylen.value)]