Merge pull request #143 from agourlay/expose-aes-info
feat: Expose AES information
This commit is contained in:
commit
6d1b5f7d6c
2 changed files with 69 additions and 1 deletions
21
src/aes.rs
21
src/aes.rs
|
@ -15,7 +15,7 @@ use std::io::{self, Error, ErrorKind, Read, Write};
|
||||||
use zeroize::{Zeroize, Zeroizing};
|
use zeroize::{Zeroize, Zeroizing};
|
||||||
|
|
||||||
/// The length of the password verifcation value in bytes
|
/// The length of the password verifcation value in bytes
|
||||||
const PWD_VERIFY_LENGTH: usize = 2;
|
pub const PWD_VERIFY_LENGTH: usize = 2;
|
||||||
/// The length of the authentication code in bytes
|
/// The length of the authentication code in bytes
|
||||||
const AUTH_CODE_LENGTH: usize = 10;
|
const AUTH_CODE_LENGTH: usize = 10;
|
||||||
/// The number of iterations used with PBKDF2
|
/// The number of iterations used with PBKDF2
|
||||||
|
@ -124,6 +124,25 @@ impl<R: Read> AesReader<R> {
|
||||||
finalized: false,
|
finalized: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read the AES header bytes and returns the verification value and salt.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// the verification value and the salt
|
||||||
|
pub fn get_verification_value_and_salt(
|
||||||
|
mut self,
|
||||||
|
) -> io::Result<([u8; PWD_VERIFY_LENGTH], Vec<u8>)> {
|
||||||
|
let salt_length = self.aes_mode.salt_length();
|
||||||
|
|
||||||
|
let mut salt = vec![0; salt_length];
|
||||||
|
self.reader.read_exact(&mut salt)?;
|
||||||
|
|
||||||
|
// next are 2 bytes used for password verification
|
||||||
|
let mut pwd_verification_value = [0; PWD_VERIFY_LENGTH];
|
||||||
|
self.reader.read_exact(&mut pwd_verification_value)?;
|
||||||
|
Ok((pwd_verification_value, salt))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A reader for aes encrypted files, which has already passed the first password check.
|
/// A reader for aes encrypted files, which has already passed the first password check.
|
||||||
|
|
49
src/read.rs
49
src/read.rs
|
@ -82,6 +82,8 @@ pub(crate) mod zip_archive {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "aes-crypto")]
|
||||||
|
use crate::aes::PWD_VERIFY_LENGTH;
|
||||||
#[cfg(feature = "lzma")]
|
#[cfg(feature = "lzma")]
|
||||||
use crate::read::lzma::LzmaDecoder;
|
use crate::read::lzma::LzmaDecoder;
|
||||||
use crate::result::ZipError::{InvalidPassword, UnsupportedArchive};
|
use crate::result::ZipError::{InvalidPassword, UnsupportedArchive};
|
||||||
|
@ -648,6 +650,41 @@ impl<R: Read + Seek> ZipArchive<R> {
|
||||||
Ok(shared)
|
Ok(shared)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the verification value and salt for the AES encryption of the file
|
||||||
|
///
|
||||||
|
/// It fails if the file number is invalid.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// - None if the file is not encrypted with AES
|
||||||
|
#[cfg(feature = "aes-crypto")]
|
||||||
|
pub fn get_aes_verification_key_and_salt(
|
||||||
|
&mut self,
|
||||||
|
file_number: usize,
|
||||||
|
) -> ZipResult<Option<AesInfo>> {
|
||||||
|
let (_, data) = self
|
||||||
|
.shared
|
||||||
|
.files
|
||||||
|
.get_index(file_number)
|
||||||
|
.ok_or(ZipError::FileNotFound)?;
|
||||||
|
|
||||||
|
let limit_reader = find_content(data, &mut self.reader)?;
|
||||||
|
match data.aes_mode {
|
||||||
|
None => Ok(None),
|
||||||
|
Some((aes_mode, _, _)) => {
|
||||||
|
let (verification_value, salt) =
|
||||||
|
AesReader::new(limit_reader, aes_mode, data.compressed_size)
|
||||||
|
.get_verification_value_and_salt()?;
|
||||||
|
let aes_info = AesInfo {
|
||||||
|
aes_mode,
|
||||||
|
verification_value,
|
||||||
|
salt,
|
||||||
|
};
|
||||||
|
Ok(Some(aes_info))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Read a ZIP archive, collecting the files it contains
|
/// Read a ZIP archive, collecting the files it contains
|
||||||
///
|
///
|
||||||
/// This uses the central directory record of the ZIP file, and ignores local file headers
|
/// This uses the central directory record of the ZIP file, and ignores local file headers
|
||||||
|
@ -940,6 +977,18 @@ impl<R: Read + Seek> ZipArchive<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Holds the AES information of a file in the zip archive
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[cfg(feature = "aes-crypto")]
|
||||||
|
pub struct AesInfo {
|
||||||
|
/// The AES encryption mode
|
||||||
|
pub aes_mode: AesMode,
|
||||||
|
/// The verification key
|
||||||
|
pub verification_value: [u8; PWD_VERIFY_LENGTH],
|
||||||
|
/// The salt
|
||||||
|
pub salt: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
const fn unsupported_zip_error<T>(detail: &'static str) -> ZipResult<T> {
|
const fn unsupported_zip_error<T>(detail: &'static str) -> ZipResult<T> {
|
||||||
Err(ZipError::UnsupportedArchive(detail))
|
Err(ZipError::UnsupportedArchive(detail))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue