/ bin / darkirc / src / crypto / saltbox.rs
saltbox.rs
 1  /* This file is part of DarkFi (https://dark.fi)
 2   *
 3   * Copyright (C) 2020-2025 Dyne.org foundation
 4   *
 5   * This program is free software: you can redistribute it and/or modify
 6   * it under the terms of the GNU Affero General Public License as
 7   * published by the Free Software Foundation, either version 3 of the
 8   * License, or (at your option) any later version.
 9   *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU Affero General Public License for more details.
14   *
15   * You should have received a copy of the GNU Affero General Public License
16   * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17   */
18  
19  use crypto_box::{
20      aead::{Aead, AeadCore},
21      ChaChaBox,
22  };
23  use rand::rngs::OsRng;
24  
25  /// Encrypt given data using the given `ChaChaBox`.
26  /// Returns base58-encoded string of the ciphertext.
27  /// Panics if encryption fails.
28  ///
29  /// The encryption format we're using with `ChaChaBox` is `nonce||ciphertext`,
30  /// where nonce is 24 bytes large, and the remaining data should be the ciphertext.
31  pub fn encrypt(salt_box: &ChaChaBox, plaintext: &[u8]) -> String {
32      // Generate the nonce
33      let nonce = ChaChaBox::generate_nonce(&mut OsRng);
34  
35      // Encrypt
36      let mut ciphertext = salt_box.encrypt(&nonce, plaintext).unwrap();
37  
38      // Concatenate
39      let mut concat = Vec::with_capacity(24 + ciphertext.len());
40      concat.append(&mut nonce.as_slice().to_vec());
41      concat.append(&mut ciphertext);
42  
43      // Encode
44      bs58::encode(concat).into_string()
45  }
46  
47  /// Attempt to decrypt given ciphertext using the given `ChaChaBox`.
48  /// Returns a `Vec<u8>` on success, and `None` on failure.
49  ///
50  /// The encryption format we're using with `ChaChaBox` is `nonce||ciphertext`,
51  /// where nonce is 24 bytes large, and the remaining data should be the ciphertext.
52  pub fn try_decrypt(salt_box: &ChaChaBox, ciphertext: &[u8]) -> Option<Vec<u8>> {
53      // Make sure we have enough bytes to work with
54      if ciphertext.len() < 25 {
55          return None
56      }
57  
58      salt_box.decrypt((&ciphertext[0..24]).into(), &ciphertext[24..]).ok()
59  }