Check note plaintext version byte when decrypting
This commit is contained in:
parent
060977fe54
commit
fdb6e208db
|
@ -351,6 +351,12 @@ fn parse_note_plaintext_without_memo(
|
||||||
cmu: &Fr,
|
cmu: &Fr,
|
||||||
plaintext: &[u8],
|
plaintext: &[u8],
|
||||||
) -> Option<(Note<Bls12>, PaymentAddress<Bls12>)> {
|
) -> Option<(Note<Bls12>, PaymentAddress<Bls12>)> {
|
||||||
|
// Check note plaintext version
|
||||||
|
match plaintext[0] {
|
||||||
|
0x01 => (),
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
|
||||||
let mut d = [0u8; 11];
|
let mut d = [0u8; 11];
|
||||||
d.copy_from_slice(&plaintext[1..12]);
|
d.copy_from_slice(&plaintext[1..12]);
|
||||||
|
|
||||||
|
@ -508,6 +514,12 @@ pub fn try_sapling_output_recovery(
|
||||||
NOTE_PLAINTEXT_SIZE
|
NOTE_PLAINTEXT_SIZE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Check note plaintext version
|
||||||
|
match plaintext[0] {
|
||||||
|
0x01 => (),
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
|
||||||
let mut d = [0u8; 11];
|
let mut d = [0u8; 11];
|
||||||
d.copy_from_slice(&plaintext[1..12]);
|
d.copy_from_slice(&plaintext[1..12]);
|
||||||
|
|
||||||
|
@ -543,6 +555,7 @@ pub fn try_sapling_output_recovery(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crypto_api_chachapoly::ChachaPolyIetf;
|
||||||
use ff::{PrimeField, PrimeFieldRepr};
|
use ff::{PrimeField, PrimeFieldRepr};
|
||||||
use pairing::bls12_381::{Bls12, Fr, FrRepr};
|
use pairing::bls12_381::{Bls12, Fr, FrRepr};
|
||||||
use rand::{thread_rng, Rand, Rng};
|
use rand::{thread_rng, Rand, Rng};
|
||||||
|
@ -558,7 +571,8 @@ mod tests {
|
||||||
use super::{
|
use super::{
|
||||||
kdf_sapling, prf_ock, sapling_ka_agree, try_sapling_compact_note_decryption,
|
kdf_sapling, prf_ock, sapling_ka_agree, try_sapling_compact_note_decryption,
|
||||||
try_sapling_note_decryption, try_sapling_output_recovery, Memo, SaplingNoteEncryption,
|
try_sapling_note_decryption, try_sapling_output_recovery, Memo, SaplingNoteEncryption,
|
||||||
COMPACT_NOTE_SIZE, ENC_CIPHERTEXT_SIZE, OUT_CIPHERTEXT_SIZE,
|
COMPACT_NOTE_SIZE, ENC_CIPHERTEXT_SIZE, NOTE_PLAINTEXT_SIZE, OUT_CIPHERTEXT_SIZE,
|
||||||
|
OUT_PLAINTEXT_SIZE,
|
||||||
};
|
};
|
||||||
use crate::{keys::OutgoingViewingKey, JUBJUB};
|
use crate::{keys::OutgoingViewingKey, JUBJUB};
|
||||||
|
|
||||||
|
@ -738,6 +752,60 @@ mod tests {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reencrypt_enc_ciphertext(
|
||||||
|
ovk: &OutgoingViewingKey,
|
||||||
|
cv: &edwards::Point<Bls12, Unknown>,
|
||||||
|
cmu: &Fr,
|
||||||
|
epk: &edwards::Point<Bls12, PrimeOrder>,
|
||||||
|
enc_ciphertext: &mut [u8; ENC_CIPHERTEXT_SIZE],
|
||||||
|
out_ciphertext: &[u8; OUT_CIPHERTEXT_SIZE],
|
||||||
|
modify_plaintext: impl Fn(&mut [u8; NOTE_PLAINTEXT_SIZE]),
|
||||||
|
) {
|
||||||
|
let ock = prf_ock(&ovk, &cv, &cmu, &epk);
|
||||||
|
|
||||||
|
let mut op = [0; OUT_CIPHERTEXT_SIZE];
|
||||||
|
assert_eq!(
|
||||||
|
ChachaPolyIetf::aead_cipher()
|
||||||
|
.open_to(&mut op, out_ciphertext, &[], ock.as_bytes(), &[0u8; 12])
|
||||||
|
.unwrap(),
|
||||||
|
OUT_PLAINTEXT_SIZE
|
||||||
|
);
|
||||||
|
|
||||||
|
let pk_d = edwards::Point::<Bls12, _>::read(&op[0..32], &JUBJUB)
|
||||||
|
.unwrap()
|
||||||
|
.as_prime_order(&JUBJUB)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut esk = FsRepr::default();
|
||||||
|
esk.read_le(&op[32..OUT_PLAINTEXT_SIZE]).unwrap();
|
||||||
|
let esk = Fs::from_repr(esk).unwrap();
|
||||||
|
|
||||||
|
let shared_secret = sapling_ka_agree(&esk, &pk_d);
|
||||||
|
let key = kdf_sapling(shared_secret, &epk);
|
||||||
|
|
||||||
|
let mut plaintext = {
|
||||||
|
let mut buf = [0; ENC_CIPHERTEXT_SIZE];
|
||||||
|
assert_eq!(
|
||||||
|
ChachaPolyIetf::aead_cipher()
|
||||||
|
.open_to(&mut buf, enc_ciphertext, &[], key.as_bytes(), &[0u8; 12])
|
||||||
|
.unwrap(),
|
||||||
|
NOTE_PLAINTEXT_SIZE
|
||||||
|
);
|
||||||
|
let mut pt = [0; NOTE_PLAINTEXT_SIZE];
|
||||||
|
pt.copy_from_slice(&buf[..NOTE_PLAINTEXT_SIZE]);
|
||||||
|
pt
|
||||||
|
};
|
||||||
|
|
||||||
|
modify_plaintext(&mut plaintext);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
ChachaPolyIetf::aead_cipher()
|
||||||
|
.seal_to(enc_ciphertext, &plaintext, &[], &key.as_bytes(), &[0u8; 12])
|
||||||
|
.unwrap(),
|
||||||
|
ENC_CIPHERTEXT_SIZE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decryption_with_invalid_ivk() {
|
fn decryption_with_invalid_ivk() {
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
@ -792,6 +860,28 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decryption_with_invalid_version_byte() {
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
|
let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) =
|
||||||
|
random_enc_ciphertext(&mut rng);
|
||||||
|
|
||||||
|
reencrypt_enc_ciphertext(
|
||||||
|
&ovk,
|
||||||
|
&cv,
|
||||||
|
&cmu,
|
||||||
|
&epk,
|
||||||
|
&mut enc_ciphertext,
|
||||||
|
&out_ciphertext,
|
||||||
|
|pt| pt[0] = 0x02,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
try_sapling_note_decryption(&ivk, &epk, &cmu, &enc_ciphertext),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compact_decryption_with_invalid_ivk() {
|
fn compact_decryption_with_invalid_ivk() {
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
@ -843,6 +933,33 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn compact_decryption_with_invalid_version_byte() {
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
|
let (ovk, ivk, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) =
|
||||||
|
random_enc_ciphertext(&mut rng);
|
||||||
|
|
||||||
|
reencrypt_enc_ciphertext(
|
||||||
|
&ovk,
|
||||||
|
&cv,
|
||||||
|
&cmu,
|
||||||
|
&epk,
|
||||||
|
&mut enc_ciphertext,
|
||||||
|
&out_ciphertext,
|
||||||
|
|pt| pt[0] = 0x02,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
try_sapling_compact_note_decryption(
|
||||||
|
&ivk,
|
||||||
|
&epk,
|
||||||
|
&cmu,
|
||||||
|
&enc_ciphertext[..COMPACT_NOTE_SIZE]
|
||||||
|
),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compact_decryption_with_invalid_diversifier() {
|
fn compact_decryption_with_invalid_diversifier() {
|
||||||
let mut rng = thread_rng();
|
let mut rng = thread_rng();
|
||||||
|
@ -961,6 +1078,28 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn recovery_with_invalid_version_byte() {
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
|
||||||
|
let (ovk, _, cv, cmu, epk, mut enc_ciphertext, out_ciphertext) =
|
||||||
|
random_enc_ciphertext(&mut rng);
|
||||||
|
|
||||||
|
reencrypt_enc_ciphertext(
|
||||||
|
&ovk,
|
||||||
|
&cv,
|
||||||
|
&cmu,
|
||||||
|
&epk,
|
||||||
|
&mut enc_ciphertext,
|
||||||
|
&out_ciphertext,
|
||||||
|
|pt| pt[0] = 0x02,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
try_sapling_output_recovery(&ovk, &cv, &cmu, &epk, &enc_ciphertext, &out_ciphertext),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_vectors() {
|
fn test_vectors() {
|
||||||
let test_vectors = crate::test_vectors::note_encryption::make_test_vectors();
|
let test_vectors = crate::test_vectors::note_encryption::make_test_vectors();
|
||||||
|
|
Loading…
Reference in New Issue