public void AuthValidSignAndRecoverEip8()
        {
            // Generate all needed keypairs.
            EthereumEcdsa localPrivateKey     = EthereumEcdsa.Generate();
            EthereumEcdsa ephemeralPrivateKey = EthereumEcdsa.Generate();
            EthereumEcdsa receiverPrivateKey  = EthereumEcdsa.Generate();

            // Create an RLPx auth packet and sign it.
            RLPxAuthEIP8 authPacket = new RLPxAuthEIP8();

            authPacket.Sign(localPrivateKey, ephemeralPrivateKey, receiverPrivateKey, null);

            // Serialize and deserialize it.
            byte[]       serializedData     = authPacket.Serialize();
            RLPxAuthEIP8 deserializedPacket = new RLPxAuthEIP8(serializedData);

            // Verify all matches between our serialized/deserialized object data.
            Assert.Equal(authPacket.Nonce.ToHexString(), deserializedPacket.Nonce.ToHexString());
            Assert.Equal(authPacket.PublicKey.ToHexString(), deserializedPacket.PublicKey.ToHexString());
            Assert.Equal(authPacket.R.ToHexString(), deserializedPacket.R.ToHexString());
            Assert.Equal(authPacket.S.ToHexString(), deserializedPacket.S.ToHexString());
            Assert.Equal(authPacket.V, deserializedPacket.V);

            // Try to recover the public key
            EthereumEcdsa recoveredEphemeralPublicKey = deserializedPacket.RecoverDataFromSignature(receiverPrivateKey).remoteEphemeralPublicKey;

            // Verify our public key hashes match
            Assert.Equal(ephemeralPrivateKey.GetPublicKeyHash().ToHexString(), recoveredEphemeralPublicKey.GetPublicKeyHash().ToHexString());
        }
示例#2
0
        protected override void EndProcessing()
        {
            var config = this.ReadConfig();

            IAccountDerivation accountDerivation;

            if (string.IsNullOrWhiteSpace(Mnemonic))
            {
                var hdWalletAccountDerivation = HDAccountDerivation.Create();
                accountDerivation = hdWalletAccountDerivation;
                Host.UI.WriteLine($"Using mnemonic phrase: '{hdWalletAccountDerivation.MnemonicPhrase}'");
                Host.UI.WriteErrorLine("Warning: this private key generation is not secure and should not be used in production.");
            }
            else
            {
                accountDerivation = new HDAccountDerivation(Mnemonic);
            }

            var accountKeys = new List <(Address Address, EthereumEcdsa Account)>();

            foreach (var account in EthereumEcdsa.Generate(config.AccountCount, accountDerivation))
            {
                // Get an account from the public key hash.
                var address = account.EcdsaKeyPairToAddress();
                accountKeys.Add((address, account));
            }

            var accounts = accountKeys.ToArray();

            GlobalVariables.AccountKeys = accounts;

            Console.WriteLine($"Created {accounts.Length} accounts. Use '{CmdLetExtensions.GetCmdletName<WriteAccountsCommand>()}' to save account keys to disk.");
        }
示例#3
0
        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);
            }
        }
        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); });
        }
示例#5
0
        public RLPxSession(RLPxSessionRole role, EthereumEcdsa localPrivateKey, EthereumEcdsa ephemeralPrivateKey, bool usingEIP8 = false)
        {
            // Verify the private key is not null
            if (localPrivateKey == null)
            {
                throw new ArgumentNullException("Provided local private key for RLPx session was null.");
            }

            // Verify the private key is a private key
            if (localPrivateKey.KeyType != EthereumEcdsaKeyType.Private)
            {
                throw new ArgumentException("Provided local private key for RLPx session was not a valid private key.");
            }

            // Set the local private key
            LocalPrivateKey = localPrivateKey;

            // Verify the ephemeral private key is a private key
            if (ephemeralPrivateKey != null && ephemeralPrivateKey.KeyType != EthereumEcdsaKeyType.Private)
            {
                throw new ArgumentException("Provided local private key for RLPx session was not a valid private key.");
            }

            // Set the ephemeral private key.
            LocalEphemeralPrivateKey = ephemeralPrivateKey ?? EthereumEcdsa.Generate();

            // Set the role and session state
            Role         = role;
            SessionState = RLPxSessionState.Initial;

            // Set the auth type if we are initiator.
            if (Role == RLPxSessionRole.Initiator)
            {
                UsingEIP8Authentication = usingEIP8;
            }
        }
示例#6
0
        public static byte[] Encrypt(EthereumEcdsa remotePublicKey, byte[] data, byte[] sharedMacData = null)
        {
            // If we have no shared mac data, we set it as a blank array
            sharedMacData = sharedMacData ?? Array.Empty <byte>();

            // Generate a random private key
            EthereumEcdsa senderPrivateKey = EthereumEcdsa.Generate(new SystemRandomAccountDerivation());

            // Generate the elliptic curve diffie hellman ("ECDH") shared key
            byte[] ecdhKey = senderPrivateKey.ComputeECDHKey(remotePublicKey);

            // Perform NIST SP 800-56 Concatenation Key Derivation Function ("KDF")
            Memory <byte> keyData = DeriveKeyKDF(ecdhKey, 32);

            // Split the AES encryption key and MAC from the derived key data.
            var aesKey = keyData.Slice(0, 16).ToArray();

            byte[] hmacSha256Key = keyData.Slice(16, 16).ToArray();
            hmacSha256Key = _sha256.ComputeHash(hmacSha256Key);

            // We generate a counter for our aes-128-ctr operation.
            byte[] counter = new byte[AesCtr.BLOCK_SIZE];
            _randomNumberGenerator.GetBytes(counter);

            // Encrypt the data accordingly.
            byte[] encryptedData = AesCtr.Encrypt(aesKey, data, counter);

            // Obtain the sender's public key to compile our message.
            byte[] localPublicKey = senderPrivateKey.ToPublicKeyArray(false, true);

            // We'll want to put this data into the message in the following order (where || is concatenation):
            // ECIES_HEADER_BYTE (1 byte) || sender's public key (64 bytes) || counter (16 bytes) || encrypted data (arbitrary length) || tag (32 bytes)
            // This gives us a total size of 113 + data.Length
            byte[] result = new byte[ECIES_ADDITIONAL_OVERHEAD + encryptedData.Length];

            // Define a pointer and copy in our data as suggested.
            int offset = 0;

            result[offset++] = ECIES_HEADER_BYTE;
            Array.Copy(localPublicKey, 0, result, offset, localPublicKey.Length);
            offset += localPublicKey.Length;
            Array.Copy(counter, 0, result, offset, counter.Length);
            offset += counter.Length;
            Array.Copy(encryptedData, 0, result, offset, encryptedData.Length);
            offset += encryptedData.Length;

            // We still have to copy the tag, which is a HMACSHA256 of our counter + encrypted data + shared mac.

            // We copy the data into a buffer for this hash computation since counter + encrypted data are already aligned.
            byte[] tagPreimage = new byte[counter.Length + encryptedData.Length + sharedMacData.Length];
            Array.Copy(result, 65, tagPreimage, 0, counter.Length + encryptedData.Length);
            Array.Copy(sharedMacData, 0, tagPreimage, counter.Length + encryptedData.Length, sharedMacData.Length);

            // Obtain a HMACSHA256 provider
            HMACSHA256 hmacSha256 = new HMACSHA256(hmacSha256Key);

            // Compute a hash of our counter + encrypted data + shared mac data.
            byte[] tag = hmacSha256.ComputeHash(tagPreimage);

            // Copy the tag into our result buffer.
            Array.Copy(tag, 0, result, offset, tag.Length);
            offset += tag.Length;

            // Return the resulting data.
            return(result);
        }