Skip to main content

IvStash

Struct IvStash 

Source
pub struct IvStash { /* private fields */ }
Expand description

Remembers the IV used for each (type, plaintext, aad) triple so re-encrypting an unchanged value reproduces its exact previous ciphertext.

This is not an optimisation. sops edit decrypts, hands the tree to an editor, and re-encrypts everything; without the stash every line of the file changes on every edit, which destroys the property the whole format exists for — a readable, reviewable diff.

§The type is part of the key, and leaving it out is a real bug

Upstream’s key is stashKey{plaintext interface{}, additionalData string}, and a Go map compares an interface{} by dynamic type and value — so int(1) and string("1") are two different keys there. The first version of this struct keyed on the raw plaintext bytes, which collapses exactly the pairs the encodings make indistinguishable:

these are distinct upstreambut share one byte string
1 (int) / 1.0 (float) / "1" (str)1
true (bool) / "True" (str)True
false (bool) / "False" (str)False

Two such leaves under the same AAD — which is to say two elements of one list, since a sequence adds no path component — would then be handed the same nonce. The plaintext bytes are equal, so this is not the catastrophic form of GCM nonce reuse; the consequence is a file whose bytes differ from the one sops would have written, which for a tool whose entire claim is byte-parity is the bug that matters. LeafType is in the key.

§The reuse that remains, stated rather than inherited

Two genuinely identical typed values at one path do still share a nonce. The plaintexts are identical, so an attacker learns only that they are equal — which any deterministic encryption concedes by construction. It is a knowing trade, confined to unchanged values, and it is the price of a reviewable diff.

Implementations§

Source§

impl IvStash

Source

pub fn new() -> Self

Source

pub fn remember(&mut self, plaintext: &Plaintext, aad: &Aad, iv: &[u8])

Record the IV a leaf was decrypted with, so an unchanged value keeps it.

Source

pub fn recall(&self, plaintext: &Plaintext, aad: &Aad) -> Option<Iv>

The remembered IV for this pair, if any.

Source

pub fn len(&self) -> usize

How many pairs are remembered. Diagnostics only.

Source

pub fn is_empty(&self) -> bool

Trait Implementations§

Source§

impl Debug for IvStash

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

The keys of this map are plaintexts. Printing the map would leak every value in the file, so Debug prints only the count.

Source§

impl Default for IvStash

Source§

fn default() -> IvStash

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.