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::{b64, rand_bytes};
|
||||||
use super::hdkf::{derive_auth_key, derive_file_key, derive_meta_key};
|
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 {
|
pub struct KeySet {
|
||||||
/// A secret.
|
/// A secret.
|
||||||
secret: [u8; 16],
|
secret: Vec<u8>,
|
||||||
|
|
||||||
/// Input vector.
|
/// Input vector.
|
||||||
iv: [u8; 12],
|
iv: [u8; KEY_IV_LEN],
|
||||||
|
|
||||||
/// A derived file encryption key.
|
/// A derived file encryption key.
|
||||||
file_key: Option<Vec<u8>>,
|
file_key: Option<Vec<u8>>,
|
||||||
|
@ -22,7 +25,7 @@ pub struct KeySet {
|
||||||
|
|
||||||
impl KeySet {
|
impl KeySet {
|
||||||
/// Construct a new key, with the given `secret` and `iv`.
|
/// 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 {
|
Self {
|
||||||
secret,
|
secret,
|
||||||
iv,
|
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.
|
/// Generate a secure new key.
|
||||||
///
|
///
|
||||||
/// If `derive` is `true`, file, authentication and metadata keys will be
|
/// If `derive` is `true`, file, authentication and metadata keys will be
|
||||||
/// derived from the generated secret.
|
/// derived from the generated secret.
|
||||||
pub fn generate(derive: bool) -> Self {
|
pub fn generate(derive: bool) -> Self {
|
||||||
// Allocate two keys
|
// Allocate two keys
|
||||||
let mut secret = [0u8; 16];
|
let mut secret = vec![0u8; 16];
|
||||||
let mut iv = [0u8; 12];
|
let mut iv = [0u8; 12];
|
||||||
|
|
||||||
// Generate the secrets
|
// Generate the secrets
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crypto::b64;
|
||||||
// TODO: match any sub-path?
|
// TODO: match any sub-path?
|
||||||
// TODO: match URL-safe base64 chars for the file ID?
|
// TODO: match URL-safe base64 chars for the file ID?
|
||||||
// TODO: constrain the ID length?
|
// 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.
|
/// A pattern for Send download URL fragments, capturing the file secret.
|
||||||
// TODO: constrain the secret length?
|
// 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.
|
/// 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 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> {
|
pub fn parse_url(url: String) -> Result<DownloadFile, FileParseError> {
|
||||||
// Try to parse as an URL
|
// Try to parse as an URL
|
||||||
let url = Url::parse(&url)
|
let url = Url::parse(&url)
|
||||||
|
@ -152,6 +153,9 @@ impl DownloadFile {
|
||||||
host.set_query(None);
|
host.set_query(None);
|
||||||
host.set_path("");
|
host.set_path("");
|
||||||
|
|
||||||
|
// TODO: remove this after debugging
|
||||||
|
println!("DEBUG: Extracted host: {}", host);
|
||||||
|
|
||||||
// Validate the path, get the file ID
|
// Validate the path, get the file ID
|
||||||
let re_path = Regex::new(DOWNLOAD_PATH_PATTERN).unwrap();
|
let re_path = Regex::new(DOWNLOAD_PATH_PATTERN).unwrap();
|
||||||
let id = re_path.captures(url.path())
|
let id = re_path.captures(url.path())
|
||||||
|
|
|
@ -27,7 +27,7 @@ impl ProgressReporter for ProgressBar {
|
||||||
// Initialize the progress bar
|
// Initialize the progress bar
|
||||||
let mut bar = Pbr::new(total);
|
let mut bar = Pbr::new(total);
|
||||||
bar.set_units(Units::Bytes);
|
bar.set_units(Units::Bytes);
|
||||||
bar.message("Upload/encrypt ");
|
bar.message("Encrypt & Upload ");
|
||||||
|
|
||||||
self.bar = Some(bar);
|
self.bar = Some(bar);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue