From 5a218b105f03e458d6468e8107004fd2896440e4 Mon Sep 17 00:00:00 2001 From: Jari Nippula Date: Tue, 19 Nov 2024 10:36:21 +0200 Subject: [PATCH 1/2] Logger: combined key & cipher file Use one single .ulge file to store both wrapped symmetric key and encrypted ulog data instead of creating separate .ulgk/ulgc files --- src/modules/logger/log_writer_file.cpp | 31 ++++++-------------------- src/modules/logger/logger.cpp | 2 +- 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/src/modules/logger/log_writer_file.cpp b/src/modules/logger/log_writer_file.cpp index dae17c2efb0c..4329e730b945 100644 --- a/src/modules/logger/log_writer_file.cpp +++ b/src/modules/logger/log_writer_file.cpp @@ -149,28 +149,7 @@ bool LogWriterFile::init_logfile_encryption(const char *filename) rsa_crypto.close(); // Write the encrypted key to the disk - - // Allocate a buffer for filename - size_t fnlen = strlen(filename); - char *tmp_buf = (char *)malloc(fnlen + 1); - - if (!tmp_buf) { - PX4_ERR("out of memory"); - free(key); - return false; - } - - // Copy the original logfile name, and append 'k' to the filename - - memcpy(tmp_buf, filename, fnlen + 1); - tmp_buf[fnlen - 1] = 'k'; - tmp_buf[fnlen] = 0; - - int key_fd = ::open((const char *)tmp_buf, O_CREAT | O_WRONLY, PX4_O_MODE_666); - - // The file name is no longer needed, free it - free(tmp_buf); - tmp_buf = nullptr; + int key_fd = ::open((const char *)filename, O_CREAT | O_WRONLY | O_DIRECT | O_SYNC, PX4_O_MODE_666); if (key_fd < 0) { PX4_ERR("Can't open key file, errno: %d", errno); @@ -178,9 +157,9 @@ bool LogWriterFile::init_logfile_encryption(const char *filename) return false; } - // write the header to the key exchange file + // write the header to the combined key exchange & cipherdata file struct ulog_key_header_s keyfile_header = { - .magic = {'U', 'L', 'o', 'g', 'K', 'e', 'y'}, + .magic = {'U', 'L', 'o', 'g', 'E', 'n', 'c'}, .hdr_ver = 1, .timestamp = hrt_absolute_time(), .exchange_algorithm = CRYPTO_RSA_OAEP, @@ -651,7 +630,11 @@ size_t LogWriterFile::LogFileBuffer::get_read_ptr(void **ptr, bool *is_part) bool LogWriterFile::LogFileBuffer::start_log(const char *filename) { +#if defined(PX4_CRYPTO) + _fd = ::open(filename, O_APPEND | O_WRONLY, PX4_O_MODE_666); +#else _fd = ::open(filename, O_CREAT | O_WRONLY, PX4_O_MODE_666); +#endif if (_fd < 0) { PX4_ERR("Can't open log file %s, errno: %d", filename, errno); diff --git a/src/modules/logger/logger.cpp b/src/modules/logger/logger.cpp index 101120707577..3be6f92ae6ee 100644 --- a/src/modules/logger/logger.cpp +++ b/src/modules/logger/logger.cpp @@ -1317,7 +1317,7 @@ int Logger::get_log_file_name(LogType type, char *file_name, size_t file_name_si #if defined(PX4_CRYPTO) if (_param_sdlog_crypto_algorithm.get() != 0) { - crypto_suffix = "c"; + crypto_suffix = "e"; } #endif From 78a4d5bda5730416e017cc892bd199b1b8d437c7 Mon Sep 17 00:00:00 2001 From: Jari Nippula Date: Tue, 19 Nov 2024 10:42:26 +0200 Subject: [PATCH 2/2] Tools/decrypt_ulog.py: support for .ulge log files --- Tools/decrypt_ulog.py | 67 +++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/Tools/decrypt_ulog.py b/Tools/decrypt_ulog.py index f6d888c56b62..3015686b9749 100755 --- a/Tools/decrypt_ulog.py +++ b/Tools/decrypt_ulog.py @@ -1,62 +1,91 @@ #!/usr/bin/env python3 +import sys + +try: + from Crypto.Cipher import ChaCha20 +except ImportError as e: + print("Failed to import crypto: " + str(e)) + print("") + print("You may need to install it using:") + print(" pip3 install --user pycryptodome") + print("") + sys.exit(1) + from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_OAEP -from Crypto.Cipher import ChaCha20 from Crypto.Hash import SHA256 -import binascii +from pathlib import Path import argparse -#from pathlib import Path -import sys + if __name__ == "__main__": parser = argparse.ArgumentParser(description="""CLI tool to decrypt an ulog file\n""") - parser.add_argument("ulog_file", help=".ulog file", nargs='?', default=None) - parser.add_argument("ulog_key", help=".ulogk, encrypted key", nargs='?', default=None) + parser.add_argument("ulog_file", help=".ulge/.ulgc, encrypted log file", nargs='?', default=None) + parser.add_argument("ulog_key", help=".ulgk, legacy encrypted key (give empty string '' to ignore for .ulge)", nargs='?', default=None) parser.add_argument("rsa_key", help=".pem format key for decrypting the ulog key", nargs='?', default=None) args = parser.parse_args() - # Only generate a key pair, don't sign - if not args.ulog_file or not args.ulog_key or not args.rsa_key: - print('Need all arguments, the encrypted ulog file, the key and the key decryption key') - sys.exit(1); + # Check all arguments are given + if not args.rsa_key: + print('Need all arguments, the encrypted ulog file, key file (or empty string if not needed) and the key decryption key (.pem)') + sys.exit(1) # Read the private RSA key to decrypt the cahcha key with open(args.rsa_key, 'rb') as f: r = RSA.importKey(f.read(), passphrase='') - # Read the encrypted xchacha key and the nonce - with open(args.ulog_key, 'rb') as f: + if args.ulog_key == "": + key_data_filename = args.ulog_file + magic = "ULogEnc" + else: + key_data_filename = args.ulog_key + magic = "ULogKey" + + with open(key_data_filename, 'rb') as f: + # Read the encrypted xchacha key and the nonce ulog_key_header = f.read(22) # Parse the header try: # magic - if not ulog_key_header.startswith(bytearray("ULogKey".encode())): + if not ulog_key_header.startswith(bytearray(magic.encode())): + print("Incorrect header magic") raise Exception() # version if ulog_key_header[7] != 1: + print("Unsupported header version") raise Exception() # expected key exchange algorithm (RSA_OAEP) if ulog_key_header[16] != 4: + print("Unsupported key algorithm") raise Exception() - key_size = ulog_key_header[19] << 8 | ulog_key_header[18]; - nonce_size = ulog_key_header[21] << 8 | ulog_key_header[20]; + key_size = ulog_key_header[19] << 8 | ulog_key_header[18] + nonce_size = ulog_key_header[21] << 8 | ulog_key_header[20] ulog_key_cipher = f.read(key_size) nonce = f.read(nonce_size) except: - print("Keyfile format error") - sys.exit(1); + print("Keydata format error") + sys.exit(1) + + if magic == "ULogEnc": + data_offset = 22 + key_size + nonce_size + else: + data_offset = 0 # Decrypt the xchacha key cipher_rsa = PKCS1_OAEP.new(r,SHA256) ulog_key = cipher_rsa.decrypt(ulog_key_cipher) #print(binascii.hexlify(ulog_key)) - # Read and decrypt the .ulgc + # Read and decrypt the ulog data cipher = ChaCha20.new(key=ulog_key, nonce=nonce) + + outfilename = Path(args.ulog_file).stem + ".ulog" with open(args.ulog_file, 'rb') as f: - with open(args.ulog_file.rstrip(args.ulog_file[-1]), 'wb') as out: + if data_offset > 0: + f.seek(data_offset) + with open(outfilename, 'wb') as out: out.write(cipher.decrypt(f.read()))