如何从 Android 应用调用 OpenSSL SRP API?

How to call OpenSSL SRP APIs from Android app?

我正在尝试为 Android 中的服务器和客户端应用程序实施 SRP protocol。我检查过 OpenSSL 支持 SRP 协议,但如何从 Android 应用程序访问 OpenSSL API? JNI 是访问 OpenSSL C API 的唯一方法吗?是否有任何示例可供我参考如何为 Android 构建 OpenSSL 以及如何通过 JNI 调用 OpenSSL SRP API。

I am trying to implement the SRP protocol

我也喜欢 SRP。请务必使用 Thomas Wu 的规范,或 IETF 规范的版本 6。


OpenSSL supports SRP protocol but how can I access OpenSSL APIs from the Android app? Is JNI the only way to access the OpenSSL C APIs?

是的。

您也可以参考 Bouncy Castle 的 Java 实现。


Are there any samples that I can refer how to build the OpenSSL for Android...

请参阅 OpenSSL wiki 上的 OpenSSL and Android

Android 随身携带一份 OpenSSL,但我不确定它是否包含 SRP。


Are there any samples that I can refer ... to call the OpenSSL SRP APIs through JNI.

我不知道。您会发现最接近 s_client 的源代码、-srpuser <user> 等选项和 srp_arg_st 等数据结构以及 ssl_srp_verify_param_cbssl_give_srp_client_pwd_cb 等函数。

您可以在 <openssl src dir>/apps/s_client.c 找到 s_client 的源代码。第 1365 行看起来很有趣(来自 1.0.2h):

# ifndef OPENSSL_NO_SRP
    if (srp_arg.srplogin) {
        if (!srp_lateuser && !SSL_CTX_set_srp_username(ctx, srp_arg.srplogin)) {
            BIO_printf(bio_err, "Unable to set SRP username\n");
            goto end;
        }
        srp_arg.msg = c_msg;
        srp_arg.debug = c_debug;
        SSL_CTX_set_srp_cb_arg(ctx, &srp_arg);
        SSL_CTX_set_srp_client_pwd_callback(ctx, ssl_give_srp_client_pwd_cb);
        SSL_CTX_set_srp_strength(ctx, srp_arg.strength);
        if (c_msg || c_debug || srp_arg.amp == 0)
            SSL_CTX_set_srp_verify_param_callback(ctx,
                                                  ssl_srp_verify_param_cb);
    }
# endif

以及第 475 行附近的 srp_arg_st

/* This is a context that we pass to all callbacks */
typedef struct srp_arg_st {
    char *srppassin;
    char *srplogin;
    int msg;                    /* copy from c_msg */
    int debug;                  /* copy from c_debug */
    int amp;                    /* allow more groups */
    int strength /* minimal size for N */ ;
} SRP_ARG;

很明显,OpenSSL 是原生的 C,不使用 JNI。


How to call OpenSSL SRP APIs ...?

在最高级别,您需要用 C 语言做两三件事。将它们视为对来自 OpenSSL wiki 的标准 TLS Client 的补充。 (我在侧步 Android/JNI 部分)。

首先,需要设置SSL_CTX_set_srp_*_callback。回调是库如何提示您的 TLS 客户端输入用户名和密码等信息。

其次,您删除所有非 SRP 密码套件。这意味着你不要使用像"HIGH:!aNULL:!MD5:!RC4".

这样的密码列表

第三,你只使用了SRP密码套件。我不确定使用 "HIGH:!aNULL:..." 时密码列表会是什么样子。但是您可以手动选择密码列表:

$ openssl ciphers -v | grep SRP | grep -v DSS | cut -f 1 -d ' '
SRP-RSA-AES-256-CBC-SHA
SRP-AES-256-CBC-SHA
SRP-RSA-AES-128-CBC-SHA
SRP-AES-128-CBC-SHA
SRP-RSA-3DES-EDE-CBC-SHA
SRP-3DES-EDE-CBC-SHA

如果您转到 openssl ciphers man page,那么您应该能够交叉引用 SRP-RSA-AES-256-CBC-SHA 和密码列表中所需的名称。不幸的是,缺少 SRP 密码套件。

但是,您可以访问 ICANN 的 TLS paramter registry 并获取名称:

  • SRP-RSA-AES-256-CBC-SHA → TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA
  • SRP-AES-256-CBC-SHA → TLS_SRP_SHA_WITH_AES_256_CBC_SHA
  • SRP-RSA-AES-128-CBC-SHA → TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA
  • SRP-AES-128-CBC-SHA → TLS_SRP_SHA_WITH_AES_128_CBC_SHA
  • SRP-RSA-3DES-EDE-CBC-SHA → TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA
  • SRP-3DES-EDE-CBC-SHA → TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA

因此,您将用于 SSL_CTX_set_cipher_listSSL_set_cipher_list 的字符串:

static const char const PREFERRED_CIPHERS[] =
   "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
    TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
    TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA";