gpt4 book ai didi

javascript - C# 和 javascript 之间的 ECDH

转载 作者:行者123 更新时间:2023-12-04 12:25:51 26 4
gpt4 key购买 nike

我正在构建一个 Web API,我需要实现 ECDH 来执行端到端加密。在服务器端我有一个 C# 应用程序,在客户端我有一个 Javascript 应用程序。

我能够交换 key 、生成私钥并加密消息,但我在解密它时遇到了问题。

我认为问题在于公钥的交换。在 javascript 键以字节“4”开头,.NET 键以 8 字节开始标识键的类型和大小,我需要更改此字节以导入每个键(我找到的信息 here )。也许这会导致一些不一致。

在客户端,我使用 Web Cryptography API 来处理 ECDH。我正在执行如下。

生成 key

await window.crypto.subtle.generateKey(
{
name: "ECDH",
namedCurve: "P-256",
},
false,
["deriveKey", "deriveBits"]
);

像这样导出公钥:
await window.crypto.subtle.exportKey(
"raw",
publicKey
);

导入外部公钥
await window.crypto.subtle.importKey(
"raw",
{
name: "ECDH",
namedCurve: "P-256",
},
false,
["deriveKey", "deriveBits"]
)

最后推导出 key
await window.crypto.subtle.deriveKey(
{
name: "ECDH",
namedCurve: "P-256",
public: publicKey,
},
privateKey,
{
name: "AES-CBC",
length: 256,
},
false,
["encrypt", "decrypt"]
)

在服务器端,我正在执行以下相同的步骤。
生成公钥
private static ECDiffieHellmanCng ecdh = new ECDiffieHellmanCng(256);

public static void GeneratePublicKey()
{
ecdh.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
ecdh.HashAlgorithm = CngAlgorithm.Sha256;
publicKey = ecdh.PublicKey.ToByteArray();
}

导出公钥。请注意,我更改了第一个字节
public static byte[] GetPublicKey()
{
var auxKey = publicKey.Skip(7).ToArray();
auxKey[0] = 4;

return auxKey;
}

导入公钥和派生私钥。请注意,我更改了第一个字节
public static void GerarChavePrivada(byte[] bobPublicKey)
{
byte[] aux = new byte[bobPublicKey.Length + 7];

aux[0] = 0x45;
aux[1] = 0x43;
aux[2] = 0x4B;
aux[3] = 0x31;
aux[4] = 0x20;
aux[5] = 0x00;
aux[6] = 0x00;
aux[7] = 0x00;

for (int i = 1; i < bobPublicKey.Length; i++)
{
aux[7 + i] = bobPublicKey[i];
}

var importedKey = CngKey.Import(aux, CngKeyBlobFormat.EccPublicBlob);
privateKey = ecdh.DeriveKeyMaterial(importedKey);
}

我相信问题出在那些 key 上。无论如何,这些都是加密和解密代码:

Javascript
async function encrypt2(iv, key, data){
var mensagemCriptografada;

await window.crypto.subtle.encrypt(
{
name: "AES-CBC",
iv: iv,
},
key,
str2ab(data) //Data is a string and I'm converting using str2ab method.
)

.then(function(encrypted){
mensagemCriptografada = encrypted;
})
.catch(function(err){
console.error(err);
});

return mensagemCriptografada;
}

function str2ab (str) {
var array = new Uint8Array(str.length);
for(var i = 0; i < str.length; i++) {
array[i] = str.charCodeAt(i);
}
return array.buffer
}

C#
string decMessage = "";

using (Aes aes = new AesCryptoServiceProvider())
{
aes.Key = privateKey;
aes.IV = iv; //IV is the same used by the javascript code
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.None;

var dec = aes.CreateDecryptor(privateKey, iv);

var plain = dec.TransformFinalBlock(message, 0, message.Length);

//I've tried every possible enconding.
decMessage = Encoding.UTF8.GetString(plain);
}

return decMessage;

我真的不知道如何解决这个问题。

最佳答案

我遇到过同样的问题。经过更多调试,我意识到 C# 使用 DeriveKeyMaterial 生成的 key 然后使用 SHA-256 进行哈希处理。

我的解决方案是在 javascript 上导出派生 key ,对其进行哈希处理,然后将其作为新 key 导入。

cryptoApi().deriveKey(
{
name: "ECDH",
namedCurve: "P-256", //can be "P-256", "P-384", or "P-521"
public: ServerKey, //an ECDH public key from generateKey or importKey
},
ECkey.privateKey, //your ECDH private key from generateKey or importKey
{ //the key type you want to create based on the derived bits
name: "AES-CBC", //can be any AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH", or "HMAC")
//the generateKey parameters for that type of algorithm
length: 256, //can be 128, 192, or 256
},
true, //whether the derived key is extractable (i.e. can be used in exportKey)
["encrypt", "decrypt"] //limited to the options in that algorithm's importKey
)
.then(function(AESKeyData){
//returns the exported key data
console.log(AESKeyData);

cryptoApi().exportKey('raw',
AESKeyData
).then(function (exportedAESKeyData) {
cryptoApi().digest('SHA-256', exportedAESKeyData).then(function (HashedAESKeyValue) {
console.log(HashedAESKeyValue);

cryptoApi().importKey(
'raw',
HashedAESKeyValue,
{ //the key type you want to create based on the derived bits
name: "AES-CBC", //can be any AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH", or "HMAC")
//the generateKey parameters for that type of algorithm
length: 256, //can be 128, 192, or 256
},
false,
["encrypt", "decrypt"]
).then(function (TrueAESKey) {

cryptoApi().decrypt(
{
name: 'AES-CBC',
length: 256,
iv: base64ToArrayBuffer(IV)
},
TrueAESKey,
base64ToArrayBuffer(EncryptedData)
).then(function (decrypted) {
console.log(buf2hex(decrypted));
});
})
});
});


})

关于javascript - C# 和 javascript 之间的 ECDH,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52117763/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com