public void TestKeyExchange(ScpConfig.EncryptionMode encryptionMode) { // Client side var clientEph = ECDHHelper.CreateCngKey(); var clientEphCng = ECDHHelper.CreateECDiffieHellmanCngSha256(clientEph); var clientEphPubKey = clientEphCng.PublicKey(); // Server side var secretarium = new MockedSecretarium(encryptionMode); Assert.IsTrue(secretarium.GetServerHello(clientEphPubKey, out byte[] serverHello)); Assert.IsTrue(ServerHello.Parse(serverHello, 18, out ServerHello serverHelloObj)); // Client side Assert.IsTrue(DiffieHellmanHelper.ComputeProofOfWork(serverHelloObj.proofOfWorkDetails, out byte[] proofOfWork)); var clientProofOfWork = ByteHelper.Combine(proofOfWork.ExtendTo(32), MockedSecretarium.GenesisPubKey); // Server side Assert.IsTrue(secretarium.GetServerIdentity(clientProofOfWork, out byte[] serverIdentity)); Assert.IsTrue(ServerIdentity.Parse(serverIdentity, out ServerIdentity serverIdentityObj)); // Client side var symmetricKey = DiffieHellmanHelper.GetSymmetricKey( clientEphCng, serverIdentityObj.ephDHKey, serverIdentityObj.preMasterSecret); // Check keys are the same both sides Assert.IsTrue(symmetricKey.SequenceEqual(secretarium.Session.SymmetricKey)); }
public bool GetServerIdentity(byte[] clientProofOfWork, out byte[] serverIdentity) { serverIdentity = null; if (!ClientProofOfWork.Parse(clientProofOfWork, out ClientProofOfWork cpow)) { return(false); } if (!cpow.knownSecretariumPubKey.SequenceEqual(GenesisPubKey)) { return(false); } // Create ephemereal DH keys var eph = ECDHHelper.CreateCngKey(); var ephCng = ECDHHelper.CreateECDiffieHellmanCngSha256(eph); var ephPubKey = ephCng.PublicKey(); // Get CommonKey from DH var clientPublicCngKey = Session.ClientEphDHPubKey.ToECDHCngKey(); var commonKey = ephCng.DeriveKeyMaterial(clientPublicCngKey); // Generate a random SymmetricKey var symmetricKey = ByteHelper.GetRandom(commonKey.Length); // XOR CommonKey and SymmetricKey to produce a PreMasterSecret var preMasterSecret = commonKey.Xor(symmetricKey); serverIdentity = ByteHelper.Combine(preMasterSecret, ephPubKey, GenesisPubKey); Session.SymmetricKey = symmetricKey; return(true); }
public void TestDiffieHellmanSha256() { var client = ECDHHelper.CreateECDiffieHellmanCngSha256(); var server = ECDHHelper.CreateECDiffieHellmanCngSha256(); var commonSecretBytesClient = client.DeriveKeyMaterial(server.PublicKey); var commonSecretBytesServer = server.DeriveKeyMaterial(client.PublicKey); Assert.IsTrue(commonSecretBytesClient.SequenceEqual(commonSecretBytesServer)); }
public void TestDiffieHellmanP256() { var clientKey = ECDHHelper.CreateCngKey(); var serverKey = ECDHHelper.CreateCngKey(); var clientECDHCng = ECDHHelper.CreateECDiffieHellmanCngSha256(clientKey); var serverECDHCng = ECDHHelper.CreateECDiffieHellmanCngSha256(serverKey); var commonSecretServer = serverECDHCng.DeriveKeyMaterial(clientECDHCng.PublicKey); var commonSecretClient = clientECDHCng.DeriveKeyMaterial(serverECDHCng.PublicKey); Assert.IsTrue(commonSecretClient.SequenceEqual(commonSecretServer)); }
public void TestDiffieHellmanSha256IsReplayable() { var clientFullKey = ECDHHelper.CreateECDiffieHellmanCngSha256().Key; var serverFullKey = ECDHHelper.CreateECDiffieHellmanCngSha256().Key; var clientECDH1 = ECDHHelper.CreateECDiffieHellmanCngSha256(clientFullKey); var serverECDH1 = ECDHHelper.CreateECDiffieHellmanCngSha256(serverFullKey); var commonSecretBytesClient1 = clientECDH1.DeriveKeyMaterial(serverECDH1.PublicKey); var commonSecretBytesServer1 = serverECDH1.DeriveKeyMaterial(clientECDH1.PublicKey); Assert.IsTrue(commonSecretBytesClient1.SequenceEqual(commonSecretBytesServer1)); var clientECDH2 = ECDHHelper.CreateECDiffieHellmanCngSha256(clientFullKey); var serverECDH2 = ECDHHelper.CreateECDiffieHellmanCngSha256(serverFullKey); var commonSecretBytesClient2 = clientECDH2.DeriveKeyMaterial(serverECDH2.PublicKey); var commonSecretBytesServer2 = serverECDH2.DeriveKeyMaterial(clientECDH2.PublicKey); Assert.IsTrue(commonSecretBytesClient2.SequenceEqual(commonSecretBytesServer2)); Assert.IsTrue(commonSecretBytesClient1.SequenceEqual(commonSecretBytesClient2)); }
private bool FullProtocolFromX509(ScpConfig.EncryptionMode encryptionMode, out byte[] symmetricKey, out MockedSecretarium secretarium) { // Client keys Assert.IsTrue(ScpConfigHelper.TryLoad("test.x509.json", out ScpConfig config)); Assert.IsTrue(config.TryGetECDsaKey(out ECDsaCng clientECDsaKeyCng, "SecretariumTestClient256")); var clientPub = clientECDsaKeyCng.ExportPublicKeyRaw(); // Client Hello var clientEph = ECDHHelper.CreateCngKey(); var clientEphCng = ECDHHelper.CreateECDiffieHellmanCngSha256(clientEph); var clientEphPub = clientEphCng.PublicKey(); var clientHello = clientEphPub; Assert.IsTrue(ClientHello.Parse(clientHello, out ClientHello clientHelloObj)); // Server Hello secretarium = new MockedSecretarium(encryptionMode); secretarium.GetServerHello(clientHello, out byte[] serverHello); Assert.IsTrue(ServerHello.Parse(serverHello, 18, out ServerHello serverHelloObj)); // Client ClientProofOfWork Assert.IsTrue(DiffieHellmanHelper.ComputeProofOfWork(serverHelloObj.proofOfWorkDetails, out byte[] proofOfWork)); var clientProofOfWork = ByteHelper.Combine(proofOfWork.ExtendTo(32), MockedSecretarium.GenesisPubKey); Assert.IsTrue(ClientProofOfWork.Parse(clientProofOfWork, out ClientProofOfWork clientProofOfWorkObj)); // Server Identity secretarium.GetServerIdentity(clientProofOfWork, out byte[] serverIdentity); Assert.IsTrue(ServerIdentity.Parse(serverIdentity, out ServerIdentity serverIdentityObj)); // Client computes symmetric key symmetricKey = DiffieHellmanHelper.GetSymmetricKey( clientEphCng, serverIdentityObj.ephDHKey, serverIdentityObj.preMasterSecret); // Client Proof Of Identity var nonce = ByteHelper.GetRandom(32); var nonceSigned = clientECDsaKeyCng.SignData(nonce); var clientProofOfIdentity = ByteHelper.Combine(nonce, clientEphPub, clientPub, nonceSigned); Assert.IsTrue(ClientProofOfIdentity.Parse(clientProofOfIdentity, out ClientProofOfIdentity clientProofOfIdentityObj)); // Client Encrypts Client Proof Of Identity var ivOffset = ByteHelper.GetRandom(16); var encryptedClientProofOfIdentity = encryptionMode == ScpConfig.EncryptionMode.AESCTR ? clientProofOfIdentity.AesCtrEncrypt(symmetricKey, ivOffset) : clientProofOfIdentity.AesGcmEncryptWithOffset(symmetricKey, ivOffset); var encryptedClientProofOfIdentityWithIvOffset = ByteHelper.Combine(ivOffset, encryptedClientProofOfIdentity); // Server Checks And Sends Proof Of Identity Assert.IsTrue(secretarium.GetServerProofOfIdentity( encryptedClientProofOfIdentityWithIvOffset, out byte[] encryptedServerProofOfIdentity)); // Client Decrypts Server Proof Of Identity ivOffset = encryptedServerProofOfIdentity.Extract(0, 16); var serverProofOfIdentity = encryptionMode == ScpConfig.EncryptionMode.AESCTR ? encryptedServerProofOfIdentity.Extract(16).AesCtrDecrypt(symmetricKey, ivOffset) : encryptedServerProofOfIdentity.Extract(16).AesGcmDecryptWithOffset(symmetricKey, ivOffset); Assert.IsTrue(ServerProofOfIdentity.Parse(serverProofOfIdentity, out ServerProofOfIdentity serverProofOfIdentityObj)); // Client Checks Server Proof Of Idendity var msg = "Hey you! Welcome to Secretarium!".ToBytes(); var secretariumECDsaCng = ECDsaHelper.ImportPublicKey(serverIdentityObj.publicKey); Assert.IsTrue(secretariumECDsaCng.VerifyData( ByteHelper.Combine(serverProofOfIdentityObj.nonce, msg), serverProofOfIdentityObj.welcomeSigned)); return(true); }
public bool Connect(int timeout = 3000) { if (_webSocket != null) { _webSocket.Close(); } // -1- Open Websocket UpdateState(ConnectionState.Connecting); var signal = new AutoResetEvent(false); var canContinue = true; void onOpenHandler(object sender, EventArgs e) { UpdateState(ConnectionState.Open); signal.Set(); } void onCloseHandler(object sender, CloseEventArgs e) { UpdateState(ConnectionState.Closed); canContinue = false; //signal.Set(); Force wait until timeout to avoid quick reconnection loops } void onErrorHandler(object sender, ErrorEventArgs e) { UpdateState(ConnectionState.Closed); canContinue = false; //signal.Set(); Force wait until timeout to avoid quick reconnection loops } EventHandler <MessageEventArgs> onMessageHandler; _webSocket = new WebSocket(_config.secretarium.endPoint, "pair1.sp.nanomsg.org"); _webSocket.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls12; _webSocket.Compression = CompressionMethod.None; _webSocket.OnOpen += onOpenHandler; _webSocket.OnClose += onCloseHandler; _webSocket.OnError += onErrorHandler; _webSocket.Connect(); if (!signal.WaitOne(timeout) || !canContinue) { _webSocket.Close(); return(false); } _webSocket.OnOpen -= onOpenHandler; // -2- Send Client Hello UpdateState(ConnectionState.SecureConnectionInProgress); var clientEphCngKey = ECDHHelper.CreateCngKey(); var clientEphCng = ECDHHelper.CreateECDiffieHellmanCngSha256(clientEphCngKey); var clientEphPub = clientEphCngKey.ExportPublicKeyRaw(); var clientHello = ByteHelper.Combine(_hop, clientEphPub); ServerHello serverHello = null; onMessageHandler = (sender, e) => { if (!ServerHello.Parse(e.RawData.Extract(4), MaxAllowedPoWDifficilty, out serverHello)) { canContinue = false; } signal.Set(); }; _webSocket.OnMessage += onMessageHandler; _webSocket.Send(clientHello); if (!signal.WaitOne(timeout) || !canContinue) { _webSocket.Close(); return(false); } _webSocket.OnMessage -= onMessageHandler; // -3- Send Client Proof Of Work if (!DiffieHellmanHelper.ComputeProofOfWork(serverHello.proofOfWorkDetails, out byte[] proofOfWork))