Compare commits

..

5 Commits

Author SHA1 Message Date
Andrew Gunnerson 0bad6f8c6f Version 3.1.1
Signed-off-by: Andrew Gunnerson <accounts+github@chiller3.com>
2024-03-05 21:59:41 -05:00
Andrew Gunnerson 4ce4863237 CHANGELOG.md: Add entry for PR #261
Signed-off-by: Andrew Gunnerson <accounts+github@chiller3.com>
2024-03-05 21:59:07 -05:00
Andrew Gunnerson f615bf48cc crypto: reformat_pem: Strip out irrelevant lines
x509_cert is unable to parse files that contains non-empty lines outside
of the BEGIN CERTIFICATE and END CERTIFICATE markers.

Signed-off-by: Andrew Gunnerson <accounts+github@chiller3.com>
2024-03-05 21:42:02 -05:00
Andrew Gunnerson b505b14574 CHANGELOG.md: Add entry for PR #257
Signed-off-by: Andrew Gunnerson <accounts+github@chiller3.com>
2024-02-03 20:38:39 -05:00
Andrew Gunnerson e2adff6eed hashtree: Precompute salted SHA-256 context
With the dm-verity hash tree format, each digest is salted, meaning it
first hashes the salt byte string and then the actual data. Previously,
the salt was being rehashed for each digest operation. Instead, the
salted SHA-256 context can be computed once and then cloned when needed.

The performance improvement is pretty minor, but it's worth doing anyway
since it's not any more complex.

Signed-off-by: Andrew Gunnerson <accounts+github@chiller3.com>
2024-02-03 20:20:15 -05:00
5 changed files with 40 additions and 28 deletions
+7
View File
@@ -7,6 +7,11 @@
to update the actual links at the bottom of the file.
-->
### Version 3.1.1
* Cache salted SHA-256 contexts for a small performance improvement ([PR #257])
* Fix loading certificates that have extra text outside of the marker lines ([PR #261])
### Version 3.1.0
* The `OEMUnlockOnBoot` module has been split out to a separate repo ([Discussion #235], [PR #246])
@@ -244,3 +249,5 @@ Behind-the-scenes changes:
[PR #251]: https://github.com/chenxiaolong/avbroot/pull/251
[PR #255]: https://github.com/chenxiaolong/avbroot/pull/255
[PR #256]: https://github.com/chenxiaolong/avbroot/pull/256
[PR #257]: https://github.com/chenxiaolong/avbroot/pull/257
[PR #261]: https://github.com/chenxiaolong/avbroot/pull/261
Generated
+4 -4
View File
@@ -108,7 +108,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "avbroot"
version = "3.1.0"
version = "3.1.1"
dependencies = [
"anyhow",
"assert_matches",
@@ -532,7 +532,7 @@ dependencies = [
[[package]]
name = "e2e"
version = "3.1.0"
version = "3.1.1"
dependencies = [
"anyhow",
"avbroot",
@@ -626,7 +626,7 @@ dependencies = [
[[package]]
name = "fuzz"
version = "3.1.0"
version = "3.1.1"
dependencies = [
"avbroot",
"honggfuzz",
@@ -2045,7 +2045,7 @@ dependencies = [
[[package]]
name = "xtask"
version = "3.1.0"
version = "3.1.1"
dependencies = [
"anyhow",
"clap",
+1 -1
View File
@@ -4,7 +4,7 @@ members = ["avbroot", "e2e", "fuzz", "xtask"]
resolver = "2"
[workspace.package]
version = "3.1.0"
version = "3.1.1"
license = "GPL-3.0-only"
edition = "2021"
repository = "https://github.com/chenxiaolong/avbroot"
+6 -3
View File
@@ -164,6 +164,9 @@ fn reformat_pem(data: &[u8]) -> Result<Vec<u8>> {
continue;
} else if line.starts_with(b"-----BEGIN CERTIFICATE-----") {
inside_base64 = true;
result.extend_from_slice(line);
result.push(b'\n');
} else if line.starts_with(b"-----END CERTIFICATE-----") {
inside_base64 = false;
@@ -173,13 +176,13 @@ fn reformat_pem(data: &[u8]) -> Result<Vec<u8>> {
}
base64.clear();
result.extend_from_slice(line);
result.push(b'\n');
} else if inside_base64 {
base64.extend_from_slice(line);
continue;
}
result.extend_from_slice(line);
result.push(b'\n');
}
if inside_base64 {
+22 -20
View File
@@ -52,18 +52,19 @@ pub enum Error {
type Result<T> = std::result::Result<T, Error>;
pub struct HashTree<'a> {
pub struct HashTree {
block_size: u32,
algorithm: &'static Algorithm,
salt: &'a [u8],
salted_context: Context,
}
impl<'a> HashTree<'a> {
pub fn new(block_size: u32, algorithm: &'static Algorithm, salt: &'a [u8]) -> Self {
impl HashTree {
pub fn new(block_size: u32, algorithm: &'static Algorithm, salt: &[u8]) -> Self {
let mut salted_context = Context::new(algorithm);
salted_context.update(salt);
Self {
block_size,
algorithm,
salt,
salted_context,
}
}
@@ -72,7 +73,8 @@ impl<'a> HashTree<'a> {
/// in the list. Note that the bottom level is stored at the end of the hash
/// tree data.
fn compute_level_offsets(&self, image_size: u64) -> Result<Vec<Range<usize>>> {
let digest_size = self.algorithm.output_len().next_power_of_two();
let algorithm = self.salted_context.algorithm();
let digest_size = algorithm.output_len().next_power_of_two();
let mut ranges = vec![];
let mut level_size = image_size;
@@ -143,8 +145,8 @@ impl<'a> HashTree<'a> {
cancel_signal: &AtomicBool,
) -> io::Result<()> {
// Each digest must be a power of 2.
let digest_padding =
self.algorithm.output_len().next_power_of_two() - self.algorithm.output_len();
let algorithm = self.salted_context.algorithm();
let digest_padding = algorithm.output_len().next_power_of_two() - algorithm.output_len();
let mut buf = vec![0u8; self.block_size as usize];
while size > 0 {
@@ -157,8 +159,7 @@ impl<'a> HashTree<'a> {
// with padding.
buf[n..].fill(0);
let mut context = Context::new(self.algorithm);
context.update(self.salt);
let mut context = self.salted_context.clone();
context.update(&buf);
// Add the digest to the tree level. Each tree node must be a power
@@ -191,7 +192,8 @@ impl<'a> HashTree<'a> {
);
// Parallelize in larger chunks to avoid too much seek thrashing.
let digest_size = self.algorithm.output_len().next_power_of_two();
let algorithm = self.salted_context.algorithm();
let digest_size = algorithm.output_len().next_power_of_two();
let multiplier = 1024u64;
level_data
@@ -222,7 +224,8 @@ impl<'a> HashTree<'a> {
level_data: &mut [u8],
cancel_signal: &AtomicBool,
) -> io::Result<()> {
let digest_size = self.algorithm.output_len().next_power_of_two();
let algorithm = self.salted_context.algorithm();
let digest_size = algorithm.output_len().next_power_of_two();
level_data
.par_chunks_exact_mut(digest_size)
@@ -263,8 +266,7 @@ impl<'a> HashTree<'a> {
let mut buf = vec![0u8; image_size as usize];
reader.read_exact(&mut buf)?;
let mut context = Context::new(self.algorithm);
context.update(self.salt);
let mut context = self.salted_context.clone();
context.update(&buf);
let digest = context.finish();
@@ -309,8 +311,7 @@ impl<'a> HashTree<'a> {
}
// Calculate the root hash.
let mut context = Context::new(self.algorithm);
context.update(self.salt);
let mut context = self.salted_context.clone();
context.update(&hash_tree_data[level_offsets.last().unwrap().clone()]);
let root_hash = context.finish().as_ref().to_vec();
@@ -402,8 +403,9 @@ impl<'a> HashTree<'a> {
if hash_tree_data != actual_hash_tree_data {
// These are multiple megabytes, so only report the hashes.
let expected = ring::digest::digest(self.algorithm, hash_tree_data);
let actual = ring::digest::digest(self.algorithm, &actual_hash_tree_data);
let algorithm = self.salted_context.algorithm();
let expected = ring::digest::digest(algorithm, hash_tree_data);
let actual = ring::digest::digest(algorithm, &actual_hash_tree_data);
return Err(Error::InvalidHashTree {
expected: hex::encode(expected),