python ECDSA 和 C micro-ecc 库之间的 ECDSA 签名和验证问题
ECDSA Signing and Verifying issue between python ECDSA and C micro-ecc library
我在执行以下操作时遇到问题:
- 使用 python 为 ECDSA SECP256k1 曲线创建了 Public 私钥对,并将其打印在终端上。
- 将密钥对复制粘贴到 Python 脚本和 visual studio 中(使用 micro-ecc 库的 C 编码)。所以每次我 运行 代码时都不会生成新密钥。
- 使用私钥在 Python 中签署消息 ("Hello"),并在终端上打印签名和消息。我知道必须先使用标准哈希算法(如 SHA256)对消息进行哈希处理,但在这种情况下,我直接使用消息进行签名。
- 将签名和相同的消息(哈希)复制到 Visual studio。
- 当我在 visual studio 中调用验证 API 时,验证失败了,尽管它使用了相同的 public 密钥、消息、签名和曲线。
我正在使用的库:
- visual studio https://github.com/kmackay/micro-ecc
中 C 的微 ecc
- python https://github.com/warner/python-ecdsa
的 ECDSA
我已经测试并确保的其他事项:
- 在 python 中签名和验证两者都适用于相同的密钥对,比如 (sk,vk)。
- 在 visual studio 中签名和验证两者都适用于相同的密钥对,例如 (sk,vk)。
- 在 Visual Studio 中使用 microECC 签名和在 python 中使用 ECDSA 验证失败,同样在 python 中使用 ECDSA 签名和使用 microECC 验证失败。
- 我确定从终端粘贴的密钥副本实际上是预期的密钥,因为我已经从复制的签名密钥中交叉验证了验证密钥并且它是匹配的。
首先,我通过 运行ning 这个脚本
生成密钥
GenerateKeys.py
import ecdsa
from ecdsa import SigningKey, SECP256k1
sk = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)
vk = sk.get_verifying_key()
sklst = []
for e in bytearray(sk.to_string()):
sklst.append(e)
vklst = []
for e in bytearray(vk.to_string()):
vklst.append(e)
print("Private Key is:")
print(sklst)
print("Public Key is:")
print(vklst)
GenerateKeys.py
的输出
Private Key is:
[38, 108, 90, 112, 230, 138, 62, 97, 107, 90, 227, 165, 207, 80, 251, 154, 17, 4, 73, 53, 33, 162, 33, 200, 243, 205, 116, 43, 36, 59, 201, 84]
Public Key is:
[163, 238, 83, 33, 229, 249, 105, 12, 141, 7, 214, 134, 148, 1, 198, 45, 13, 31, 9, 223, 85, 201, 98, 248, 73, 160, 40, 255, 64, 214, 250, 121, 234, 103, 212, 148, 197, 48, 210, 38, 166, 51, 30, 81, 119, 240, 125, 104, 237, 24, 3, 216, 229, 87, 45, 7, 115, 69, 94, 187, 236, 91, 142, 18]
将私钥复制粘贴到 Sign.py python 脚本中并生成签名和 public 密钥
我使用 "Hello" 作为创建签名的消息
Sign.py
import ecdsa
from ecdsa import SigningKey, SECP256k1
signinKey_lst = [38, 108, 90, 112, 230, 138, 62, 97, 107, 90, 227, 165, 207, 80, 251, 154, 17, 4, 73, 53, 33, 162, 33, 200, 243, 205, 116, 43, 36, 59, 201, 84]
signinKey_lst = bytearray(signinKey_lst)
signinKey = ecdsa.SigningKey.from_string(signinKey_lst, curve=ecdsa.SECP256k1)
verifyKey = signinKey.get_verifying_key()
signinKey_lst = []
for e in bytearray(signinKey.to_string()):
signinKey_lst.append(e)
verifyKey_lst = []
for e in bytearray(verifyKey.to_string()):
verifyKey_lst.append(e)
print("Public Key is:")
print(verifyKey_lst)
msg = "Hello"
sign = signinKey.sign(msg)
sign_lst = []
verifyKey_lst = []
for e in bytearray(sign):
sign_lst.append(e)
print("Signature is:")
print(sign_lst)
Sign.py 的输出:
Private Key is:
[38, 108, 90, 112, 230, 138, 62, 97, 107, 90, 227, 165, 207, 80, 251, 154, 17, 4, 73, 53, 33, 162, 33, 200, 243, 205, 116, 43, 36, 59, 201, 84]
Public Key is:
[163, 238, 83, 33, 229, 249, 105, 12, 141, 7, 214, 134, 148, 1, 198, 45, 13, 31, 9, 223, 85, 201, 98, 248, 73, 160, 40, 255, 64, 214, 250, 121, 234, 103, 212, 148, 197, 48, 210, 38, 166, 51, 30, 81, 119, 240, 125, 104, 237, 24, 3, 216, 229, 87, 45, 7, 115, 69, 94, 187, 236, 91, 142, 18]
Signature is:
[47, 107, 101, 228, 187, 209, 97, 180, 83, 149, 133, 71, 62, 15, 86, 186, 192, 222, 108, 221, 249, 128, 124, 7, 139, 110, 103, 108, 62, 89, 136, 152, 226, 43, 104, 166, 92, 247, 9, 201, 135, 96, 19, 75, 55, 229, 67, 198, 188, 90, 246, 17, 157, 1, 229, 71, 151, 206, 211, 95, 41, 51, 96, 42]
复制粘贴签名并在 visual studio 中使用与微型 ecc 库相同的消息:-
source.c
#include "stdio.h"
#include <stdlib.h>
#include <string.h>
#include "uECC.h"
#include "constants.h"
uint8_t privateKey[32] = { 0 };
uint8_t publicKey[64] = { 163, 238, 83, 33, 229, 249, 105, 12, 141, 7, 214, 134, 148, 1, 198, 45, 13, 31, 9, 223, 85, 201, 98, 248, 73, 160, 40, 255, 64, 214, 250, 121, 234, 103, 212, 148, 197, 48, 210, 38, 166, 51, 30, 81, 119, 240, 125, 104, 237, 24, 3, 216, 229, 87, 45, 7, 115, 69, 94, 187, 236, 91, 142, 18 };
uint8_t msg[5] = { 'H','e','l','l','o' };
uint8_t sign[64] = { 47, 107, 101, 228, 187, 209, 97, 180, 83, 149, 133, 71, 62, 15, 86, 186, 192, 222, 108, 221, 249, 128, 124, 7, 139, 110, 103, 108, 62, 89, 136, 152, 226, 43, 104, 166, 92, 247, 9, 201, 135, 96, 19, 75, 55, 229, 67, 198, 188, 90, 246, 17, 157, 1, 229, 71, 151, 206, 211, 95, 41, 51, 96, 42 };
void printArray(uint8_t* pToArr, uint32_t u16ArrSize)
{
uint32_t c = 0;
printf("[ ");
for (c = 0; c < u16ArrSize; c++)
{
if (c != (u16ArrSize - 1))
{
printf(" %u,", *pToArr);
}
else
{
printf(" %u", *pToArr);
}
pToArr++;
}
printf(" ]");
return;
}
int main()
{
const struct uECC_Curve_t* curve;
#if uECC_SUPPORTS_secp256k1
curve = uECC_secp256k1();
#endif
const char* m = "Hello World"; //{0xff, 0xff, 0xff, 0xff, 0xff,0xff }
printf("\n/*************************************************************************************************\n");
printf("Validating the Encrypted hash with the public key and the hash used\n");
printf("\n\nPublic Key:\n");
printArray(publicKey, sizeof(publicKey));
printf("\n\nMsg:\n");
printArray(msg, sizeof(msg));
printf("\n\nsignature:\n");
printArray(sign, sizeof(sign));
printf("\n");
if (!uECC_verify(publicKey, msg, sizeof(msg), sign, curve))
{
printf("\nuECC_verify() failed\n");
}
else
{
printf("\nuECC_verify() succeeded\n");
}
printf("\n/*************************************************************************************************/\n");
return 0;
}
运行ning source.c 的 visual studio 的输出:-
/*************************************************************************************************
Validating the Encrypted hash with the public key and the hash used
Public Key:
[ 148, 49, 144, 80, 185, 77, 185, 14, 186, 168, 164, 110, 123, 192, 55, 219, 184, 133, 153, 65, 144, 169, 175, 171, 203, 225, 88, 134, 51, 199, 254, 215, 237, 144, 141, 137, 80, 190, 25, 35, 33, 136, 248, 190, 114, 60, 128, 34, 155, 157, 83, 68, 187, 154, 137, 9, 51, 112, 155, 54, 88, 104, 82, 138 ]
Msg:
[ 72, 101, 108, 108, 111 ]
signature:
[ 186, 247, 43, 62, 152, 84, 40, 197, 74, 135, 80, 18, 152, 150, 121, 177, 155, 242, 1, 11, 171, 155, 45, 19, 174, 171, 190, 66, 31, 125, 214, 136, 41, 116, 139, 82, 71, 208, 4, 80, 47, 154, 100, 173, 110, 164, 25, 19, 7, 253, 175, 123, 34, 1, 99, 86, 241, 241, 211, 45, 15, 35, 210, 69 ]
uECC_verify() failed
/*************************************************************************************************/
C:\Users\prajwal.bv\source\repos\Crypt_sample1\x64\Debug\Crypt_sample1.exe (process 17160) exited with code 0.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops.
Press any key to close this window . . .
我预计 运行ning source.c 的输出是 uECC_verify() 成功。但它打印 uECC_verify() failed.
ECDSA 签名程序是一个 two-stage 过程:
- 根据消息计算散列摘要
- 然后对这个摘要进行签名。
Python ECDSA 默认使用 SHA-1,除非另有说明。
消息 'Hello' 的 SHA-1 摘要是十六进制编码的:f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0
。
这意味着你需要在调用uECC_verify函数时使用这个摘要。
验证
用以下代码行替换您的 .c 代码中的 msg 数组:
uint8_t msg[] = { 0xf7, 0xff, 0x9e, 0x8b, 0x7b, 0xb2, 0xe0, 0x9b, 0x70, 0x93, 0x5a, 0x5d, 0x78, 0x5e, 0x0c, 0xc5, 0xd9, 0xd0, 0xab, 0xf0};
那么verfiy函数就成功了。
输出
调试控制台中的输出如下所示:
我在执行以下操作时遇到问题:
- 使用 python 为 ECDSA SECP256k1 曲线创建了 Public 私钥对,并将其打印在终端上。
- 将密钥对复制粘贴到 Python 脚本和 visual studio 中(使用 micro-ecc 库的 C 编码)。所以每次我 运行 代码时都不会生成新密钥。
- 使用私钥在 Python 中签署消息 ("Hello"),并在终端上打印签名和消息。我知道必须先使用标准哈希算法(如 SHA256)对消息进行哈希处理,但在这种情况下,我直接使用消息进行签名。
- 将签名和相同的消息(哈希)复制到 Visual studio。
- 当我在 visual studio 中调用验证 API 时,验证失败了,尽管它使用了相同的 public 密钥、消息、签名和曲线。
我正在使用的库:
- visual studio https://github.com/kmackay/micro-ecc 中 C 的微 ecc
- python https://github.com/warner/python-ecdsa 的 ECDSA
我已经测试并确保的其他事项:
- 在 python 中签名和验证两者都适用于相同的密钥对,比如 (sk,vk)。
- 在 visual studio 中签名和验证两者都适用于相同的密钥对,例如 (sk,vk)。
- 在 Visual Studio 中使用 microECC 签名和在 python 中使用 ECDSA 验证失败,同样在 python 中使用 ECDSA 签名和使用 microECC 验证失败。
- 我确定从终端粘贴的密钥副本实际上是预期的密钥,因为我已经从复制的签名密钥中交叉验证了验证密钥并且它是匹配的。
首先,我通过 运行ning 这个脚本
生成密钥GenerateKeys.py
import ecdsa
from ecdsa import SigningKey, SECP256k1
sk = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1)
vk = sk.get_verifying_key()
sklst = []
for e in bytearray(sk.to_string()):
sklst.append(e)
vklst = []
for e in bytearray(vk.to_string()):
vklst.append(e)
print("Private Key is:")
print(sklst)
print("Public Key is:")
print(vklst)
GenerateKeys.py
的输出Private Key is:
[38, 108, 90, 112, 230, 138, 62, 97, 107, 90, 227, 165, 207, 80, 251, 154, 17, 4, 73, 53, 33, 162, 33, 200, 243, 205, 116, 43, 36, 59, 201, 84]
Public Key is:
[163, 238, 83, 33, 229, 249, 105, 12, 141, 7, 214, 134, 148, 1, 198, 45, 13, 31, 9, 223, 85, 201, 98, 248, 73, 160, 40, 255, 64, 214, 250, 121, 234, 103, 212, 148, 197, 48, 210, 38, 166, 51, 30, 81, 119, 240, 125, 104, 237, 24, 3, 216, 229, 87, 45, 7, 115, 69, 94, 187, 236, 91, 142, 18]
将私钥复制粘贴到 Sign.py python 脚本中并生成签名和 public 密钥 我使用 "Hello" 作为创建签名的消息
Sign.py
import ecdsa
from ecdsa import SigningKey, SECP256k1
signinKey_lst = [38, 108, 90, 112, 230, 138, 62, 97, 107, 90, 227, 165, 207, 80, 251, 154, 17, 4, 73, 53, 33, 162, 33, 200, 243, 205, 116, 43, 36, 59, 201, 84]
signinKey_lst = bytearray(signinKey_lst)
signinKey = ecdsa.SigningKey.from_string(signinKey_lst, curve=ecdsa.SECP256k1)
verifyKey = signinKey.get_verifying_key()
signinKey_lst = []
for e in bytearray(signinKey.to_string()):
signinKey_lst.append(e)
verifyKey_lst = []
for e in bytearray(verifyKey.to_string()):
verifyKey_lst.append(e)
print("Public Key is:")
print(verifyKey_lst)
msg = "Hello"
sign = signinKey.sign(msg)
sign_lst = []
verifyKey_lst = []
for e in bytearray(sign):
sign_lst.append(e)
print("Signature is:")
print(sign_lst)
Sign.py 的输出:
Private Key is:
[38, 108, 90, 112, 230, 138, 62, 97, 107, 90, 227, 165, 207, 80, 251, 154, 17, 4, 73, 53, 33, 162, 33, 200, 243, 205, 116, 43, 36, 59, 201, 84]
Public Key is:
[163, 238, 83, 33, 229, 249, 105, 12, 141, 7, 214, 134, 148, 1, 198, 45, 13, 31, 9, 223, 85, 201, 98, 248, 73, 160, 40, 255, 64, 214, 250, 121, 234, 103, 212, 148, 197, 48, 210, 38, 166, 51, 30, 81, 119, 240, 125, 104, 237, 24, 3, 216, 229, 87, 45, 7, 115, 69, 94, 187, 236, 91, 142, 18]
Signature is:
[47, 107, 101, 228, 187, 209, 97, 180, 83, 149, 133, 71, 62, 15, 86, 186, 192, 222, 108, 221, 249, 128, 124, 7, 139, 110, 103, 108, 62, 89, 136, 152, 226, 43, 104, 166, 92, 247, 9, 201, 135, 96, 19, 75, 55, 229, 67, 198, 188, 90, 246, 17, 157, 1, 229, 71, 151, 206, 211, 95, 41, 51, 96, 42]
复制粘贴签名并在 visual studio 中使用与微型 ecc 库相同的消息:-
source.c
#include "stdio.h"
#include <stdlib.h>
#include <string.h>
#include "uECC.h"
#include "constants.h"
uint8_t privateKey[32] = { 0 };
uint8_t publicKey[64] = { 163, 238, 83, 33, 229, 249, 105, 12, 141, 7, 214, 134, 148, 1, 198, 45, 13, 31, 9, 223, 85, 201, 98, 248, 73, 160, 40, 255, 64, 214, 250, 121, 234, 103, 212, 148, 197, 48, 210, 38, 166, 51, 30, 81, 119, 240, 125, 104, 237, 24, 3, 216, 229, 87, 45, 7, 115, 69, 94, 187, 236, 91, 142, 18 };
uint8_t msg[5] = { 'H','e','l','l','o' };
uint8_t sign[64] = { 47, 107, 101, 228, 187, 209, 97, 180, 83, 149, 133, 71, 62, 15, 86, 186, 192, 222, 108, 221, 249, 128, 124, 7, 139, 110, 103, 108, 62, 89, 136, 152, 226, 43, 104, 166, 92, 247, 9, 201, 135, 96, 19, 75, 55, 229, 67, 198, 188, 90, 246, 17, 157, 1, 229, 71, 151, 206, 211, 95, 41, 51, 96, 42 };
void printArray(uint8_t* pToArr, uint32_t u16ArrSize)
{
uint32_t c = 0;
printf("[ ");
for (c = 0; c < u16ArrSize; c++)
{
if (c != (u16ArrSize - 1))
{
printf(" %u,", *pToArr);
}
else
{
printf(" %u", *pToArr);
}
pToArr++;
}
printf(" ]");
return;
}
int main()
{
const struct uECC_Curve_t* curve;
#if uECC_SUPPORTS_secp256k1
curve = uECC_secp256k1();
#endif
const char* m = "Hello World"; //{0xff, 0xff, 0xff, 0xff, 0xff,0xff }
printf("\n/*************************************************************************************************\n");
printf("Validating the Encrypted hash with the public key and the hash used\n");
printf("\n\nPublic Key:\n");
printArray(publicKey, sizeof(publicKey));
printf("\n\nMsg:\n");
printArray(msg, sizeof(msg));
printf("\n\nsignature:\n");
printArray(sign, sizeof(sign));
printf("\n");
if (!uECC_verify(publicKey, msg, sizeof(msg), sign, curve))
{
printf("\nuECC_verify() failed\n");
}
else
{
printf("\nuECC_verify() succeeded\n");
}
printf("\n/*************************************************************************************************/\n");
return 0;
}
运行ning source.c 的 visual studio 的输出:-
/*************************************************************************************************
Validating the Encrypted hash with the public key and the hash used
Public Key:
[ 148, 49, 144, 80, 185, 77, 185, 14, 186, 168, 164, 110, 123, 192, 55, 219, 184, 133, 153, 65, 144, 169, 175, 171, 203, 225, 88, 134, 51, 199, 254, 215, 237, 144, 141, 137, 80, 190, 25, 35, 33, 136, 248, 190, 114, 60, 128, 34, 155, 157, 83, 68, 187, 154, 137, 9, 51, 112, 155, 54, 88, 104, 82, 138 ]
Msg:
[ 72, 101, 108, 108, 111 ]
signature:
[ 186, 247, 43, 62, 152, 84, 40, 197, 74, 135, 80, 18, 152, 150, 121, 177, 155, 242, 1, 11, 171, 155, 45, 19, 174, 171, 190, 66, 31, 125, 214, 136, 41, 116, 139, 82, 71, 208, 4, 80, 47, 154, 100, 173, 110, 164, 25, 19, 7, 253, 175, 123, 34, 1, 99, 86, 241, 241, 211, 45, 15, 35, 210, 69 ]
uECC_verify() failed
/*************************************************************************************************/
C:\Users\prajwal.bv\source\repos\Crypt_sample1\x64\Debug\Crypt_sample1.exe (process 17160) exited with code 0.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the console when debugging stops.
Press any key to close this window . . .
我预计 运行ning source.c 的输出是 uECC_verify() 成功。但它打印 uECC_verify() failed.
ECDSA 签名程序是一个 two-stage 过程:
- 根据消息计算散列摘要
- 然后对这个摘要进行签名。
Python ECDSA 默认使用 SHA-1,除非另有说明。
消息 'Hello' 的 SHA-1 摘要是十六进制编码的:f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0
。
这意味着你需要在调用uECC_verify函数时使用这个摘要。
验证
用以下代码行替换您的 .c 代码中的 msg 数组:
uint8_t msg[] = { 0xf7, 0xff, 0x9e, 0x8b, 0x7b, 0xb2, 0xe0, 0x9b, 0x70, 0x93, 0x5a, 0x5d, 0x78, 0x5e, 0x0c, 0xc5, 0xd9, 0xd0, 0xab, 0xf0};
那么verfiy函数就成功了。
输出
调试控制台中的输出如下所示: