我正在使用需要登录 URL 的那部分包括身份验证的服务器。该方案的工作方式(如手册中推荐的那样)是
- 使用 Java JDK keytool 生成公钥/私钥对(在 Java 密钥库中创建它们)
- 使用 Java JDK keytool 为密钥对生成证书
- 证书安装在服务器上。
登录客户端时(我的代码)
- 生成明文令牌字符串
- 使用 SHA1 和 DSA 使用私钥对明文令牌字符串进行签名
- 在登录 URL 中包含签名的令牌字符串。
Java keytool 不提供从密钥库中导出私钥的机制,但另外我有 Java 代码从密钥库中提取私钥并将其保存在文件中 - 基于如何从密钥库?.
当客户端使用 Java 进行签名时,这一切都有效,代码如下。
String plaintext = "This is a sample plaintext token string";
Signature instance = Signature.getInstance("SHA1withDSA");
instance.initSign(privateKey);
instance.update((plaintext).getBytes());
byte[] signature = instance.sign();
当客户端使用 PHP 进行签名时,它也可以工作,代码如下。这里的私钥是从 PHP 中的 Java 密钥库文件中检索的。]
$privateKey = openssl_pkey_get_private("file://$keyfile", $keystorePassword);
openssl_sign($paramsEncoded, $signature, $privateKey, OPENSSL_ALGO_DSS1))
但是,我现在遇到一种情况,客户想要使用 Bash 脚本和 openssl 构建登录 URL - 这不起作用。我的该代码的最新版本如下所示,它执行 SHA1 消息摘要,然后执行 DSA 签名。但是服务器拒绝了令牌。
echo $tokenString | openssl dgst -sha1 > tokendigest
openssl dgst -dss1 -passin pass:$storePassword -sign $privateKeyFile > tokensigned
我遇到了这篇文章(Using SHA1 and RSA with java.security.Signature vs. MessageDigest and Cipher)这表明Java签名签名方法不对摘要进行签名,而是对摘要算法ID和摘要的串联进行签名. 在逐步浏览帖子中的代码后,似乎(对于 SHA1)摘要需要以 bytes 为前缀48 33 48 9 6 5 43 14 3 2 26 5 0 4 20
。但即使在添加之后,我仍然无法让 opensll 生成服务器可以接受的签名令牌。
有谁知道如何使用 openssl 来模拟 Java Signature 签名方法?