В машинописном тексте у меня есть следующий код для подписи сообщения с помощью метода ecdsa и алгоритма SHA-512.
const pem = "-----BEGIN PRIVATE KEY-----\nByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgUIcMiv/YpEgR1CKRsL6sS85BVo6lYft/S5nIjTlCHvihRANCAATykP7bc8\n-----END PRIVATE KEY-----"
// fetch the part of the PEM string between header and footer
const pemHeader = "-----BEGIN PRIVATE KEY-----";
const pemFooter = "-----END PRIVATE KEY-----";
const pemContents = pem.substring(pemHeader.length, pem.length - pemFooter.length);
// base64 decode the string to get the binary data
const binaryDerString = window.atob(pemContents);
// convert from a binary string to an ArrayBuffer
const binaryDer = this.str2ab(binaryDerString);
return window.crypto.subtle.importKey(
"pkcs8",
binaryDer,
{
name: "RSA-PSS",
hash: "SHA-512",
},
true,
["sign"]
);
}
У меня есть этот метод, чтобы подписать сообщение:
createSignature2(){
let privateKey = this.importPrivateKey();
console.info(privateKey)
let data = this.str2ab("Test buffer")
let sign = window.crypto.subtle.sign(
{
name: "ECDSA",
hash: {name: "SHA-512"}, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
},
privateKey, //from generateKey or importKey above
data //ArrayBuffer of data you want to sign
)
.then(function(signature){
//returns an ArrayBuffer containing the signature
console.info(new Uint8Array(signature));
})
.catch(function(err){
console.error(err);
});
}
Я получаю сообщение об ошибке:
Argument of type 'Promise<CryptoKey>' is not assignable to parameter of type 'CryptoKey'.
Type 'Promise<CryptoKey>' is missing the following properties from type 'CryptoKey': algorithm, extractable, type, usages
Что мне здесь не хватает?
Спасибо,
Я знаю, но я не хотел раскрывать свой полный закрытый ключ.
Неверный импорт ключа. RSA-PSS
импортирует ключ RSA (для подписи/проверки с использованием RSASSA-PSS в качестве дополнения). Однако для ECDSA нет смысла импортировать ключ RSA. RSA и ECDSA — совершенно разные алгоритмы. Вместо ключа RSA необходимо импортировать ключ EC и тем самым указать кривую EC.
Что касается самого опубликованного ключа: как уже упоминалось в комментарии, он не соответствует ни одному допустимому формату и не представляет собой ни RSA, ни ключ EC.
Еще один момент касается используемого синтаксиса. Код часто применяется then()
, а также конструкции, в которых отсутствует ключевое слово await
. Здесь либо только async/await
(правильно), либо только then()
следует использовать последовательно (см. здесь для разницы).
Кроме того, str2ab()
отсутствует.
В следующем коде показан пример импорта ключа EC, включая подписание с помощью ECDSA. P-521 используется как кривая. В качестве закрытого ключа применяется образец EC-ключа в кодировке PEM в формате PKCS#8.
В коде применяется синтаксис async/await
(потому что так на мой взгляд понятнее). str2ab() взято из документации WebCrypto API. ab2str()
— это обратная функция. Подпись закодирована в Base64 для отображения:
(async () => {
createSignature2(); // Fix: apply consistently async/await syntax
async function createSignature2(){
const privateKey = await importPrivateKey();
console.info(privateKey)
const data = str2ab("Test buffer")
const sign = await window.crypto.subtle.sign({name: "ECDSA",hash: {name: "SHA-512"}}, privateKey, data);
console.info(window.btoa(ab2str(sign)));
}
async function importPrivateKey() {
const pem = `-----BEGIN PRIVATE KEY-----
MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIA3G3l+QFixI4fD4zW
lC9n7xnT/7MS4bm6Ge6KXPmesmy9AARSdysdhWLXq51hvd/4F4Rd+ZYWn8bdeN58
zOJdRAOhgYkDgYYABAGBW8V/nf4yXdePGpotIL8WNR1182yBdcztCpWQUkL9TOEy
vhhnf8SwtRDglbjCBiVONw4+WjC3pRfo3yTmee+mEQE3peJArA1zOFz9WJZhigA9
aK3t8BUbisZ38C4jcRuGgaBYUvg3ndMdqZnsNdbcg7sKOM9szCUvzGWkIWn2l4lW
zA==
-----END PRIVATE KEY-----`;
const pemHeader = "-----BEGIN PRIVATE KEY-----";
const pemFooter = "-----END PRIVATE KEY-----";
const pemContents = pem.substring(pemHeader.length, pem.length - pemFooter.length);
const binaryDerString = window.atob(pemContents);
const binaryDer = str2ab(binaryDerString);
return await window.crypto.subtle.importKey("pkcs8", binaryDer,{name: "ECDSA",namedCurve: "P-521"}, true, ["sign"]); // Fix: import ECDSA key
}
function str2ab(str) {
const buf = new ArrayBuffer(str.length);
const bufView = new Uint8Array(buf);
for (let i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
}
})();
Большое спасибо! Решил мою проблему. И понятное объяснение.
Обратите внимание, что помимо правильного ответа от Topaco, что-то пошло не так при копировании/вставке ключа. Эта база 64 вообще не представляет закрытый ключ, закодированный PKCS # 8, даже декодирование ASN.1 DER не удается.