Validate encryption using externally-generated data

This commit is contained in:
Dustin J. Mitchell 2021-10-19 18:31:30 -04:00
parent 17f5521ea4
commit 0af66fd6c8
9 changed files with 178 additions and 0 deletions

View file

@ -317,4 +317,96 @@ mod test {
let cryptor = Cryptor::new(client_key, &secret).unwrap();
assert!(cryptor.unseal(sealed).is_err());
}
mod externally_valid {
// validate data generated by generate-test-data.py. The intent is to
// validate that this format matches the specification by implementing
// the specification in a second language
use super::*;
use pretty_assertions::assert_eq;
/// The values in generate-test-data.py
fn defaults() -> (Uuid, Uuid, Vec<u8>) {
(
Uuid::parse_str("b0517957-f912-4d49-8330-f612e73030c4").unwrap(),
Uuid::parse_str("0666d464-418a-4a08-ad53-6f15c78270cd").unwrap(),
b"b4a4e6b7b811eda1dc1a2693ded".to_vec(),
)
}
#[test]
fn good() {
let (version_id, client_key, encryption_secret) = defaults();
let sealed = Sealed {
version_id,
payload: include_bytes!("test-good.data").to_vec(),
};
let cryptor = Cryptor::new(client_key, &Secret(encryption_secret)).unwrap();
let unsealed = cryptor.unseal(sealed).unwrap();
assert_eq!(unsealed.payload, b"SUCCESS");
assert_eq!(unsealed.version_id, version_id);
}
#[test]
fn bad_version_id() {
let (version_id, client_key, encryption_secret) = defaults();
let sealed = Sealed {
version_id,
payload: include_bytes!("test-bad-version-id.data").to_vec(),
};
let cryptor = Cryptor::new(client_key, &Secret(encryption_secret)).unwrap();
assert!(cryptor.unseal(sealed).is_err());
}
#[test]
fn bad_client_key() {
let (version_id, client_key, encryption_secret) = defaults();
let sealed = Sealed {
version_id,
payload: include_bytes!("test-bad-client-key.data").to_vec(),
};
let cryptor = Cryptor::new(client_key, &Secret(encryption_secret)).unwrap();
assert!(cryptor.unseal(sealed).is_err());
}
#[test]
fn bad_secret() {
let (version_id, client_key, encryption_secret) = defaults();
let sealed = Sealed {
version_id,
payload: include_bytes!("test-bad-secret.data").to_vec(),
};
let cryptor = Cryptor::new(client_key, &Secret(encryption_secret)).unwrap();
assert!(cryptor.unseal(sealed).is_err());
}
#[test]
fn bad_version() {
let (version_id, client_key, encryption_secret) = defaults();
let sealed = Sealed {
version_id,
payload: include_bytes!("test-bad-version.data").to_vec(),
};
let cryptor = Cryptor::new(client_key, &Secret(encryption_secret)).unwrap();
assert!(cryptor.unseal(sealed).is_err());
}
#[test]
fn bad_app_id() {
let (version_id, client_key, encryption_secret) = defaults();
let sealed = Sealed {
version_id,
payload: include_bytes!("test-bad-app-id.data").to_vec(),
};
let cryptor = Cryptor::new(client_key, &Secret(encryption_secret)).unwrap();
assert!(cryptor.unseal(sealed).is_err());
}
}
}

View file

@ -0,0 +1,77 @@
# This file generates test-encrypted.data. To run it:
# - pip install cryptography pbkdf2
# - python taskchampion/src/server/generate-test-data.py taskchampion/src/server/
import os
import hashlib
import pbkdf2
import secrets
import sys
import uuid
from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305
# these values match values used in the rust tests
client_key = "0666d464-418a-4a08-ad53-6f15c78270cd"
encryption_secret = b"b4a4e6b7b811eda1dc1a2693ded"
version_id = "b0517957-f912-4d49-8330-f612e73030c4"
def gen(
version_id=version_id, client_key=client_key, encryption_secret=encryption_secret,
app_id=1, version=1):
# first, generate the encryption key
salt = hashlib.sha256(uuid.UUID(client_key).bytes).digest()
key = pbkdf2.PBKDF2(
encryption_secret,
salt,
digestmodule=hashlib.sha256,
iterations=100000,
).read(32)
# create a nonce
nonce = secrets.token_bytes(12)
assert len(b"\x01") == 1
# create the AAD
aad = b''.join([
bytes([app_id]),
uuid.UUID(version_id).bytes,
])
# encrypt using AEAD
chacha = ChaCha20Poly1305(key)
ciphertext = chacha.encrypt(nonce, b"SUCCESS", aad)
# create the envelope
envelope = b''.join([
bytes([version]),
nonce,
ciphertext,
])
return envelope
def main():
dir = sys.argv[1]
with open(os.path.join(dir, 'test-good.data'), "wb") as f:
f.write(gen())
with open(os.path.join(dir, 'test-bad-version-id.data'), "wb") as f:
f.write(gen(version_id=uuid.uuid4().hex))
with open(os.path.join(dir, 'test-bad-client-key.data'), "wb") as f:
f.write(gen(client_key=uuid.uuid4().hex))
with open(os.path.join(dir, 'test-bad-secret.data'), "wb") as f:
f.write(gen(encryption_secret=b"xxxxxxxxxxxxxxxxxxxxx"))
with open(os.path.join(dir, 'test-bad-version.data'), "wb") as f:
f.write(gen(version=99))
with open(os.path.join(dir, 'test-bad-app-id.data'), "wb") as f:
f.write(gen(app_id=99))
main()

View file

@ -0,0 +1,2 @@
$á­
†—Õ^~B>n)ji†¯1—î9™|µœÓ~

View file

@ -0,0 +1 @@
<01>ΝA4φ―Γθ t;Δτ υηp¦Ο¦x^Αύreό…<CF8C>JΤ¤<CEA4>

View file

@ -0,0 +1 @@
/}åd E°‡dIcÁXéè-‡!V°Û%è4îáòd]³ÃÇ}

View file

@ -0,0 +1 @@
lΰζδa|ο@Ο<>S_¬…γzέV9£q¦Ρ…‘)+¦

View file

@ -0,0 +1 @@
c╙╤TH╗Гp>╔╚Ф╨╕m4О╧к~в1╣0P░IЖ╢W╒

View file

@ -0,0 +1,2 @@
B∙
Ат-в3%╕jё,*ъ╨7Й╘√QьKЗO╕°FPZщ

View file

@ -0,0 +1 @@
pÑ¿µÒŸ½V²ûÝäToë"}cT·äY7Æ ˆÀ@ÙdLTý`Ò