mirror of
https://github.com/timvisee/ffsend.git
synced 2025-10-06 02:29:57 +02:00
Use dynamic vector as secret type
This commit is contained in:
parent
3f3f12aa70
commit
e7e0d8c1ff
3 changed files with 83 additions and 7 deletions
|
@ -3,12 +3,15 @@ use openssl::symm::Cipher;
|
|||
use super::{b64, rand_bytes};
|
||||
use super::hdkf::{derive_auth_key, derive_file_key, derive_meta_key};
|
||||
|
||||
/// The length of an input vector.
|
||||
const KEY_IV_LEN: usize = 12;
|
||||
|
||||
pub struct KeySet {
|
||||
/// A secret.
|
||||
secret: [u8; 16],
|
||||
secret: Vec<u8>,
|
||||
|
||||
/// Input vector.
|
||||
iv: [u8; 12],
|
||||
iv: [u8; KEY_IV_LEN],
|
||||
|
||||
/// A derived file encryption key.
|
||||
file_key: Option<Vec<u8>>,
|
||||
|
@ -22,7 +25,7 @@ pub struct KeySet {
|
|||
|
||||
impl KeySet {
|
||||
/// Construct a new key, with the given `secret` and `iv`.
|
||||
pub fn new(secret: [u8; 16], iv: [u8; 12]) -> Self {
|
||||
pub fn new(secret: Vec<u8>, iv: [u8; 12]) -> Self {
|
||||
Self {
|
||||
secret,
|
||||
iv,
|
||||
|
@ -32,13 +35,82 @@ impl KeySet {
|
|||
}
|
||||
}
|
||||
|
||||
/// Create a key set from the given file ID and secret.
|
||||
/// This method may be used to create a key set based on a Send download
|
||||
/// URL.
|
||||
// TODO: add a parameter for the password and URL
|
||||
// TODO: return a result?
|
||||
// TODO: supply a client instance as parameter
|
||||
pub fn from(file: &DownloadFile) -> Self {
|
||||
// Create a new key set instance
|
||||
let mut set = Self::new(
|
||||
file.secret_raw().clone(),
|
||||
[0; 12],
|
||||
);
|
||||
|
||||
// Derive all keys
|
||||
set.derive();
|
||||
|
||||
// Build the meta cipher
|
||||
// let mut metadata_tag = vec![0u8; 16];
|
||||
// let mut meta_cipher = match encrypt_aead(
|
||||
// KeySet::cipher(),
|
||||
// self.meta_key().unwrap(),
|
||||
// self.iv,
|
||||
// &[],
|
||||
// &metadata,
|
||||
// &mut metadata_tag,
|
||||
// ) {
|
||||
// Ok(cipher) => cipher,
|
||||
// Err(_) => // TODO: return error here,
|
||||
// };
|
||||
|
||||
// Create a reqwest client
|
||||
let client = Client::new();
|
||||
|
||||
// Get the download url, and parse the nonce
|
||||
// TODO: do not unwrap here, return error
|
||||
let download_url = file.download_url(false);
|
||||
let response = client.get(download_url)
|
||||
.send()
|
||||
.expect("failed to get nonce, failed to send file request");
|
||||
|
||||
// Validate the status code
|
||||
// TODO: allow redirects here?
|
||||
if !response.status().is_success() {
|
||||
// TODO: return error here
|
||||
panic!("failed to get nonce, request status is not successful");
|
||||
}
|
||||
|
||||
// Get the authentication nonce
|
||||
// TODO: don't unwrap here, return an error
|
||||
let nonce = b64::decode(
|
||||
response.headers()
|
||||
.get_raw("WWW-Authenticate")
|
||||
.expect("missing authenticate header")
|
||||
.one()
|
||||
.map(|line| String::from_utf8(line.to_vec())
|
||||
.expect("invalid authentication header contents")
|
||||
)
|
||||
.expect("authentication header is empty")
|
||||
.split_terminator(" ")
|
||||
.skip(1)
|
||||
.next()
|
||||
.expect("missing authentication nonce")
|
||||
);
|
||||
|
||||
// TODO: set the input vector
|
||||
|
||||
set
|
||||
}
|
||||
|
||||
/// Generate a secure new key.
|
||||
///
|
||||
/// If `derive` is `true`, file, authentication and metadata keys will be
|
||||
/// derived from the generated secret.
|
||||
pub fn generate(derive: bool) -> Self {
|
||||
// Allocate two keys
|
||||
let mut secret = [0u8; 16];
|
||||
let mut secret = vec![0u8; 16];
|
||||
let mut iv = [0u8; 12];
|
||||
|
||||
// Generate the secrets
|
||||
|
|
|
@ -14,7 +14,7 @@ use crypto::b64;
|
|||
// TODO: match any sub-path?
|
||||
// TODO: match URL-safe base64 chars for the file ID?
|
||||
// TODO: constrain the ID length?
|
||||
const DOWNLOAD_PATH_PATTERN: &'static str = r"$/?download/([[:alnum:]]+={0,3})/?^";
|
||||
const DOWNLOAD_PATH_PATTERN: &'static str = r"$/?download/([[:alnum:]]{8,}={0,3})/?^";
|
||||
|
||||
/// A pattern for Send download URL fragments, capturing the file secret.
|
||||
// TODO: constrain the secret length?
|
||||
|
@ -140,7 +140,8 @@ impl DownloadFile {
|
|||
/// this does not check whether the host is a valid and online Send host.
|
||||
///
|
||||
/// If the URL fragmet contains a file secret, it is also parsed.
|
||||
/// If it does not, the secret is left empty and must be specified manually.
|
||||
/// If it does not, the secret is left empty and must be specified
|
||||
/// manually.
|
||||
pub fn parse_url(url: String) -> Result<DownloadFile, FileParseError> {
|
||||
// Try to parse as an URL
|
||||
let url = Url::parse(&url)
|
||||
|
@ -152,6 +153,9 @@ impl DownloadFile {
|
|||
host.set_query(None);
|
||||
host.set_path("");
|
||||
|
||||
// TODO: remove this after debugging
|
||||
println!("DEBUG: Extracted host: {}", host);
|
||||
|
||||
// Validate the path, get the file ID
|
||||
let re_path = Regex::new(DOWNLOAD_PATH_PATTERN).unwrap();
|
||||
let id = re_path.captures(url.path())
|
||||
|
|
|
@ -27,7 +27,7 @@ impl ProgressReporter for ProgressBar {
|
|||
// Initialize the progress bar
|
||||
let mut bar = Pbr::new(total);
|
||||
bar.set_units(Units::Bytes);
|
||||
bar.message("Upload/encrypt ");
|
||||
bar.message("Encrypt & Upload ");
|
||||
|
||||
self.bar = Some(bar);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue