Use dynamic vector as secret type

This commit is contained in:
Tim Visée 2018-03-20 11:43:15 +01:00
parent 3f3f12aa70
commit e7e0d8c1ff
No known key found for this signature in database
GPG key ID: A28432A0AE6E6306
3 changed files with 83 additions and 7 deletions

View file

@ -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

View file

@ -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())

View file

@ -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);
} }