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

View file

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