.NET Core 5.0到Javascript DFH密钥交换不工作
我们正试图获得一个基于浏览器的应用程序,该应用程序使用JS与使用Eliptical Curve Diffie Hellman的.Net Core 5.0服务器交换密钥。 我们的应用程序需要在两端共享一个秘密,用于我们所做的某些特定处理(不是加密,而是我们自己的处理),我们希望该秘密能够被派生出来 而不是出于安全目的传输。 我们已经四处寻找合适的解决方案,并将各种解决方案拼凑在一起,我们已经找到了这个解决方案,但它失败了,C#端出现了一个例外。 基本上,我们的伪代码如下(到目前为止,我们只进行了步骤3):.NET Core 5.0到Javascript DFH密钥交换不工作,javascript,c#,diffie-hellman,Javascript,C#,Diffie Hellman,我们正试图获得一个基于浏览器的应用程序,该应用程序使用JS与使用Eliptical Curve Diffie Hellman的.Net Core 5.0服务器交换密钥。 我们的应用程序需要在两端共享一个秘密,用于我们所做的某些特定处理(不是加密,而是我们自己的处理),我们希望该秘密能够被派生出来 而不是出于安全目的传输。 我们已经四处寻找合适的解决方案,并将各种解决方案拼凑在一起,我们已经找到了这个解决方案,但它失败了,C#端出现了一个例外。 基本上,我们的伪代码如下(到目前为止,我们只进行了步
async function setUpDFHKeys() {
let bobPublicKeyB64;
let bobPrivateKeyB64;
try {
const bobKey = await window.crypto.subtle.generateKey(
{ name: 'ECDH', namedCurve: 'P-256' },
true,
["deriveKey"]
);
const publicKeyData = await window.crypto.subtle.exportKey("raw", bobKey.publicKey);
const publicKeyBytes = new Uint8Array(publicKeyData);
const publicKeyB64 = btoa(publicKeyBytes);
bobPublicKeyB64 = publicKeyB64;
const privateKeyData = await window.crypto.subtle.exportKey("pkcs8", bobKey.privateKey);
const privateKeyBytes = new Uint8Array(privateKeyData);
const privateKeyB64 = btoa(String.fromCharCode.apply(null, privateKeyBytes));
bobPrivateKeyB64 = privateKeyB64;
}
catch (error) {
console.log("Could not setup DFH Keys " + error);
}};
以下是Alice的C#代码:
private string WorkWithJSPublicKey(string bobPublicKeyB64, out string alicePublicKey)
{
try
{
//
// Alice is this server.
// Bob is a browser that uses the window.crypto.subtle.generateKey with 'ECDH' and 'P-256' as parameters
// and window.crypto.subtle.exportKey of the key.publicKey in "raw" format (this is then converted to a B64 string using btoa)
//
using (ECDiffieHellman alice = ECDiffieHellman.Create(ECCurve.NamedCurves.nistP256))
{
//
// Get the public key info from Bob and convert to B64 string to return to Alice
//
Span<byte> exported = new byte[alice.KeySize];
int len = 0;
alice.TryExportSubjectPublicKeyInfo(exported, out len);
alicePublicKey = Convert.ToBase64String(exported.Slice(0, len));
//
// Get Alice's private key to use to generate a shared secret
//
byte[] alicePrivateKey = alice.ExportECPrivateKey();
//
// Import Bob's public key after converting it to bytes
//
var bobPubKeyBytes = Convert.FromBase64String(bobPublicKeyB64);
//
// TRY THIS... (Bombs with "The specified curve 'nistP256' or its parameters are not valid for this platform").
//
// getDerivedKey(bobPubKeyBytes, alice);
//
// This throws exception ("The provided data is tagged with 'Universal' class value '20', but it should have been 'Universal' class value '16'.")
//
alice.ImportSubjectPublicKeyInfo(bobPubKeyBytes, out len);
//
// Once Alice knows about Bob, create a shared secret and return it.
//
byte[] sharedSecret = alice.DeriveKeyMaterial(alice.PublicKey);
return Convert.ToBase64String(sharedSecret);
}
}
catch (Exception ex)
{
_logger.LogError(ex, ex.Message);
alicePublicKey = string.Empty;
return string.Empty;
}
}
如果Web加密端的公钥以X.509/SPKI格式导出,而不是作为原始密钥导出,则解决方案更简单,因为.NET 5对此格式有一个专用的导入方法。此外,这与C#代码一致,其中公钥也以X.509/SPKI格式导出。在下面的示例中,Web加密代码以X.509/SPKI格式导出公钥 步骤1-Web加密端(Bob):生成EC密钥对 以下Web加密代码创建ECDH密钥对,并导出X.509/SPKI格式的公钥(以及PKCS8格式的私钥)。请注意,由于存在错误,以PKCS8格式导出在Firefox下不起作用,另请参见:
setUpDFHKeys()。然后(()=>{});
异步函数setUpDFHKeys(){
var bobKey=wait window.crypto.minute.generateKey(
{name:'ECDH',namedCurve:'P-256'},
是的,
[“衍生密钥”]
);
var publicKeyData=await window.crypto.minute.exportKey(“spki”,bobKey.publicKey);
var publicKeyBytes=新的Uint8Array(publicKeyData);
var publicKeyB64=btoa(String.fromCharCode.apply(null,publicKeyBytes));
log(“Bob的public:\n”+publicKeyB64.replace(/({56})/g,$1\n');
var privateKeyData=await window.crypto.minute.exportKey(“pkcs8”,bobKey.privateKey);
var privateKeyBytes=新的Uint8Array(privateKeyData);
var privateKeyB64=btoa(String.fromCharCode.apply(null,privateKeyBytes));
log(“Bob的private:\n”+privateKeyB64.replace(/({56})/g,$1\n');
};代码>只是“.NET5.0”,而不是“.NETCore5.0”。谢谢,这很有效。注意,在将BobPublicey发送给Alice之前,必须使用EncodeuriComponent(BobPublice64)对其进行编码,因为它嵌入了“+”和“=”字符。
static byte[] getDerivedKey(byte[] key1, ECDiffieHellman alice)
{
byte[] keyX = new byte[key1.Length / 2];
byte[] keyY = new byte[keyX.Length];
Buffer.BlockCopy(key1, 1, keyX, 0, keyX.Length);
Buffer.BlockCopy(key1, 1 + keyX.Length, keyY, 0, keyY.Length);
ECParameters parameters = new ECParameters
{
Curve = ECCurve.NamedCurves.nistP256,
Q = {
X = keyX,
Y = keyY,
},
};
byte[] derivedKey;
using (ECDiffieHellman bob = ECDiffieHellman.Create(parameters))
using (ECDiffieHellmanPublicKey bobPublic = bob.PublicKey)
{
return derivedKey = alice.DeriveKeyFromHash(bobPublic, HashAlgorithmName.SHA256);
}
}