public void CreatePublicKeyToStringAndBack() { var key = RsaTools.CreateKey(); var str = RsaTools.KeyToString(key.Public); var key2 = RsaTools.PublicKeyFromString(str); Assert.AreEqual(key.Public, key2); }
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); }
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 }); }
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)); }
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) })); }
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()); } }
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() })); }
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) })); }
public void CreateKey_Success() { var key = RsaTools.CreateKeyAndSave("test"); Assert.IsNotNull(key); }
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()); }
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)); }
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(); } }