Example #1
0
        public void CreatePublicKeyToStringAndBack()
        {
            var key  = RsaTools.CreateKey();
            var str  = RsaTools.KeyToString(key.Public);
            var key2 = RsaTools.PublicKeyFromString(str);

            Assert.AreEqual(key.Public, key2);
        }
Example #2
0
        public void CreateKeypairToStringAndBack()
        {
            var key  = RsaTools.CreateKey();
            var str  = RsaTools.KeyToString(key.Private);
            var key2 = RsaTools.KeyPairFromString(str);

            Assert.AreEqual(key.Public, key2.Public);
            Assert.AreEqual(key.Private, key2.Private);
        }
Example #3
0
        public void LoadKeysFromFile_Success()
        {
            var keysStored = RsaTools.LoadKeysFromFile("test");

            Assert.IsNotNull(keysStored.Private);
            Assert.IsTrue(keysStored.Private.IsPrivate);

            Assert.IsNotNull(keysStored.Public);
            Assert.IsFalse(keysStored.Public.IsPrivate);
        }
        public BlockchainVoteModelPlainText Decrypt(string keyStr)
        {
            // Get key for decryption from string
            var key = RsaTools.KeyPairFromString(keyStr);
            // Decrypt answers
            var plainAnswersStr = RsaTools.DecryptMessage(Answers, key.Private);
            // Read into answer models
            var answers = JsonConvert.DeserializeObject <List <BlockchainVoteAnswerModel> >(plainAnswersStr);

            // Convert to regular model
            return(new BlockchainVoteModelPlainText
            {
                MagicWords = MagicWords,
                Answers = answers
            });
        }
Example #5
0
        public void BlindSignature_KeysFromFile_Success()
        {
            var serverKey = RsaTools.LoadKeysFromFile("test");

            // Client
            const string message        = "abcdefghijklmnopqrstuvwxyz0123456789";
            var          blindedMessage = RsaTools.BlindMessage(message, serverKey.Public);

            // Server
            var blindSig = RsaTools.SignBlindedMessage(blindedMessage.Blinded, serverKey.Private);

            // Client
            var signedToken = RsaTools.UnblindMessage(blindSig, blindedMessage.Random, serverKey.Public);

            // Server
            Assert.IsTrue(RsaTools.VerifySignature(message, signedToken, serverKey.Private));
        }
Example #6
0
        public async Task <IHttpActionResult> GetPublicKey(string chainString)
        {
            // Check blockchain exists
            try
            {
                await _blockchainStore.GetBlockchainByChainString(chainString);
            }
            catch (RecordNotFoundException)
            {
                return(NotFound());
            }

            var keys = RsaTools.LoadKeysFromFile(chainString);

            return(Ok(new
            {
                PublicKey = RsaTools.KeyToString(keys.Public)
            }));
        }
Example #7
0
        public async Task <IHttpActionResult> IssueCurrency(IssueCurrencyModel model)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            try
            {
                var blockchain = await _blockchainStore.GetBlockchainByChainString(model.Blockchain);

                var keys = RsaTools.LoadKeysFromFile(blockchain.ChainString);

                var signature = new BigInteger(model.BlindSignature);
                if (!RsaTools.VerifySignature(model.Token, signature, keys.Private))
                {
                    return(Unauthorized());
                }

                MultichainModel chain;
                if (!_multichaind.Connections.TryGetValue(model.Blockchain, out chain))
                {
                    return(NotFound());
                }

                var txId = await chain.IssueVote(model.WalletId);

                string words;
                do
                {
                    words = string.Join(" ", RandomWordsGenerator.GetRandomWords());
                } while (await chain.CheckMagicWordsNotOnBlockchain(words, model.WalletId));

                return(Ok(new { TxId = txId, RegistrarAddress = blockchain.WalletId, Words = words }));
            }
            catch (RecordNotFoundException)
            {
                return(NotFound());
            }
        }
Example #8
0
        public async Task <IHttpActionResult> GetBlindSignature(GetBlindSignatureModel model)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            // Get active blockchain connection
            MultichainModel chain;

            if (!_multichaind.Connections.TryGetValue(model.Blockchain, out chain))
            {
                return(NotFound());
            }

            // Check user hasn't had a key signed before
            var voters = await chain.GetVoters();

            if (voters.Any(v => v.Id == User.Identity.GetUserId <int>()))
            {
                return(Unauthorized());
            }

            // Load key
            var keys = RsaTools.LoadKeysFromFile(model.Blockchain);

            // Blindly sign the token
            var message = new BigInteger(model.BlindedToken);
            var signed  = RsaTools.SignBlindedMessage(message, keys.Private);

            // Store the user on the blockchain so they can't have another key
            var voter = new BlockchainVoterModel {
                Id = User.Identity.GetUserId <int>()
            };
            await chain.WriteToStream(MultiChainTools.ROOT_STREAM_NAME, MultiChainTools.VOTERS_KEY, voter);

            return(Ok(new { Signature = signed.ToString() }));
        }
Example #9
0
        public async Task <IHttpActionResult> GetDecryptKey(string chainString)
        {
            // Check blockchain exists
            try
            {
                var blockchain = await _blockchainStore.GetBlockchainByChainString(chainString);

                if (blockchain.ExpiryDate > DateTime.UtcNow)
                {
                    return(Unauthorized());
                }
            }
            catch (RecordNotFoundException)
            {
                return(NotFound());
            }

            var keys = RsaTools.LoadKeysFromFile(chainString + "-encrypt");

            return(Ok(new
            {
                PrivateKey = RsaTools.KeyToString(keys.Private)
            }));
        }
Example #10
0
        public void CreateKey_Success()
        {
            var key = RsaTools.CreateKeyAndSave("test");

            Assert.IsNotNull(key);
        }
Example #11
0
        public async Task <IHttpActionResult> CreateBlockchain(CreateBlockchain model)
        {
            // Must have at least one question
            if ((model.Questions == null) || !model.Questions.Any())
            {
                ModelState.AddModelError("Questions", "At least one question is required");
                return(BadRequest(ModelState));
            }

            // All questions must have at least one answer (although should probably have at least two?)
            if (model.Questions.Any(q => (q.Answers == null) || !q.Answers.Any()))
            {
                ModelState.AddModelError("Questions", "All questions must have at least one answer");
                return(BadRequest(ModelState));
            }

            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            // Check we're not going to have a ChainString collision
            try
            {
                await _blockchainStore.GetBlockchainByChainString(model.ChainString);

                return(BadRequest("A Blockchain already exists with the same name as this!"));
            }
            catch (RecordNotFoundException)
            {
                // This is good
            }

            // multichain-util create {model.ChainString}
            await MultiChainUtilHandler.CreateBlockchain(model.ChainString);

            // Find a Port to run multichaind on
            var blockchains = await _blockchainStore.GetAllBlockchains();

            int port;

            while (true)
            {
                port = MultiChainTools.GetNewPort(EPortType.MultichainD);
                if (blockchains.All(b => b.Port != port))
                {
                    break;
                }
            }

            // Update the default multichain.params to adjust permissions etc.
            UpdateParams(model);

            // Run the blockchain for the first time
            var rpcPort = MultiChainTools.GetNewPort(EPortType.MultichainD);
            var chain   =
                await _multichaind.Connect(IPAddress.Loopback.ToString(), model.ChainString, port, port, rpcPort, false);

            // Convert questions. Each has a unique number (per blockchain) starting from 1
            var questionNumber = 1;

            foreach (var q in model.Questions.Select(q => RequestToBlockchainQuestion(q, ref questionNumber)))
            {
                await chain.WriteToStream(MultiChainTools.ROOT_STREAM_NAME, MultiChainTools.QUESTIONS_KEY, q);
            }

            // Create a new wallet ID for votes to be sent to
            var walletId = await chain.GetNewWalletAddress();

            var blockchain = new RegiBlockchain
            {
                Name        = model.Name,
                ExpiryDate  = model.ExpiryDate,
                Info        = model.Info,
                ChainString = model.ChainString,
                WalletId    = walletId,
                Port        = port
            };

            // Encrypt blockchain results
            if (model.Encrypted)
            {
                // Create encryption key TODO: Don't store on disk?
                var key = RsaTools.CreateKeyAndSave(blockchain.ChainString + "-encrypt");
                blockchain.EncryptKey = RsaTools.KeyToString(key.Public);
            }

            // Save blockchain data in store
            await _blockchainStore.CreateBlockchain(blockchain);

            // Create RSA keypair for blind signing
            RsaTools.CreateKeyAndSave(blockchain.ChainString);

            return(Ok());
        }
Example #12
0
        public async Task <IHttpActionResult> Results(string chainString)
        {
            RegiBlockchain blockchain;

            try
            {
                // Get blockchain info. Ensure exists and is connected to
                blockchain = await _blockchainStore.GetBlockchainByChainString(chainString);
            }
            catch (RecordNotFoundException)
            {
                return(NotFound());
            }

            // Don't allow results if the blockchain is encrypted and not yet ended
            if (!string.IsNullOrWhiteSpace(blockchain.EncryptKey) && (blockchain.ExpiryDate > DateTime.UtcNow))
            {
                return(Unauthorized());
            }

            MultichainModel chain;

            if (!_multichaind.Connections.TryGetValue(blockchain.ChainString, out chain))
            {
                return(NotFound());
            }

            var priv = "";

            if (!string.IsNullOrWhiteSpace(blockchain.EncryptKey))
            {
                var key = RsaTools.LoadKeysFromFile(blockchain.ChainString + "-encrypt");
                priv = RsaTools.KeyToString(key.Private);
            }

            var answers = await chain.GetResults(blockchain.WalletId, priv);

            // Read the questions from the blockchain
            var questions = await chain.GetQuestions();

            // For each question, get its total for each answer
            var results = questions.Select(question =>
            {
                // Setup response dictionary, answer -> num votes
                var options = question.Answers.ToDictionary(a => a.Answer, a => 0);
                foreach (var answer in answers)
                {
                    foreach (var questionAnswer in answer.Answers.Where(a => a.Question == question.Number))
                    {
                        // In case we have anything unusual going on
                        if (!options.ContainsKey(questionAnswer.Answer))
                        {
                            Debug.WriteLine(
                                $"Unexpected answer for question {questionAnswer.Question}: {questionAnswer.Answer}");
                            continue;
                        }
                        options[questionAnswer.Answer]++;
                    }
                }

                return(new BlockchainQuestionResultsResponse(
                           question.Number,
                           question.Question,
                           options
                           ));
            });

            return(Ok(results));
        }
Example #13
0
        public async Task <string> Vote(List <QuestionViewModel> questions, BlockchainDetails blockchain, IProgress <int> progress)
        {
            var voteClient = new VoteClient();

            progress.Report(1);

            try
            {
                // Create our random voting token
                var token = GenerateRandomToken();

                // Get the registrar's public key, to use for the blind signature
                var keyStr = await voteClient.GetPublicKey(Model.Name);

                var key = RsaTools.PublicKeyFromString(keyStr);

                // Blind our token
                progress.Report(2);
                var blindedToken = RsaTools.BlindMessage(token, key);

                // Get the token signed by the registrar
                var blindSignature = await voteClient.GetBlindSignature(Model.Name, blindedToken.Blinded.ToString());

                // Unblind the token
                var unblindedToken = RsaTools.UnblindMessage(new BigInteger(blindSignature), blindedToken.Random,
                                                             key);

                // Here we would normally sleep until a random number of other voters have had tokens blindly signed by the registrar.
                // This would be possible through observation of the root stream using the voters key, or a maximum timeout.
                // However, given that this is a prototype, there is not enough traffic to make this feasible.
                progress.Report(3);

                // Create a wallet address to vote from
                var walletId = await Model.GetNewWalletAddress();

                // Request a voting asset (currency)
                progress.Report(4);
                var regiMeta = await voteClient.GetVote(Model.Name, walletId, token, unblindedToken.ToString());

                // Wait until the currency has been confirmed
                progress.Report(5);
                await Model.ConfirmVoteAllocated();

                // Where the transaction's currency comes from
                progress.Report(6);
                var txIds = new List <CreateRawTransactionTxIn>
                {
                    new CreateRawTransactionTxIn {
                        TxId = regiMeta.TxId, Vout = 0
                    }
                };

                // Where the transaction's currency goes to (registrar)
                var toInfo = new List <CreateRawTransactionAmount>
                {
                    new CreateRawTransactionAsset
                    {
                        Address = regiMeta.RegistrarAddress,
                        Qty     = 1,
                        Name    = MultiChainTools.VOTE_ASSET_NAME
                    }
                };

                // Create our list of answers
                var answers = questions.Select(q => new BlockchainVoteAnswerModel
                {
                    Answer   = q.SelectedAnswer.Answer,
                    Question = q.QuestionNumber
                }).ToList();


                // Send our vote, encrytped if required
                if (blockchain.ShouldEncryptResults)
                {
                    var encryptKey       = RsaTools.PublicKeyFromString(blockchain.EncryptKey);
                    var encryptedAnswers = new BlockchainVoteModelEncrypted
                    {
                        MagicWords = regiMeta.Words,
                        Answers    = RsaTools.EncryptMessage(JsonConvert.SerializeObject(answers), encryptKey)
                    };

                    await Model.WriteTransaction(txIds, toInfo, encryptedAnswers);
                }
                else
                {
                    // Send vote in plaintext (live readable results)
                    var answerModel = new BlockchainVoteModelPlainText
                    {
                        MagicWords = regiMeta.Words,
                        Answers    = answers
                    };

                    await Model.WriteTransaction(txIds, toInfo, answerModel);
                }

                return(regiMeta.Words);
            }
            catch (ApiException)
            {
                progress.Report(-1);
                throw new CouldNotVoteException();
            }
            catch (Exception e)
            {
                progress.Report(-1);
                Debug.WriteLine(e.Message);
                throw new CouldNotVoteException();
            }
        }