private bool Validate(byte[] data, int msgLength)
        {
            // do we have enough data in the buffer for a HashCash token?
            if (msgLength < Kcp.OVERHEAD + KcpConnection.RESERVED + HashCashEncoding.SIZE)
            {
                return(false);
            }

            // read the token
            HashCash token = HashCashEncoding.Decode(data, Kcp.OVERHEAD + KcpConnection.RESERVED);

            RemoveExpiredTokens();

            // have this token been used?
            if (used.Contains(token))
            {
                return(false);
            }

            // does the token validate?
            if (!token.Validate("Application.productName", HashCashBits))
            {
                return(false);
            }

            used.Add(token);
            expireQueue.Enqueue(token);

            // brand new token, and it is for this app,  go on
            return(true);
        }
Exemple #2
0
        protected async UniTask HandshakeAsync(int bits)
        {
            // in the very first message we must mine a hashcash token
            // and send that as a hello
            // the server won't accept connections otherwise
            string applicationName = Application.productName;

            HashCash token = await UniTask.RunOnThreadPool(() => HashCash.Mine(applicationName, bits));

            byte[] hello  = new byte[1000];
            int    length = HashCashEncoding.Encode(hello, 0, token);

            var data = new ArraySegment <byte>(hello, 0, length);

            // send a greeting and see if the server replies
            await SendAsync(data);

            var stream = new MemoryStream();

            try
            {
                await ReceiveAsync(stream);
            }
            catch (Exception e)
            {
                throw new InvalidDataException("Unable to establish connection, no Handshake message received.", e);
            }
        }
Exemple #3
0
        /// <summary>
        /// Encode a hashcash token into a buffer
        /// </summary>
        /// <param name="buffer">the buffer where to store the hashcash</param>
        /// <param name="index">the index in the buffer where to put it</param>
        /// <param name="hashCash">the token to be encoded</param>
        /// <returns>the length of the written data</returns>
        public static int Encode(byte[] buffer, int index, HashCash hashCash)
        {
            var encoder = new Encoder(buffer, index);

            encoder.Encode64U((ulong)hashCash.dt.Ticks);
            encoder.Encode32U((uint)hashCash.resource);
            encoder.Encode64U(hashCash.salt);
            encoder.Encode64U(hashCash.counter);

            return(encoder.Position - index);
        }
        // remove all the tokens that expired
        private void RemoveExpiredTokens()
        {
            DateTime threshold = DateTime.UtcNow.AddMinutes(-10);

            while (expireQueue.Count > 0)
            {
                HashCash token = expireQueue.Peek();
                if (token.dt > threshold)
                {
                    return;
                }

                expireQueue.Dequeue();
                used.Remove(token);
            }
        }
Exemple #5
0
        /// <summary>
        /// Encode a hashcash token into a buffer
        /// </summary>
        /// <param name="buffer">the buffer where to store the hashcash</param>
        /// <param name="index">the index in the buffer where to put it</param>
        /// <param name="hashCash">the token to be encoded</param>
        /// <returns>the length of the written data</returns>
        public static HashCash Decode(byte[] buffer, int index)
        {
            var   decoder  = new Decoder(buffer, index);
            long  ticks    = (long)decoder.Decode64U();
            int   resource = (int)decoder.Decode32U();
            ulong salt     = decoder.Decode64U();
            ulong counter  = decoder.Decode64U();

            var token = new HashCash(
                new DateTime(ticks),
                resource,
                salt,
                counter
                );

            return(token);
        }