我想验证一些包含不是ASN.1 DER编码的ECDSA签名的数据包。
我正在尝试使用openSSL(版本1.1.0)执行任务,因为它似乎带来了所有必需的功能。
目前我无法从数据包导入签名。 签名如下所示:
(最后4个字节不应标记为签名的一部分)
TShark展示了相关的部分:
"gn.sh.sig": { "gn.st.pka": "0", "gn.st.eccpointtype": "3", "gn.st.opaque": "1f:f8:ad:a7:fd:99:b2:a8:a2:69:d4:d6:67:e5:ee:5b:3f:8b:e8:7f:49:fc:b4:79:95:98:15:0d:cb:bd:06:3c", "gn.st.opaque": "61:a4:6a:c9:a7:dd:bd:0d:9c:0a:0e:73:db:52:06:bb:79:53:99:51:16:45:45:81:4e:df:94:5c:58:59:40:14" }
编码符合ETSI TS 103 097 v1.2.1
第一个条目opaque
和ECC Point type
形成一个名为R
的EccPoint,而第二个字段opaque
名为s
。
我的第一步是在openSSL中创建签名并将数据导入其中。
我的代码(删除错误处理以减小大小)如下所示:
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/bn.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
void verify_signature(void)
{
int res;
// Which value is correct for r-part?
static const char sig_r_hex[] = "1ff8ada7fd99b2a8a269d4d667e5ee5b3f8be87f49fcb4799598150dcbbd063c";
static const char sig_s_hex[] = "61a46ac9a7ddbd0d9c0a0e73db5206bb79539951164545814edf945c58594014";
BN_CTX *bn_ctx = BN_CTX_new();
BN_CTX_start(bn_ctx);
// Create signature and import from packet.
BIGNUM *bn_r = BN_CTX_get(bn_ctx);
BIGNUM *bn_s = BN_CTX_get(bn_ctx);
res = BN_hex2bn(&bn_r, sig_r_hex);
res = BN_hex2bn(&bn_s, sig_s_hex);
ECDSA_SIG *signature = ECDSA_SIG_new();
res = ECDSA_SIG_set0(signature, bn_r, bn_s);
printf("ECDSA_SIG_set0(): %d\n", res);
// ...
// Create hash of message and verify signature with public key
//...
}
int main(int arc, char *argv[])
{
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
OPENSSL_config(NULL);
verify_signature();
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
return 0;
}
我目前缺少的是如何正确处理值R
。
压缩CurvePoint的哪些部分应该用作r
来初始化签名?
我是否需要解压缩y
部分?
我是否必须为压缩的y
值添加一些指示?
欢迎任何提示。
编辑:
根据我在IEEE1609.2和SEC-1中的内容,可以添加其他信息,以便更快地从R
计算r
。这可能是点R
本身。
如r = xR mod n
,应该可以从EccPoint计算r
。
openSSL是否支持此机制以加快验证速度,或者我是否真的必须删除额外信息(并了解如何执行此操作)才能将r
提供给openSSL?
答案 0 :(得分:0)
4.2.5 - 4.2.8在http://www.etsi.org/deliver/etsi_ts/103000_103099/103097/01.02.01_60/ts_103097v010201p.pdf中,给出以下结构(其中extern
表示数据中没有字面表示'):
enum {
x_coordinate_only(0),
compressed_lsb_y_0(2),
compressed_lsb_y_1(3),
uncompressed(4),
(2^8-1)
} EccPointType;
struct {
extern PublicKeyAlgorithm algorithm;
extern uint8 field_size;
EccPointType type;
opaque x[field_size];
select(type) {
case x_coordinate_only:
case compressed_lsb_y_0:
case compressed_lsb_y_1:
;
case uncompressed:
opaque y[field_size];
unknown:
opaque data<var>;
}
} EccPoint;
struct {
extern PublicKeyAlgorithm algorithm;
extern uint8 field_size;
EccPoint R;
opaque s[field_size];
} EcdsaSignature;
struct {
PublicKeyAlgorithm algorithm;
select(algorithm) {
case ecdsa_nistp256_with_sha256:
EcdsaSignature ecdsa_signature;
unknown:
opaque signature<var>;
}
} Signature;
你知道它是P-256的ECDSA,使用SHA256,而且我们有一个“压缩的y-1”点。让我们首先使用我们所知道的解析这些结构的所有“选择”部分,并消除所有“外部”字段:
struct {
PublicKeyAlgorithm algorithm; // 1 byte = 0x00 ("ecdsa, P-256, sha256")
{ //EcdsaSignature ecdsa_signature
{ //EccPoint R
EccPointType type; //1 byte = 0x03 ("compressed lsb y-1")
opaque x[field_size]; //these are the first 32 opaque bytes
; // select(type) resolves to nothing.
}
opaque s[field_size]; //these are the second 32 opaque bytes
}
} Signature;
好。那更简单。现在我们知道所有字节是什么。那么关于“压缩点”的所有这些业务是什么?从本质上讲,点压缩实际上是最大限度地减少必须通过网络发送的数据量。事实证明,给定NIST曲线上某点的X坐标,您可以求解Y坐标,但有2个可能的答案。 Certicom的一些聪明的人注意到,与给定X坐标一起使用的两个可能的Y坐标总是在它们的最低有效位中有所不同 - 因此当他们必须发送所有X时,他们只能发送LSb Y(即,足够的信息,以便您知道Y的两个解决方案中的哪一个是正确的)。因此,“压缩lsb y-1”的EccPointType告诉您,对于X坐标,正确的Y坐标是LSb中具有1的坐标。
关于此的最佳消息是您不必关心。 ECDSA仅使用R的X坐标,它位于第一个标记为“x”的不透明斑点中。
所以这是一个冗长的解释,说“你不需要做任何事情。你已经拥有正确的r
(= X坐标R)和s
来喂养进入OpenSSL的ECDSA_do_verify。