Rework tests and AES CPU detection
This commit is contained in:
parent
7540fa7d7c
commit
fe7c7f982b
14
.ci/build.sh
14
.ci/build.sh
@ -27,19 +27,7 @@ ls -lah pegh.static.*
|
||||
file pegh.static.*
|
||||
ldd pegh.static.* || true
|
||||
|
||||
# libsodium only supports AES-256-GCM on certain CPUs that have hardware instructions for it
|
||||
# we can build them regardless, but we can't test them without that, pegh prints that right away
|
||||
export TEST_BINS="./pegh.static.openssl ./pegh.openssl ./pegh.static.libsodium-openssl ./pegh.libsodium-openssl"
|
||||
set +e
|
||||
if ./pegh.static.libsodium -h 2>&1 >/dev/null | grep '^Error: libsodium'
|
||||
then
|
||||
echo "CPU does not have AES support so can't run libsodium version"
|
||||
else
|
||||
echo "CPU has AES support so can run libsodium version"
|
||||
# we can test everything
|
||||
export TEST_BINS="$TEST_BINS ./pegh.libsodium ./pegh.static.libsodium"
|
||||
fi
|
||||
set -e
|
||||
export TEST_BINS="./pegh.static.openssl ./pegh.openssl ./pegh.static.libsodium-openssl ./pegh.libsodium-openssl ./pegh.static.libsodium ./pegh.libsodium"
|
||||
|
||||
# compile dynamically linked versions (with gcc) to openssl and libsodium, then test all 4 against each other
|
||||
./test.sh
|
||||
|
53
pegh.c
53
pegh.c
@ -730,9 +730,10 @@ int check_version(uint8_t version, FILE *err) {
|
||||
return 0;
|
||||
}
|
||||
#ifdef PEGH_LIBSODIUM
|
||||
else if (version == 0 && crypto_aead_aes256gcm_is_available() == 0) {
|
||||
/* AES encrypted but libsodium/hardware AES is not available */
|
||||
/* check for AES encrypted but libsodium/hardware AES is not available */
|
||||
#ifdef PEGH_OPENSSL
|
||||
/* if we've already checked/set this, don't again */
|
||||
else if (gcm_encrypt != gcm_encrypt_openssl && version == 0 && crypto_aead_aes256gcm_is_available() == 0) {
|
||||
/* swap to OpenSSL AES which is always supported */
|
||||
if(NULL != err)
|
||||
fprintf(err, "Warning: libsodium does not support AES-256-GCM on this CPU, falling back to openssl version instead...\n");
|
||||
@ -740,9 +741,10 @@ int check_version(uint8_t version, FILE *err) {
|
||||
gcm_decrypt = gcm_decrypt_openssl;
|
||||
CHUNK_SIZE_MAX_GCM = CHUNK_SIZE_MAX_OPENSSL_GCM;
|
||||
#else
|
||||
else if (version == 0 && crypto_aead_aes256gcm_is_available() == 0) {
|
||||
/* nothing we can do */
|
||||
fprintf(stderr, "Error: libsodium does not support AES-256-GCM on this CPU, compile/use openssl version?\n");
|
||||
return 0;
|
||||
return 19;
|
||||
#endif /* PEGH_OPENSSL */
|
||||
}
|
||||
#endif /* PEGH_LIBSODIUM */
|
||||
@ -795,6 +797,8 @@ int pegh_decrypt(char *password,
|
||||
{
|
||||
unsigned char salt[SALT_LEN] = {0};
|
||||
|
||||
int version_exit_code;
|
||||
|
||||
size_t header_read, buffer_size;
|
||||
|
||||
uint32_t N;
|
||||
@ -808,9 +812,9 @@ int pegh_decrypt(char *password,
|
||||
return 0;
|
||||
}
|
||||
version = salt[0];
|
||||
if(1 != check_version(version, err)) {
|
||||
if(1 != (version_exit_code = check_version(version, err))) {
|
||||
fprintf(stderr, "Error: decryption aborting, this file cannot be decrypted with this version/CPU\n");
|
||||
return 0;
|
||||
return version_exit_code;
|
||||
}
|
||||
N = read_uint32_big_endian(salt+1);
|
||||
r = salt[5];
|
||||
@ -922,7 +926,7 @@ uint32_t next_highest_power_of_2(uint32_t v) {
|
||||
return ++v;
|
||||
}
|
||||
|
||||
/* returns 0 on success, 1 on openssl failure, 2 on other failure */
|
||||
/* returns 0 on success, 1 on cryptography failure, 19 on "libsodium only and CPU does not support AES" error, 2 on other failure */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int optind, decrypt = 0, append = 0, exit_code = 2, version = -1;
|
||||
@ -933,6 +937,13 @@ int main(int argc, char **argv)
|
||||
FILE *in = stdin, *out = stdout, *err = stderr;
|
||||
char *in_filename = NULL, *out_filename = NULL;
|
||||
|
||||
#ifdef PEGH_LIBSODIUM
|
||||
if (sodium_init() == -1) {
|
||||
fprintf(stderr, "Error: libsodium could not be initialized, compile/use openssl version?\n");
|
||||
return 1;
|
||||
}
|
||||
#endif /* PEGH_LIBSODIUM */
|
||||
|
||||
for (optind = 1; optind < argc; ++optind) {
|
||||
if(strlen(argv[optind]) == 2 && argv[optind][0] == '-') {
|
||||
|
||||
@ -988,10 +999,27 @@ int main(int argc, char **argv)
|
||||
err = NULL;
|
||||
break;
|
||||
case 'v':
|
||||
version = parse_byte_arg(++optind, argc, argv);
|
||||
if(++optind >= argc) {
|
||||
fprintf(stderr, "Error: %s requires an argument\n", argv[optind - 1]);
|
||||
return help(2);
|
||||
}
|
||||
if(strlen(argv[optind]) != 1 || (argv[optind][0] != '0' && argv[optind][0] != '1')) {
|
||||
fprintf(stderr, "Error: unsupported file format version %s, we only support version 0 (AES-256-GCM) and 1 (Chacha20-Poly1305)\n", argv[optind]);
|
||||
return help(2);
|
||||
}
|
||||
if(argv[optind][0] == '0') {
|
||||
version = 0;
|
||||
#ifdef PEGH_LIBSODIUM
|
||||
if(1 != check_version(0, NULL)) {
|
||||
return help(19);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
version = 1;
|
||||
}
|
||||
break;
|
||||
case 'V':
|
||||
fprintf(stderr, "pegh %s\nformat versions supported: 0\n", PEGH_VERSION);
|
||||
fprintf(stderr, "pegh %s\nformat versions supported: 0 (AES-256-GCM) and 1 (Chacha20-Poly1305)\n", PEGH_VERSION);
|
||||
return 0;
|
||||
case 'h':
|
||||
return help(0);
|
||||
@ -1030,13 +1058,6 @@ int main(int argc, char **argv)
|
||||
return 0;
|
||||
*/
|
||||
|
||||
#ifdef PEGH_LIBSODIUM
|
||||
if (sodium_init() == -1) {
|
||||
fprintf(stderr, "Error: libsodium could not be initialized, compile/use openssl version?\n");
|
||||
return 2;
|
||||
}
|
||||
#endif /* PEGH_LIBSODIUM */
|
||||
|
||||
if(NULL != in_filename) {
|
||||
in = fopen(in_filename, "rb");
|
||||
if(!in) {
|
||||
@ -1089,5 +1110,5 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* to the OS, 0 means success, the above functions 1 means success */
|
||||
return exit_code == 1 ? 0 : 1;
|
||||
return exit_code == 1 ? 0 : (exit_code == 0 ? 1 : exit_code);
|
||||
}
|
||||
|
33
test.sh
33
test.sh
@ -35,28 +35,44 @@ echo "key: $key"
|
||||
|
||||
test () {
|
||||
bin="$1"
|
||||
bin_decrypt="${2:-$bin}"
|
||||
shift
|
||||
bin_decrypt="${1:-$bin}"
|
||||
shift
|
||||
|
||||
echo "testing binaries bin: $bin bin_decrypt: $bin_decrypt"
|
||||
|
||||
set +eu
|
||||
if [ "$2" != "1" ]
|
||||
then
|
||||
# check both binaries through full pipe to see if it fails with an AES error
|
||||
echo a | "$bin" "$@" "$key" | "$bin_decrypt" -d "$key" >/dev/null
|
||||
# 19 is the special return code that means specifically libsodium-only and CPU doesn't support AES
|
||||
[ ${PIPESTATUS[1]} -eq 19 -o ${PIPESTATUS[2]} -eq 19 ] && set -eu && echo "skipping this test because libsodium doesn't support AES on this CPU" && return 0
|
||||
fi
|
||||
set -eu
|
||||
|
||||
|
||||
echo 'encrypting same data with same key should result in different ciphertext'
|
||||
cmp <(echo a | "$bin" "$@" "$key") <(echo a | "$bin" "$@" "$key") && echo "random generation broken? same data and key resulted in same decryption so salt generation is broken and this is insecure" && exit 1 || true
|
||||
|
||||
echo 'encrypting then decrypting with the same key should succeed'
|
||||
"$bin" -e "$key" < "$dummy_file" | "$bin_decrypt" -d "$key" | cmp - "$dummy_file"
|
||||
"$bin" -e "$@" "$key" < "$dummy_file" | "$bin_decrypt" -d "$key" | cmp - "$dummy_file"
|
||||
|
||||
echo 'test with -s 32 requiring 2gb of ram should succeed'
|
||||
# can send -s 32 or -m 2048 to decrypt command with identical effect
|
||||
#"$bin" -e "$key" -s 32 < "$dummy_file" | "$bin_decrypt" -d "$key" -m 2048 | cmp - "$dummy_file"
|
||||
"$bin" -e "$@" "$key" -s 32 < "$dummy_file" | "$bin_decrypt" -d "$key" -m 2048 | cmp - "$dummy_file"
|
||||
|
||||
set +e
|
||||
# these should fail
|
||||
echo 'encrypting with one key and decrypting with another should fail'
|
||||
"$bin" -e "$key" -i "$dummy_file" | "$bin_decrypt" -d "$key-wrongkey" | cmp - "$dummy_file" && echo "ERROR: appending -wrongkey to key somehow still worked" && exit 1
|
||||
"$bin" -e "$@" "$key" -i "$dummy_file" | "$bin_decrypt" -d "$key-wrongkey" | cmp - "$dummy_file" && echo "ERROR: appending -wrongkey to key somehow still worked" && exit 1
|
||||
|
||||
echo 'large values of N without enough memory should fail'
|
||||
"$bin" -e "$key" -N 2000000 -i "$dummy_file" >/dev/null && echo "ERROR: N of 2 million without extra memory worked" && exit 1
|
||||
"$bin" -e "$@" "$key" -N 2000000 -i "$dummy_file" >/dev/null && echo "ERROR: N of 2 million without extra memory worked" && exit 1
|
||||
"$bin_decrypt" -d "$key" -N 2000000 -i "$dummy_file" >/dev/null && echo "ERROR: N of 2 million without extra memory worked" && exit 1
|
||||
|
||||
echo 'bad decryption bytes are never output, file should be 0 bytes'
|
||||
echo 'hopefully this doesnt make it to disk' | "$bin" "$key" | cat - <(echo -n a) | "$bin_decrypt" -d "$key" -o bla.txt && exit 1
|
||||
echo 'hopefully this doesnt make it to disk' | "$bin" "$@" "$key" | cat - <(echo -n a) | "$bin_decrypt" -d "$key" -o bla.txt && exit 1
|
||||
[ -s bla.txt ] && echo "ERROR: bla.txt should be empty" && exit 1
|
||||
set -e
|
||||
}
|
||||
@ -65,7 +81,12 @@ for bin in $TEST_BINS
|
||||
do
|
||||
for bin_decrypt in $TEST_BINS
|
||||
do
|
||||
# test default versions
|
||||
time test $bin $bin_decrypt
|
||||
# test aes
|
||||
time test $bin $bin_decrypt -v 0
|
||||
# test chacha
|
||||
time test $bin $bin_decrypt -v 1
|
||||
done
|
||||
done
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user