我使用一个安全嵌入式芯片(ATECC508)来使用secp256r1曲线生成ECDSA消息/签名组合。
来自芯片的信息以Uint8Arrays: message32、signature64和publickey64输出;公钥是原始字节格式,在64字节数组中给出X/Y坐标,前面没有0x04填充。
只有当我将64字节数组放在前面的0x04上时,公钥才能成功地导入WebCrypto。
但是,当我试图验证消息和签名时,它总是失败的。
我创建了一个模拟器脚本来帮助调试。它使用WebCrypto来生成消息、签名和公钥,而不是密码芯片。模拟器生成一个32字节的Uint8array消息数组,并对返回64字节Uint8array的消息签名。WebCrypto生成的公钥也被验证在前面有0x04填充,在代表曲线的X/Y坐标的64个字节之前。这意味着我认为模拟器产生的信息应该与芯片所提供的完全相同的格式。
从WebCrypto生成的任何消息、签名和公钥都可以成功,verified...but I无法验证来自chip...it的信息总是不成功的。
我没有理由怀疑来自芯片的值是错误的,我已经从它们的chip...none生成了许多消息/签名。我也尝试了第二个芯片,也有同样的结果。
从芯片输出示例(不验证):
uint8_t message[32] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
};
uint8_t signature[64] = {
0xD6,0x82,0x25,0xCC,0x68,0x6F,0x4F,0x84,0x91,0x48,0x63,0x6E,0x67,0x3C,0xD4,0xC0,0xF8,0xE5,0x9D,0x7B,0xAD,0x6B,0xB3,0xF1,0x1C,0xDB,0x90,0xB7,0x1A,0x5E,0x43,0xCF,0xD8,0xC3,0x8C,0x77,0x74,0xE2,0xA0,0x29,0xFF,0x43,0x22,0x7D,0xF9,0x41,0x56,0x12,0x8A,0x1B,0xEA,0x4D,0x57,0x8A,0x37,0x9C,0x6A,0x85,0x0A,0x56,0xBE,0xEC,0x1A,0x69
};
uint8_t publicKey[64] = {
0x39,0xC3,0xDD,0x74,0x13,0x17,0x29,0x44,0x6D,0xC1,0xB3,0xDA,0x67,0xD4,0x9F,0xC0,
0x46,0xFC,0xBF,0x07,0x2F,0xCC,0x5B,0x9F,0xA5,0x1C,0x05,0xB9,0x74,0x30,0x7F,0x96,
0x9C,0x40,0x3B,0x16,0x35,0xF0,0x44,0x9F,0x02,0xBD,0x42,0x27,0x51,0xE3,0x31,0x21,
0xA4,0x43,0x4F,0x15,0x2F,0x2B,0x2B,0x2A,0x3F,0x67,0x52,0x19,0xC5,0xD9,0x25,0xF6,
};注意:在导入之前,上面的公钥是用0x04填充的,否则WebCrypto会抛出一个错误。
从WebCrypto模拟器javascript控制台输出示例(这验证了OK):
Message to import in hex: 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
Message Uint8Array conversion: Uint8Array(32) [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, … ]
the signature in hex: 5d4575a19cad9a56b554bafbb1db212d8badd48b5d29f6556fa33f0e8650175f48157e70377c7aa5f97e55bc455b6520060dc86f32a00577a254a97e1b7b394c
the signature buffer:
Uint8Array(64) [ 93, 69, 117, 161, 156, 173, 154, 86, 181, 84, … ]
public key in hex:
04d18669eb64b54118fbcdacbf79d2f185383abadb1982382a51675650f4596d9f917a7b9b215f2424418b4e7c824500dc29ea507f08b4ef51ca35f58de75ca274注意:上面是十六进制字符串,但在使用UintArray8调用WebCrypto API之前,我正在转换为WebCrypto。在使用PublicKey验证之前,会将其转换为正确的CryptoKey()类型。
用于验证的javascript代码:
let result = await window.crypto.subtle.verify({
name: "ECDSA",
hash: { name: "SHA-256" }
},
publicKey, sigbuffer, msgbuffer);最后,进口:
return window.crypto.subtle.importKey(
'raw',
key, {
name: 'ECDSA',
namedCurve: 'P-256'
},
true, ["verify"]
);我的意图是能够成功地将来自芯片的信息导入和验证到WebCrypto API中,但到目前为止我一直没有成功。此刻,我完全被困住了,我将非常感谢任何help...thanks的提前
发布于 2021-04-17 14:07:40
如果验证了未散列的数据(我用C#解决方案对此进行了测试,请参见联机这里),那么对发布的数据进行验证是成功的。最后,这证明了未散列数据是签名的。
但是,签名未散列数据是不常见的,通常哈希数据是签名的。一方面,这纯粹是出于实际原因(不对称算法通常只能用于对短消息进行加密),但另一方面,出于安全考虑也是必要的,例如这里。
由于这个原因,许多库都隐式执行散列,这就是为什么必须指定摘要。对于WebCrypto API来说,这也是正确的,导致使用为未散列数据生成的签名来验证散列数据,这当然会失败。
现在也不可能派生出其散列只生成消息的数据,然后使用这些数据作为WebCrypto API的输入。密码散列应该可以防止这样的推断。
由于这些原因,不能使用WebCrypto API来验证数据!
因此,您需要一个不隐式散列的JavaScript库,例如,SJCL
var pubHex = '39c3dd74131729446dc1b3da67d49fc046fcbf072fcc5b9fa51c05b974307f969c403b1635f0449f02bd422751e33121a4434f152f2b2b2a3f675219c5d925f6';
var pub = new sjcl.ecc.ecdsa.publicKey(
sjcl.ecc.curves.c256,
sjcl.codec.hex.toBits(pubHex)
)
var msgHex = '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f';
var msg = sjcl.codec.hex.toBits(msgHex)
var sigHex = 'd68225cc686f4f849148636e673cd4c0f8e59d7bad6bb3f11cdb90b71a5e43cfd8c38c7774e2a029ff43227df94156128a1bea4d578a379c6a850a56beec1a69';
var sig = sjcl.codec.hex.toBits(sigHex)
var verified = false;
try {
var verified = pub.verify(msg, sig)
} catch (e) {}
console.log('Verification:', verified)<script src="https://cdn.jsdelivr.net/npm/sjcl-full@1.0.0/sjcl.min.js"></script>
在此基础上,成功地验证了发布的数据。
https://stackoverflow.com/questions/67135136
复制相似问题