Validate encryption using externally-generated data
This commit is contained in:
@@ -317,4 +317,96 @@ mod test {
|
|||||||
let cryptor = Cryptor::new(client_key, &secret).unwrap();
|
let cryptor = Cryptor::new(client_key, &secret).unwrap();
|
||||||
assert!(cryptor.unseal(sealed).is_err());
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
77
taskchampion/src/server/generate-test-data.py
Normal file
77
taskchampion/src/server/generate-test-data.py
Normal 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()
|
||||||
2
taskchampion/src/server/test-bad-app-id.data
Normal file
2
taskchampion/src/server/test-bad-app-id.data
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#§$á
|
||||||
|
†—Õ^~B>n)j›i†¯1—î9™|µœÓ~
|
||||||
1
taskchampion/src/server/test-bad-client-key.data
Normal file
1
taskchampion/src/server/test-bad-client-key.data
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<01>ΝA4φ―Γθ
|
||||||
1
taskchampion/src/server/test-bad-secret.data
Normal file
1
taskchampion/src/server/test-bad-secret.data
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/}ådE°‡dIcÁXéè-‡!V°Û%è4îáòd]³ÃÇ}
|
||||||
1
taskchampion/src/server/test-bad-version-id.data
Normal file
1
taskchampion/src/server/test-bad-version-id.data
Normal file
@@ -0,0 +1 @@
|
|||||||
|
lΰζδa|‚ο@Ο<>S_‚¬…γzέV9£q¦Ρ…‘)+¦…
|
||||||
1
taskchampion/src/server/test-bad-version.data
Normal file
1
taskchampion/src/server/test-bad-version.data
Normal file
@@ -0,0 +1 @@
|
|||||||
|
c╙╤TH╗Гp>╔╚Ф╨╕m4О╧к~в1╣0P░IЖ╢W╒
|
||||||
2
taskchampion/src/server/test-bad-version_id.data
Normal file
2
taskchampion/src/server/test-bad-version_id.data
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
B∙
|
||||||
|
Ат-в3%╕jё,*ъ╨7Й╘√QьKЗO╕°FPZщ
|
||||||
1
taskchampion/src/server/test-good.data
Normal file
1
taskchampion/src/server/test-good.data
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pÑ¿µÒŸ½V²ûÝäToë"}cT·äY7Æ ˆÀ@ÙdLTý`Ò
|
||||||
Reference in New Issue
Block a user