crypto.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. use std::{collections::HashMap, fmt};
  2. use crypto_box::{
  3. aead::{Aead, AeadCore},
  4. SalsaBox,
  5. };
  6. use rand::rngs::OsRng;
  7. use crate::{
  8. privmsg::PrivMsgEvent,
  9. settings::{ChannelInfo, ContactInfo},
  10. };
  11. #[derive(serde::Serialize)]
  12. pub struct KeyPair {
  13. pub private_key: String,
  14. pub public_key: String,
  15. }
  16. impl fmt::Display for KeyPair {
  17. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  18. write!(f, "Public key: {}\nPrivate key: {}", self.public_key, self.private_key)
  19. }
  20. }
  21. /// The format we're using is nonce+ciphertext, where nonce is 24 bytes.
  22. fn try_decrypt(salt_box: &SalsaBox, ciphertext: &str) -> Option<String> {
  23. let bytes = match bs58::decode(ciphertext).into_vec() {
  24. Ok(v) => v,
  25. Err(_) => return None,
  26. };
  27. if bytes.len() < 25 {
  28. return None
  29. }
  30. // Try extracting the nonce
  31. let nonce = match bytes[0..24].try_into() {
  32. Ok(v) => v,
  33. Err(_) => return None,
  34. };
  35. // Take the remaining ciphertext
  36. let message = &bytes[24..];
  37. // Try decrypting the message
  38. match salt_box.decrypt(nonce, message) {
  39. Ok(v) => Some(String::from_utf8_lossy(&v).to_string()),
  40. Err(_) => None,
  41. }
  42. }
  43. /// The format we're using is nonce+ciphertext, where nonce is 24 bytes.
  44. pub fn encrypt(salt_box: &SalsaBox, plaintext: &str) -> String {
  45. let nonce = SalsaBox::generate_nonce(&mut OsRng);
  46. let mut ciphertext = salt_box.encrypt(&nonce, plaintext.as_bytes()).unwrap();
  47. let mut concat = vec![];
  48. concat.append(&mut nonce.as_slice().to_vec());
  49. concat.append(&mut ciphertext);
  50. bs58::encode(concat).into_string()
  51. }
  52. /// Decrypt PrivMsg target
  53. pub fn decrypt_target(
  54. privmsg: &mut PrivMsgEvent,
  55. configured_chans: &HashMap<String, ChannelInfo>,
  56. configured_contacts: &HashMap<String, ContactInfo>,
  57. private_key: &Option<String>,
  58. ) {
  59. for (name, chan_info) in configured_chans {
  60. if !chan_info.joined {
  61. continue
  62. }
  63. let salt_box = chan_info.salt_box(name).clone();
  64. if let Some(salt_box) = salt_box {
  65. if try_decrypt(&salt_box, &privmsg.target).is_some() {
  66. privmsg.target = name.clone();
  67. return
  68. }
  69. }
  70. }
  71. if private_key.is_none() {
  72. return
  73. }
  74. for (name, contact_info) in configured_contacts {
  75. let salt_box = contact_info.salt_box(private_key.as_ref().unwrap(), name).clone();
  76. if let Some(salt_box) = salt_box {
  77. if try_decrypt(&salt_box, &privmsg.target).is_some() {
  78. privmsg.target = name.clone();
  79. return
  80. }
  81. }
  82. }
  83. }
  84. /// Decrypt PrivMsg nickname and message
  85. pub fn decrypt_privmsg(salt_box: &SalsaBox, privmsg: &mut PrivMsgEvent) {
  86. let decrypted_nick = try_decrypt(salt_box, &privmsg.nick);
  87. let decrypted_msg = try_decrypt(salt_box, &privmsg.msg);
  88. if decrypted_nick.is_none() && decrypted_msg.is_none() {
  89. return
  90. }
  91. privmsg.nick = decrypted_nick.unwrap();
  92. privmsg.msg = decrypted_msg.unwrap();
  93. }
  94. /// Encrypt PrivMsg
  95. pub fn encrypt_privmsg(salt_box: &SalsaBox, privmsg: &mut PrivMsgEvent) {
  96. privmsg.nick = encrypt(salt_box, &privmsg.nick);
  97. privmsg.target = encrypt(salt_box, &privmsg.target);
  98. privmsg.msg = encrypt(salt_box, &privmsg.msg);
  99. }