我正在一个项目中,正在使用C++中的libssh2将端口转发到MySQL。我已经将其用于用户名/密码身份验证,但是现在我想使用公钥/私钥身份验证来实现。 libssh2的文档非常差,因此我很难确定需要做的事情。

我想做的是让一个Android应用程序将数据发布到我的C++应用程序中,在C++应用程序中将为C++提供SSH详细信息以及auth key ,并创建SSH隧道。 C++可以很好地获得 key ,然后我要执行以下操作来进行公钥身份验证。

else if (this->getAuthMethod() == SupportedAuthMethods::AUTH_PUBLICKEY)
    {

        string test = this->getSSHPrivateKey();

        boost::replace_all(test, "\n", "");

        unsigned char * key = (unsigned char *)test.c_str();

        size_t sizeofkey = strlen((char*)key);
        cout << key << endl;
        stringstream logstream;
        logstream << "Using public key authentication for SSH Host: " << this->getSSHHostnameOrIPAddress();
        this->bitsLibrary->writeToLog(logstream.str(), "SSHTunnelForwarder", "authenticateSSHServer");
        if (chosenAuthMethod & SupportedAuthMethods::AUTH_PUBLICKEY)
        {
            //int result = 0;
            int result = libssh2_userauth_publickey(this->session, this->getUsername().c_str(), key, sizeofkey, SSHTunnelForwarder::publicKeyAuthComplete, 0);
            if (result != 0)
            {
                char * error = NULL;
                int len = 0;
                int errbuf = 0;
                libssh2_session_last_error(this->session, &error, &len, errbuf);
                this->bitsLibrary->writeToLog(std::string(error), "SSHTunnelForwarder", "auth");
                JSONResponseGenerator jsonResponse;
                jsonResponse.generateJSONResponse(API_AUTH_FAILURE, "InvalidPublicKey");
                return jsonResponse.getJSONString();

            }
        }
    }

我在某处读到它不应该换行,这就是为什么我要用\n替换空白字符的原因,但是不管有没有这都没有什么不同。

非常基本的文档提到libssh2_userauth_publickey的参数之一是如下的回调:
int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, const unsigned char *data, size_t data_len, void **abstract);
但我在任何地方都找不到任何有关此回调是什么或应该包含什么的信息。在对libssh2_userauth_publickey的函数调用中,我传入了SSHTunnelForwarder::publicKeyAuthComplete,当前此函数具有以下功能:
int SSHTunnelForwarder::publicKeyAuthComplete(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
    const unsigned char *data, size_t data_len, void **abstract)
{
    cout << "In SSH Auth Callback" << endl;
    return 0;
}

上面的这个方法没有被调用,尽管我期望它甚至接近正确。

当我在上面运行我的代码时,libssh2_userauth_publickey的结果为19,从get_last_message()方法返回的错误是invalid public key。我知道公钥文件很好,因为我可以在Android上的SSH应用程序中使用它,并且可以成功验证我的服务器。

更新1

我已经取得了一些进展,发现有一个函数叫做:
libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session, const char *username, size_t username_len, const char *publickeyfiledata, size_t publickeyfiledata_len, const char *privatekeyfiledata, size_t privatekeyfiledata_len, const char *passphrase);

我以前使用的Nussh2版本来自NuGet软件包管理器,发现其中的最新版本实际上已经很旧了,因此我在Visual Studio中从GitHub构建了最新的1.7.0版本,并将项目重新链接到该新版本。

现在,我已经用此版本替换了原来使用的原始publickey auth函数,因此我的代码现在看起来像这样:
int result = libssh2_userauth_publickey_frommemory(this->session, username.c_str(), username.length(), nullptr, 0, test.c_str(), sizeofkey, nullptr);

这个功能让我有些困惑,因为它想要公钥和私钥,对于我所了解的关于SSH的所有信息(当然不是很多),公钥都保留在服务器上,并且想要登录的用户只能访问私钥。键。

我发现有人在问这个问题,并做了补丁以允许将空指针用作公钥,因此我将nullptr用作公钥,将0用作公钥长度。我还为证书密码短语设置了nullptr,因为尚未设置。

现在运行此代码时,现在出现错误-18,即invalid username/public key combination。同样,我知道我使用的用户名和私钥文件是正确的,因为我可以在Android上的SSH客户端应用程序中使用它来连接到我的SSH服务器。

最佳答案

我找到了解决方案。我在更新1中所做的是实际修复,但是由于某种原因我的服务器 key 被更改,不确定为什么,所以当它说无法将用户名与 key 链接时,它是正确的。

完整修复程序如下:

不要使用NuGet的旧版本的libssh2。我从GitHub上的https://github.com/libssh2/libssh2/releases下载了最新的源代码,然后完成了在Visual Studio中构建libssh2的以下步骤。

  • 将libssh2/src中的所有.c文件插入一个空的Win32 C++(DLL
    或静态库)项目,但libgcrypt.c/openssl.c除外
    只选择一个适合您的加密货币库的密码。
  • 将您的OpenSSL或libgcrypt包含目录添加到项目包含路径
  • 将libssh2/include添加到项目包含路径
  • 将libssh2/win32添加到项目包含路径
  • 将适当的加密库添加到项目“附加库”列表
  • 构建
  • 完成的工作

  • 上面的步骤来自https://www.libssh2.org/mail/libssh2-devel-archive-2012-09/0029.shtml

    libssh2在编译期间链接到openssl。

    将项目链接到您刚刚为libssh2完成的最新构建,并使用方法
    libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session, const char *username, size_t username_len, const char *publickeyfiledata, size_t publickeyfiledata_len, const char *privatekeyfiledata, size_t privatekeyfiledata_len, const char *passphrase);
    

    就是这样。

    关于c++ - 使用Libssh2 C++进行SSH公钥身份验证,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42285185/

    10-12 23:57