public void EciesDecryptStaticTest(string receiverPrivateKey, string expectedResult, string encryptedData) { // Generate a keypair EthereumEcdsa keypair = EthereumEcdsa.Create(receiverPrivateKey.HexToBytes(), EthereumEcdsaKeyType.Private); // Decrypt the encrypted data with the given key. byte[] decrypted = Ecies.Decrypt(keypair, encryptedData.HexToBytes(), null); // Verify the decrypted result was as expected. Assert.Equal(expectedResult.HexToBytes(), decrypted); }
public void EciesEncryptDecryptTest() { string[] testDataSets = new string[] { "okayAESstrTest", "test2", "and another \x00 test. but this one is a sentence with \x11 weird characters." }; for (int i = 0; i < testDataSets.Length; i++) { // Generate a keypair EthereumEcdsa keypair = EthereumEcdsa.Generate(); byte[] testData = Encoding.UTF8.GetBytes(testDataSets[i]); byte[] encrypted = Ecies.Encrypt(keypair, testData, null); byte[] decrypted = Ecies.Decrypt(keypair, encrypted, null); string result = Encoding.UTF8.GetString(decrypted); Assert.Equal(testDataSets[i], result); } }
/// <summary> /// Verifies the provided encrypted serialized authentication acknowledgement data received from the initiator. /// If verification fails, an appropriate exception will be thrown. If no exception is thrown, the verification /// has succeeded. /// </summary> /// <param name="authAckData">The encrypted serialized authentication acknowledgement data to verify.</param> public void VerifyAuthenticationAcknowledgement(byte[] authAckData) { // Verify this is the initiator role. if (Role != RLPxSessionRole.Initiator) { throw new Exception("RLPx auth-ack data should only be verified by the initiator."); } // Verify the session state is correct. if (SessionState != RLPxSessionState.AuthenticationCompleted) { throw new Exception("RLPx auth-ack verification should only be performed after auth was created/sent."); } // Try to deserialize the data as a standard authentication packet. // The data is currently encrypted serialized data, so it will also need to be decrypted. RLPxAuthAckBase authAckMessage = null; try { // Set the auth-ack data AuthAckData = authAckData.Slice(0, AUTH_ACK_STANDARD_ENCRYPTED_SIZE); // The authentication data can simply be decrypted without any shared mac. byte[] decryptedAuthData = Ecies.Decrypt(LocalPrivateKey, AuthAckData, null); // Try to parse the decrypted authentication data. authAckMessage = new RLPxAuthAckStandard(decryptedAuthData); UsingEIP8Authentication = false; // Set the remote version RemoteVersion = MAX_SUPPORTED_VERSION; } catch (Exception authAckStandardEx) { try { // EIP8 has a uint16 denoting encrypted data size, and the data to decrypt follows. Memory <byte> authAckDataMem = authAckData; Memory <byte> sharedMacDataMem = authAckDataMem.Slice(0, 2); ushort encryptedSize = (ushort)BigIntegerConverter.GetBigInteger(sharedMacDataMem.Span, false, sharedMacDataMem.Length); Memory <byte> encryptedData = authAckDataMem.Slice(2, encryptedSize); // Set our auth-ack data AuthAckData = authAckDataMem.Slice(0, sharedMacDataMem.Length + encryptedSize).ToArray(); // Split the shared mac from the authentication data byte[] decryptedAuthData = Ecies.Decrypt(LocalPrivateKey, encryptedData, sharedMacDataMem); // Try to parse the decrypted EIP8 authentication data. RLPxAuthAckEIP8 authEip8Message = new RLPxAuthAckEIP8(decryptedAuthData); UsingEIP8Authentication = true; // Set the generic authentication data object. authAckMessage = authEip8Message; // Set the remote version RemoteVersion = authEip8Message.Version; } catch (Exception authAckEip8Ex) { string exceptionMessage = "Could not deserialize RLPx auth-ack data in either standard or EIP8 format.\r\n"; exceptionMessage += $"Standard Auth-Ack Error: {authAckStandardEx.Message}\r\n"; exceptionMessage += $"EIP8 Auth-Ack Error: {authAckEip8Ex.Message}"; throw new Exception(exceptionMessage); } } // Set the responder nonce ResponderNonce = authAckMessage.Nonce; // Set the remote public key. RemoteEphermalPublicKey = EthereumEcdsa.Create(authAckMessage.EphemeralPublicKey, EthereumEcdsaKeyType.Public); // Set the session state SessionState = RLPxSessionState.AcknowledgementCompleted; }
/// <summary> /// Verifies the provided encrypted serialized authentication data received from the initiator. /// If verification fails, an appropriate exception will be thrown. If no exception is thrown, /// the verification has succeeded. /// </summary> /// <param name="authData">The encrypted serialized authentication data to verify.</param> public void VerifyAuthentication(byte[] authData) { // Verify this is the responder role. if (Role != RLPxSessionRole.Responder) { throw new Exception("RLPx auth data should only be verified by the responder."); } // Verify the session state is correct. if (SessionState != RLPxSessionState.Initial) { throw new Exception("RLPx auth verification should only be performed on a new session."); } // Try to deserialize the data as a standard authentication packet. // The data is currently encrypted serialized data, so it will also need to be decrypted. RLPxAuthBase authenticationMessage = null; try { // Set the auth data AuthData = authData.Slice(0, AUTH_STANDARD_ENCRYPTED_SIZE); // The authentication data can simply be decrypted without any shared mac. byte[] decryptedAuthData = Ecies.Decrypt(LocalPrivateKey, AuthData, null); // Try to parse the decrypted authentication data. authenticationMessage = new RLPxAuthStandard(decryptedAuthData); UsingEIP8Authentication = false; // Set the remote version RemoteVersion = MAX_SUPPORTED_VERSION; } catch (Exception authStandardEx) { try { // EIP8 has a uint16 denoting encrypted data size, and the data to decrypt follows. Memory <byte> authDataMem = authData; Memory <byte> sharedMacDataMem = authDataMem.Slice(0, 2); ushort encryptedSize = (ushort)BigIntegerConverter.GetBigInteger(sharedMacDataMem.Span, false, sharedMacDataMem.Length); Memory <byte> encryptedData = authDataMem.Slice(2, encryptedSize); // Set our auth data AuthData = authDataMem.Slice(0, sharedMacDataMem.Length + encryptedSize).ToArray(); // Split the shared mac from the authentication data byte[] decryptedAuthData = Ecies.Decrypt(LocalPrivateKey, encryptedData, sharedMacDataMem); // Try to parse the decrypted EIP8 authentication data. RLPxAuthEIP8 authEip8Message = new RLPxAuthEIP8(decryptedAuthData); UsingEIP8Authentication = true; // Set the generic authentication data object. authenticationMessage = authEip8Message; // Set the remote version RemoteVersion = authEip8Message.Version; } catch (Exception authEip8Ex) { string exceptionMessage = "Could not deserialize RLPx auth data in either standard or EIP8 format.\r\n"; exceptionMessage += $"Standard Auth Error: {authStandardEx.Message}\r\n"; exceptionMessage += $"EIP8 Auth Error: {authEip8Ex.Message}"; throw new Exception(exceptionMessage); } } // Set the initiator nonce InitiatorNonce = authenticationMessage.Nonce; // Set the remote public key. RemotePublicKey = EthereumEcdsa.Create(authenticationMessage.PublicKey, EthereumEcdsaKeyType.Public); // Try to recover the public key (with the "receiver" private key, which in this case is our local private key, since our role is responder). // If this fails, it will throw an exception as we expect this method to if any failure occurs. (EthereumEcdsa remoteEphermalPublicKey, uint?chainId) = authenticationMessage.RecoverDataFromSignature(LocalPrivateKey); RemoteEphermalPublicKey = remoteEphermalPublicKey; // TODO: Verify the chain id. // Set the session state SessionState = RLPxSessionState.AuthenticationCompleted; }