crypto.rs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. use crypto_box::{
  2. aead::{Aead, AeadCore},
  3. SalsaBox,
  4. };
  5. use fxhash::FxHashMap;
  6. use rand::rngs::OsRng;
  7. use crate::{privmsg::Privmsg, settings::ChannelInfo, MAXIMUM_LENGTH_OF_NICKNAME};
  8. /// Try decrypting a message given a NaCl box and a base58 string.
  9. /// The format we're using is nonce+ciphertext, where nonce is 24 bytes.
  10. fn try_decrypt_message(salt_box: &SalsaBox, ciphertext: &str) -> Option<String> {
  11. let bytes = match bs58::decode(ciphertext).into_vec() {
  12. Ok(v) => v,
  13. Err(_) => return None,
  14. };
  15. if bytes.len() < 25 {
  16. return None
  17. }
  18. // Try extracting the nonce
  19. let nonce = match bytes[0..24].try_into() {
  20. Ok(v) => v,
  21. Err(_) => return None,
  22. };
  23. // Take the remaining ciphertext
  24. let message = &bytes[24..];
  25. // Try decrypting the message
  26. match salt_box.decrypt(nonce, message) {
  27. Ok(v) => Some(String::from_utf8_lossy(&v).to_string()),
  28. Err(_) => None,
  29. }
  30. }
  31. /// Encrypt a message given a NaCl box and a plaintext string.
  32. /// The format we're using is nonce+ciphertext, where nonce is 24 bytes.
  33. pub fn encrypt_message(salt_box: &SalsaBox, plaintext: &str) -> String {
  34. let nonce = SalsaBox::generate_nonce(&mut OsRng);
  35. let mut ciphertext = salt_box.encrypt(&nonce, plaintext.as_bytes()).unwrap();
  36. let mut concat = vec![];
  37. concat.append(&mut nonce.as_slice().to_vec());
  38. concat.append(&mut ciphertext);
  39. bs58::encode(concat).into_string()
  40. }
  41. /// Decrypt PrivMsg target
  42. pub fn decrypt_target(
  43. privmsg: &mut Privmsg,
  44. configured_chans: FxHashMap<String, ChannelInfo>,
  45. configured_contacts: FxHashMap<String, SalsaBox>,
  46. ) {
  47. for chan_name in configured_chans.keys() {
  48. let chan_info = configured_chans.get(chan_name).unwrap();
  49. if !chan_info.joined {
  50. continue
  51. }
  52. let salt_box = chan_info.salt_box.clone();
  53. if salt_box.is_some() {
  54. let decrypted_target = try_decrypt_message(&salt_box.unwrap(), &privmsg.target);
  55. if decrypted_target.is_none() {
  56. continue
  57. }
  58. let target = decrypted_target.unwrap();
  59. if chan_name.to_string() == target {
  60. privmsg.target = target;
  61. }
  62. }
  63. }
  64. for contact in configured_contacts.keys() {
  65. let salt_box = configured_contacts.get(contact).unwrap();
  66. let decrypted_target = try_decrypt_message(&salt_box, &privmsg.target);
  67. if decrypted_target.is_none() {
  68. continue
  69. }
  70. let target = decrypted_target.unwrap();
  71. if contact.to_string() == target {
  72. privmsg.target = target;
  73. }
  74. }
  75. }
  76. /// Decrypt PrivMsg nickname and message
  77. pub fn decrypt_privmsg(salt_box: &SalsaBox, privmsg: &mut Privmsg) {
  78. let decrypted_nick = try_decrypt_message(&salt_box.clone(), &privmsg.nickname);
  79. let decrypted_msg = try_decrypt_message(&salt_box.clone(), &privmsg.message);
  80. if decrypted_nick.is_none() | decrypted_msg.is_none() {
  81. return
  82. }
  83. privmsg.nickname = decrypted_nick.unwrap();
  84. if privmsg.nickname.len() > MAXIMUM_LENGTH_OF_NICKNAME {
  85. privmsg.nickname = privmsg.nickname[..MAXIMUM_LENGTH_OF_NICKNAME].to_string();
  86. }
  87. privmsg.message = decrypted_msg.unwrap();
  88. }
  89. /// Encrypt PrivMsg
  90. pub fn encrypt_privmsg(salt_box: &SalsaBox, privmsg: &mut Privmsg) {
  91. privmsg.nickname = encrypt_message(salt_box, &privmsg.nickname);
  92. privmsg.target = encrypt_message(salt_box, &privmsg.target);
  93. privmsg.message = encrypt_message(salt_box, &privmsg.message);
  94. }