public virtual void Sign(EthereumEcdsa localPrivateKey, EthereumEcdsa ephemeralPrivateKey, EthereumEcdsa receiverPublicKey, uint?chainID = null) { // Generate the shared secret using ECDH between our local private key and this remote public key byte[] ecdhKey = localPrivateKey.ComputeECDHKey(receiverPublicKey); // If our nonce is null, generate a new one Nonce = Nonce ?? RLPxSession.GenerateNonce(); // Verify the nonce is the correct length. if (Nonce.Length != RLPxSession.NONCE_SIZE) { // Throw an exception if an invalid nonce was provided. throw new ArgumentException($"Invalid size nonce provided for RLPx session when signing auth message. Should be {RLPxSession.NONCE_SIZE} bytes but was {Nonce?.Length}."); } // Obtain our transformed nonce data. byte[] transformedNonceData = GetTransformedNonce(ecdhKey); // Sign the transformed data. var signature = ephemeralPrivateKey.SignData(transformedNonceData); // We want our signature in r,s,v format. R = BigIntegerConverter.GetBytes(signature.r, 32); S = BigIntegerConverter.GetBytes(signature.s, 32); V = EthereumEcdsa.GetVFromRecoveryID(chainID, signature.RecoveryID); // Set our local public key and the public key hash. PublicKey = localPrivateKey.ToPublicKeyArray(false, true); }
public void ProvidedHandshakeData() { // Define our nonces byte[] initiatorNonce = "abfee9cf900416b3c08c33e640739d5f27320ec140f024c07587a01bf2118910".HexToBytes(); byte[] responderNonce = "312d4b3f55134880afc60f1a605dbd89dfbc8bc275e0f110221c5b09a23e382e".HexToBytes(); // Create the initiator and responder keypairs EthereumEcdsa initiatorKeyPair = EthereumEcdsa.Create("549f2abf6141a90ff2d21d4a7d8f297d6629d52c279890343840b94100cfe873".HexToBytes(), EthereumEcdsaKeyType.Private); EthereumEcdsa initiatorEphemeralKeyPair = EthereumEcdsa.Create("42fe8795681de5ea19ea164348e1f0321cf2ae03c0731785a0753a503be0a91f".HexToBytes(), EthereumEcdsaKeyType.Private); EthereumEcdsa responderKeyPair = EthereumEcdsa.Create("259e1377ac0022c638b951c64446964c03b2743edd977953c83b72889493c2c4".HexToBytes(), EthereumEcdsaKeyType.Private); EthereumEcdsa responderEphemeralKeypair = EthereumEcdsa.Create("7ad9d85886f3ad51d231dc0a3fe346ffc0aedddcbc1d910a23f7d8215dc4f6f1".HexToBytes(), EthereumEcdsaKeyType.Private); // Initiate RLPx sessions for each role. RLPxSession initiatorSession = new RLPxSession(RLPxSessionRole.Initiator, initiatorKeyPair, initiatorEphemeralKeyPair); RLPxSession responderSession = new RLPxSession(RLPxSessionRole.Responder, responderKeyPair, responderEphemeralKeypair); // Create authentication data (initiator) (should work) byte[] authData = initiatorSession.CreateAuthentiation(responderKeyPair, (byte[])initiatorNonce.Clone()); // Verify the authentication data (responder) (should work) responderSession.VerifyAuthentication(authData); // Create an authentication acknowledgement (responder) (should work) byte[] authAckData = responderSession.CreateAuthenticationAcknowledgement((byte[])responderNonce.Clone()); // Verify the authentication acknowledgement (initiator) (should work) initiatorSession.VerifyAuthenticationAcknowledgement(authAckData); // Set our auth and auth-ack packets (UNCOMMENT/COMMENT THIS ACCORDINGLY FOR TESTING, AS DESCRIBED IN THE SKIP MESSAGE MARKING THIS TEST). //initiatorSession.AuthData = "04ce3672878bc585003184ae8397e7ee3484beb2edadcdb167eca1c34d8369022ce2bda5f02d165c64ea86e12712124759e57d5cac57e2c2b5dbf3b9273b8b1b51c4b879deadc142e5aba12505e307bebf043e0a39153590cd6d388e97997e1fb11e4aaf96084ead8b39f1f2f0992c0e5048219c00e7ca3729ea598ddeeef00ba61b1f6807f500c16eaedf2be25d9715cc664c56c65c1ad4878b564d245ff7b2a416d03ad40b67d7ad859a51be44634925a44f54158dcb23cf4ee7f4c6312cc4315b358be1976d7e0639b3276df741d17510ab7f8804a38a81114584c1320c9f8f55ae2dbd16e14752a5dc96a91af8bffef75e0bb69754d2e4c08e7f3f4aacb15492fa543378cf3839f1be272ad63ce9d874a253e3af358a0dd8d22122137af955e1e6d011f2c0b1792ce24466579e89fb6f44".HexToBytes(); //initiatorSession.AuthAckData = "040be304b52267f5f834b9491dd96beac89195495bbe5fae78cb82cb1bee5906c595af9a56038813f724c7936c492a3ee1f3dfa1dd826249d88acc4f4b0f2ce4f2f48faef6f34a64cbb85b13d138f82b5d447958e6b7c278b748510602dc1043f026f771ca17b9763e14dee7f6e3902d3eeb0f7f8b07da71ccb4107e8cfe53d65ccafbc70b65a0c9ef590c26d207866f9e6d3b0f9ab16cea65e93674b4f155a901e312b83dbb51aed6695afac10ec9b7ea0d1c846310a16a6c45ba2473f85d56894259caf3c425e44d9a90072e049920a6b3".HexToBytes(); //responderSession.AuthData = initiatorSession.AuthData; //responderSession.AuthAckData = initiatorSession.AuthAckData; // Derive our resulting data initiatorSession.DeriveEncryptionParameters(); responderSession.DeriveEncryptionParameters(); // Verify properties Assert.Equal(initiatorNonce, initiatorSession.InitiatorNonce); Assert.Equal(responderNonce, initiatorSession.ResponderNonce); Assert.Equal(initiatorNonce, responderSession.InitiatorNonce); Assert.Equal(responderNonce, responderSession.ResponderNonce); // Get our initial message authentication codes Assert.Equal("a459dc46f089e803a641d02a495965a5fa73e183a2fe5d938f598ff3fd7196d4", initiatorSession.EgressMac.Hash.ToHexString(false)); Assert.Equal("cc4e5144935e90fade946a394df07c293916c51fb4f283f2b0570732a7f474b4", initiatorSession.IngressMac.Hash.ToHexString(false)); Assert.Equal("a459dc46f089e803a641d02a495965a5fa73e183a2fe5d938f598ff3fd7196d4", responderSession.IngressMac.Hash.ToHexString(false)); Assert.Equal("cc4e5144935e90fade946a394df07c293916c51fb4f283f2b0570732a7f474b4", responderSession.EgressMac.Hash.ToHexString(false)); }
protected void VerifyProperties() { // If our nonce is null, generate a new one Nonce = Nonce ?? RLPxSession.GenerateNonce(); // Verify the ephemeral public key is not null and is the correct size. if (EphemeralPublicKey?.Length != EthereumEcdsa.PUBLIC_KEY_SIZE) { throw new ArgumentException("Could not construct RLPx auth-ack because the provided ephemeral public key is not the correct size."); } // Verify the nonce is not null and is the correct size. if (Nonce.Length != RLPxSession.NONCE_SIZE) { throw new ArgumentException("Could not construct RLPx auth-ack because the provided nonce is not the correct size."); } }
public void FullHandshakeStandard(bool useEip8) { // Create the initiator and responder keypairs EthereumEcdsa initiatorKeyPair = EthereumEcdsa.Generate(); EthereumEcdsa initiatorEphemeralKeyPair = EthereumEcdsa.Generate(); EthereumEcdsa responderKeyPair = EthereumEcdsa.Generate(); EthereumEcdsa responderEphemeralKeypair = EthereumEcdsa.Generate(); // Initiate RLPx sessions for each role. RLPxSession initiatorSession = new RLPxSession(RLPxSessionRole.Initiator, initiatorKeyPair, initiatorEphemeralKeyPair, useEip8); RLPxSession responderSession = new RLPxSession(RLPxSessionRole.Responder, responderKeyPair, responderEphemeralKeypair); // Create authentication data (initiator) (should work) byte[] authData = initiatorSession.CreateAuthentiation(responderKeyPair); // Create authentication data (responder) (should fail, responder should only be receiving auth data, not creating it). Assert.Throws <Exception>(() => { responderSession.CreateAuthentiation(initiatorKeyPair); }); // Verify the authentication data (responder) (should work) responderSession.VerifyAuthentication(authData); // Verify the authentication data (initiator) (should fail, responder should only be creating auth data, not verifying/receiving it). Assert.Throws <Exception>(() => { initiatorSession.VerifyAuthentication(authData); }); // After verification, the responder session should have set it's EIP8 status accordingly based off of what was received. Assert.Equal(useEip8, responderSession.UsingEIP8Authentication); // Create an authentication acknowledgement (responder) (should work) byte[] authAckData = responderSession.CreateAuthenticationAcknowledgement(); // Create an authentication acknowledgement (initiator) (should fail, initiator should only receiving auth-ack) Assert.Throws <Exception>(() => { initiatorSession.CreateAuthenticationAcknowledgement(); }); // Verify the authentication acknowledgement (initiator) (should work) initiatorSession.VerifyAuthenticationAcknowledgement(authAckData); // Verify the authentication acknowledgement (responder) (should fail, responder should not be verifying/receiving auth-ack) Assert.Throws <Exception>(() => { responderSession.VerifyAuthenticationAcknowledgement(authAckData); }); }
protected void VerifyProperties() { // If our nonce is null, generate a new one Nonce = Nonce ?? RLPxSession.GenerateNonce(); // Verify the components are the correct size if (R?.Length != 32) { throw new ArgumentException("RLPx EIP8 auth serialization failed because the signature R component must be 32 bytes."); } else if (S?.Length != 32) { throw new ArgumentException("RLPx EIP8 auth serialization failed because the signature R component must be 32 bytes."); } else if (PublicKey?.Length != EthereumEcdsa.PUBLIC_KEY_SIZE) { throw new ArgumentException($"RLPx EIP8 auth serialization failed because the public key must be {EthereumEcdsa.PUBLIC_KEY_SIZE} bytes in size."); } else if (Nonce.Length != RLPxSession.NONCE_SIZE) { throw new ArgumentException($"RLPx EIP8 auth serialization failed because the nonce must be {RLPxSession.NONCE_SIZE} bytes in size."); } }