Обмен узлами ECDH и C#
Я потерял себя, и мне нужна помощь, чтобы идти в правильном направлении:) У меня есть сервер nodejs, который должен обмениваться критическими данными с сервером, написанным на C#, поэтому в этом случае я хочу, чтобы мои данные были зашифрованы как-то. Я думал об AES, и для безопасного обмена ключами я хочу использовать ECDH, но я не знаю, как заставить его работать правильно... Если я думаю правильно, я могу сделать свою C# "allice" сторону такой:
ECDiffieHellman alice = ECDiffieHellman.Create(ECCurve.NamedCurves.brainpoolP192t1);
var aliceKey = Convert.ToBase64String(alice.PublicKey);
//send key to nodejs server
//recive nodejs key
var nodejsKey = "BobKey";
var aliceSecret = alice.DeriveKeyMaterial(nodejsKey);
//create aes iv
//send message and iv
И nodejs сторона "Боб", как это:
const crypto = require("crypto");
const bob = crypto.createECDH('brainpoolP192t1')
const bobKey = bob.generateKeys('base64');
//send key to C#server
//recive C# key
var cSharpKey = "C#key"
const bobSecret = bob.computeSecret(Buffer.from(cSharpKey));
//create aes
//get mesage and iv ...
Но я не знаю, является ли это хорошим способом сделать это, и я не знаю, как правильно экспортировать ключи между этими языками... если есть лучший способ сделать это, дайте мне знать. Между двумя серверами nodejs я просто отправляю форму ключа в формате base64 и думаю, что он должен работать (если мое понимание верно).
0 ответов
##РЕШЕНИЕ##
C#
class Program
{
static void Main(string[] args)
{
using (ECDiffieHellman alice = ECDiffieHellman.Create(ECCurve.NamedCurves.brainpoolP256r1))
{
var alicePublicKey = Convert.ToBase64String(alice.PublicKey.ToByteArray());
//send alicePublicKey
var nodejsKey = ""; //NODEJS brainpoolP256r1 publickey base64
byte[] nodejsKeyBytes= Convert.FromBase64String(nodejsKey);
var aliceKey = Convert.ToBase64String(getDeriveKey(nodejsKeyBytes,alice));
byte[] encryptedMessage = null;
byte[] iv = null;
// Send(aliceKey, "Secret message", out encryptedMessage, out iv);
}
}
static byte[] getDeriveKey(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.brainpoolP256r1,
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);
}
}
}
NODEJS
const crypto = require("crypto");
const bob = crypto.createECDH('brainpoolP256r1')
bob.generateKeys();
const bobKey = bob.getPublicKey('base64');
var bobLength = Buffer.from(bobKey, 'base64').length;
//send bobkey to c#
//recive alicekey
var alicePublicKey = "RUNLUCAAAAB/xP7JhSIhYIYAijyC2zHu7obB5CwfK/ynQPxcRAIhBI6OLRRcHyPo61AhfSZN3qA2vGDfWO2mrdWWvqqhVaDf";
var aliceKeyBuffer = Buffer.from(alicePublicKey, 'base64');
var aliceKey = Buffer.alloc(bobLength)
aliceKeyBuffer.copy(aliceKey, 1, 8);
aliceKey[0] = 4;
const hash = crypto.createHash('sha256');
var tt = bob.computeSecret(aliceKey);
var bobSecretKey = hash.update(tt).digest('base64');
большое спасибо за bartonjs и Maarten Bodewes
Приведенный выше ответ мне очень помог. Я используюsecp521r1
/nistP521
для генерации ключей как на NodeJS, так и на C#. В моем случае звонокalice.PublicKey.ToByteArray()
приведет к исключению:
Unhandled exception. System.PlatformNotSupportedException: Operation is not supported on this platform.
at System.Security.Cryptography.ECDiffieHellmanImplementation.ECDiffieHellmanSecurityTransforms.ECDiffieHellmanSecurityTransformsPublicKey.ToByteArray()
Согласно проблеме, зарегистрированной командой времени выполнения dotnet здесь:
ECDiffieHellmanPublicKey.ToByteArray() не имеет (стандартного) формата экспорта. Версия, используемая ECDiffieHellmanPublicKeyCng, зависит от Windows и работает только для NIST P-256 (secp256r1), NIST P-384 (secp384r1) и NIST P-521 (secp521r1).
Чтобы создать копию ключа, вы должны использовать метод ExportParameters() для получения расширенного объекта ECParameters; который затем можно отправить через ECDiffieHellman.Create(ECParameters) и прочитать свойство PublicKey этого объекта, чтобы получить второй экземпляр ECDiffieHellmanPublicKey.
Предполагая, что я отправляю свои X и Y от Алисы Бобу (я использовал шестнадцатеричный код вместо base64), соответствующий процесс для получения того же общего секрета на стороне NodeJS выглядит следующим образом:
// Alice's public key X, Y coordinates from DotNet Core
const aliceHexX = '00248F624728B17196B22005742C13D80D3DFF75BCA74AF865195E5A29F41C013653B0931BC544245402EDD7922F38692F38DCCF780CF1A9E27D3CFB5E09E53883C0';
const aliceHexY = '0043517F3B2EF33ED70EFA2BC4163E9B99558A7C2ECB7C659A12EA4024633CFA8B9FC997F0A42D30759B4280FDADC13A67A3E7BB0227047C907FAAE92E7716E8A10D';
const alicePublicKeyXBytes = Buffer.from(aliceHexX, 'hex');
const alicePublicKeyYBytes = Buffer.from(aliceHexY, 'hex');
const alicePublicKey = Buffer.concat([Buffer.from([0x04]), alicePublicKeyXBytes, alicePublicKeyYBytes])
const bobSecret = bob.computeSecret(alicePublicKey);
const hash = crypto.createHash('sha256');
hash.update(bobSecret);
const sharedSecret = hash.digest('hex');
console.log(`Shared Secret: ${sharedSecret.toString('hex')}`);