我使用一个名为ATECC508A的嵌入式芯片来生成ECDSASHA-256公钥/私钥,并对给定消息进行签名。
当我从芯片中读取公钥时,我获得的值为:
0x4B 0x34 0x89 0xAB 0x1B 0xE2 0x4C 0x84 0xA4 0x74 0xBE 0x85 0xD9 0xCF 0x99 0xF1
0x12 0xF1 0x5E 0x13 0x67 0x17 0xB8 0x8C 0x3D 0xD8 0x54 0xC4 0x70 0xB0 0x11 0x05
0xB1 0x9E 0x4E 0x3D 0xED 0x39 0xFA 0xED 0xF3 0xDB 0x94 0x7A 0xF6 0xCE 0x3A 0x0F
0x6C 0xB1 0x86 0xB1 0x64 0x5D 0x8A 0xB8 0xA2 0x74 0x9F 0xF2 0x42 0x55 0x67 0x62它不会像DER格式化的键那样以0x30开头,我也不确定字节字符串是否有任何特殊的格式。
要以上述原始格式导入公钥,我在javascript中使用WebCrypto API (微妙密码库)执行以下操作:
var pubkeytest = new Uint8Array([0x4B 0x34 0x89 0xAB 0x1B 0xE2 0x4C 0x84 0xA4 0x74 0xBE 0x85 0xD9 0xCF 0x99 0xF1
0x12 0xF1 0x5E 0x13 0x67 0x17 0xB8 0x8C 0x3D 0xD8 0x54 0xC4 0x70 0xB0 0x11 0x05
0xB1 0x9E 0x4E 0x3D 0xED 0x39 0xFA 0xED 0xF3 0xDB 0x94 0x7A 0xF6 0xCE 0x3A 0x0F
0x6C 0xB1 0x86 0xB1 0x64 0x5D 0x8A 0xB8 0xA2 0x74 0x9F 0xF2 0x42 0x55 0x67 0x62]); window.crypto.subtle.importKey(
"raw",
pubkeytest.buffer, {
name: "ECDSA",
namedCurve: "P-256",
hash: {
name: 'SHA-256'
}
},
false, //whether the key is extractable (i.e. can be used in exportKey)
["verify"] //"verify" for public key import, "sign" for private key imports
)
.then(function(pubkeytest) {
//returns a publicKey (or privateKey if you are importing a private key)
console.log(pubkeytest);
})
.catch(function(err) {
console.error(err);
});控制台中的输出在console.error(err)行上触发一个错误:
DOMException: Data provided to an operation does not meet requirements通过执行以下操作,我可以使用AES成功地导入随机公钥:
const rawKey = window.crypto.getRandomValues(new Uint8Array(16));window.crypto.subtle.importKey(
"raw",
rawKey,
"AES-GCM",
true,
["encrypt", "decrypt"]
);我看到的唯一不同是数组中的字节数(16比64),以及算法类型AES-GCM,而不是ECDSA,它不声明P-256或SHA-256。
如何将上面的64字节原始十六进制公钥字符串导入到javascript中?我可以使用下面的示例对签名/消息执行密码验证:https://github.com/mdn/dom-examples/tree/master/web-crypto
提前感谢
发布于 2021-04-14 03:37:44
我相信我自己解决了这个问题,我想在这里发布解决方案,以防将来有人碰到这个问题。这个问题是一个简单的格式化问题,但解决起来并不那么简单,因为我找不到这些信息。
芯片提供的64字节公钥包含密钥内的完整X和Y坐标。它唯一缺少的是一个0x04前缀,它是ECDSA格式规则所必需的:
https://en.bitcoin.it/wiki/Elliptic_Curve_Digital_Signature_Algorithm
公钥:与私钥相对应但不需要保密的数字。公钥可以从私钥中计算,但反之亦然。公钥可用于确定签名是否真实(换句话说,使用适当的密钥生成),而不要求泄露私钥。在比特币中,公钥要么被压缩,要么被解压缩。压缩公钥为33个字节,由前缀0x02或0x03和一个名为x. 的256位整数组成,旧的未压缩密钥为65个字节,由常数前缀(0x04)组成,后面是两个名为x和y的256位整数(2 * 32字节)。压缩键的前缀允许从x值导出y值。
将与_04_4B3489AB1BE24C84A474BE85D9CF99F112F15E136717B88C3DD854C470B01105B19E4E3DED39FAEDF3DB947AF6CE3A0F6CB186B1645D8AB8A2749FF242556762 API一起工作的公钥的正确版本如下(对于下面的懒散十六进制格式表示歉意,但它与问题相同,除了粗体的新前缀外):
发布于 2022-08-22 09:37:35
我写这篇文章是为了防止有人有同样的问题。上面的解决方案(将0x04添加到原始键中)对我来说非常有效。在我看来,这个问题很奇怪。我用OpenSSL生成密钥,然后通过微妙的密码导入它们。这一定意味着OpenSSL错误地对密钥进行了编码,这听起来很奇怪,因为它很受欢迎。如果我有时间,我会进一步研究这个问题。
谢谢你的提问和回答,帮了我很大的忙。
编辑:我用Python导入了读取密钥文件,并将其解码为字节,以查看它是否以0x04开头。结果为阳性。
https://stackoverflow.com/questions/67083465
复制相似问题