-
Notifications
You must be signed in to change notification settings - Fork 914
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Bag encryption/decryption. #1206
Changes from 1 commit
a2c0545
3b583b4
e969e8f
51920c9
c8bebef
abec8bc
a01abe9
1557fe6
ac8ebd9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
/********************************************************************* | ||
* Software License Agreement (BSD License) | ||
* | ||
* Copyright (c) 2017, Open Source Robotics Foundation | ||
* All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions | ||
* are met: | ||
* | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above | ||
* copyright notice, this list of conditions and the following | ||
* disclaimer in the documentation and/or other materials provided | ||
* with the distribution. | ||
* * Neither the name of Willow Garage, Inc. nor the names of its | ||
* contributors may be used to endorse or promote products derived | ||
* from this software without specific prior written permission. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | ||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
* POSSIBILITY OF SUCH DAMAGE. | ||
*********************************************************************/ | ||
|
||
#include <iostream> | ||
|
||
#include <boost/scoped_ptr.hpp> | ||
#include <boost/program_options.hpp> | ||
#include <boost/progress.hpp> | ||
#include <boost/regex.hpp> | ||
|
||
#include <ros/ros.h> | ||
|
||
#include "rosbag/bag.h" | ||
#include "rosbag/view.h" | ||
|
||
namespace po = boost::program_options; | ||
|
||
struct EncryptorOptions | ||
{ | ||
EncryptorOptions() : quiet(false), compression(rosbag::compression::Uncompressed) { } | ||
|
||
void buildOutbagName(); | ||
|
||
bool quiet; | ||
std::string plugin; | ||
std::string param; | ||
rosbag::CompressionType compression; | ||
std::string inbag; | ||
std::string outbag; | ||
}; | ||
|
||
void EncryptorOptions::buildOutbagName() { | ||
if (!outbag.empty()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use a consistent style for positioning curly braces. In ROS 1 they are generally on a separate line. But most important is consistency. Across the code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to make the style consistent with sibling files, "play.cpp" and "record.cpp", though the style in those two files are problematic. Let me use consistent separate-line braces in |
||
return; | ||
} | ||
if (inbag.empty()) { | ||
throw ros::Exception("Input bag is not specified."); | ||
} | ||
std::string::size_type pos = inbag.find_last_of('.'); | ||
if (pos == std::string::npos) { | ||
throw ros::Exception("Input bag name has no extension."); | ||
} | ||
outbag = inbag.substr(0, pos) + std::string(".out") + inbag.substr(pos); | ||
} | ||
|
||
//! Parse the command-line arguments for encrypt options | ||
EncryptorOptions parseOptions(int argc, char** argv) { | ||
EncryptorOptions opts; | ||
|
||
po::options_description desc("Allowed options"); | ||
|
||
desc.add_options() | ||
("help,h", "produce help message") | ||
("quiet,q", "suppress console output") | ||
("plugin,p", po::value<std::string>()->default_value("rosbag/AesCbcEncryptor"), "encryptor name") | ||
("param,r", po::value<std::string>()->default_value("*"), "encryptor parameter") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please avoid such long blocks of spaces for aligning arguments. Same below. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed. |
||
("bz2,j", "use BZ2 compression") | ||
("lz4", "use lz4 compression") | ||
("inbag", po::value<std::string>(), "bag file to encrypt") | ||
("outbag,o", po::value<std::string>(), "bag file encrypted") | ||
; | ||
|
||
po::positional_options_description p; | ||
p.add("inbag", -1); | ||
|
||
po::variables_map vm; | ||
|
||
try | ||
{ | ||
po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm); | ||
} catch (boost::program_options::invalid_command_line_syntax& e) | ||
{ | ||
throw ros::Exception(e.what()); | ||
} catch (boost::program_options::unknown_option& e) | ||
{ | ||
throw ros::Exception(e.what()); | ||
} | ||
|
||
if (vm.count("help")) { | ||
std::cout << desc << std::endl; | ||
exit(0); | ||
} | ||
|
||
if (vm.count("quiet")) | ||
opts.quiet = true; | ||
if (vm.count("plugin")) | ||
opts.plugin = vm["plugin"].as<std::string>(); | ||
if (vm.count("param")) | ||
opts.param = vm["param"].as<std::string>(); | ||
if (vm.count("bz2")) | ||
opts.compression = rosbag::compression::BZ2; | ||
if (vm.count("lz4")) | ||
opts.compression = rosbag::compression::LZ4; | ||
if (vm.count("inbag")) | ||
{ | ||
opts.inbag = vm["inbag"].as<std::string>(); | ||
} else { | ||
throw ros::Exception("You must specify bag to encrypt."); | ||
} | ||
if (vm.count("outbag")) | ||
opts.outbag = vm["outbag"].as<std::string>(); | ||
opts.buildOutbagName(); | ||
|
||
return opts; | ||
} | ||
|
||
std::string getStringCompressionType(rosbag::CompressionType compression) { | ||
switch(compression) { | ||
case rosbag::compression::Uncompressed: return "none"; | ||
case rosbag::compression::BZ2: return "bz2"; | ||
case rosbag::compression::LZ4: return "lz4"; | ||
default: return "Unknown"; | ||
} | ||
} | ||
|
||
int encrypt(EncryptorOptions const& options) { | ||
if (!options.quiet) { | ||
std::cout << "Output bag: " << options.outbag << "\n"; | ||
std::cout << "Encryption: " << options.plugin << ":" << options.param << "\n"; | ||
std::cout << "Compression: " << getStringCompressionType(options.compression) << "\n"; | ||
} | ||
rosbag::Bag inbag(options.inbag, rosbag::bagmode::Read); | ||
rosbag::Bag outbag(options.outbag, rosbag::bagmode::Write); | ||
// Compression type is per chunk, and cannot be retained. | ||
// If chunk-by-chunk encryption is implemented, compression type could be honored. | ||
outbag.setEncryptorPlugin(options.plugin, options.param); | ||
outbag.setCompression(options.compression); | ||
rosbag::View view(inbag); | ||
boost::scoped_ptr<boost::progress_display> progress; | ||
if (!options.quiet) | ||
progress.reset(new boost::progress_display(view.size(), std::cout, "Progress:\n ", " ", " ")); | ||
for (rosbag::View::const_iterator it = view.begin(); it != view.end(); ++it) { | ||
outbag.write(it->getTopic(), it->getTime(), *it, it->getConnectionHeader()); | ||
if (progress) | ||
++(*progress); | ||
} | ||
outbag.close(); | ||
inbag.close(); | ||
return 0; | ||
} | ||
|
||
int main(int argc, char** argv) { | ||
// Parse the command-line options | ||
EncryptorOptions opts; | ||
try { | ||
opts = parseOptions(argc, argv); | ||
} | ||
catch (ros::Exception const& ex) { | ||
ROS_ERROR("Error reading options: %s", ex.what()); | ||
return 1; | ||
} | ||
catch(boost::regex_error const& ex) { | ||
ROS_ERROR("Error reading options: %s\n", ex.what()); | ||
return 1; | ||
} | ||
|
||
return encrypt(opts); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ if(NOT WIN32) | |
endif() | ||
|
||
find_package(console_bridge REQUIRED) | ||
find_package(catkin REQUIRED COMPONENTS cpp_common roscpp_serialization roscpp_traits rostime roslz4) | ||
find_package(catkin REQUIRED COMPONENTS cpp_common pluginlib roscpp_serialization roscpp_traits rostime roslz4) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The dependency on In general a dependency on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm in favour of that change, as I'd like to use plugins (or at least plugin discovery) in tools like rostopic. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That would be "challenging" since There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I think I was thinking that the python plugin discovery stuff that rqt uses was part of In any case, pluginlib is itself a lightweight dependency, isn't it? Is the pocoo stuff it depends on heavy? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not heavy: mostly The "problem" is that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Declared build/run dependency to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The repo-level circular dependency doesn't impact our builds, so we'd be happy to proceed with this path if the proposed change is otherwise acceptable, and plan to assist with splitting out Alternatively, I could look at breaking If not, we can retain the idea of encryption being a pluggable capability while not actually allowing external encryption modules to be plugged in (eg, Let us know how you'd like to proceed here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I will add some higher level comment to the PR. But the general feature sounds like a good idea to me.
I don't think we want the repository level circular dependency. So splitting out
It might be but you might want to check with the |
||
find_package(Boost REQUIRED COMPONENTS date_time filesystem program_options regex) | ||
find_package(BZip2 REQUIRED) | ||
|
||
|
@@ -24,21 +24,40 @@ add_definitions(-D_FILE_OFFSET_BITS=64) | |
include_directories(include ${catkin_INCLUDE_DIRS} ${console_bridge_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${BZIP2_INCLUDE_DIR}) | ||
add_definitions(${BZIP2_DEFINITIONS}) | ||
|
||
add_library(rosbag_storage | ||
src/bag.cpp | ||
src/bag_player.cpp | ||
src/buffer.cpp | ||
src/bz2_stream.cpp | ||
src/lz4_stream.cpp | ||
src/chunked_file.cpp | ||
src/message_instance.cpp | ||
src/query.cpp | ||
src/stream.cpp | ||
src/view.cpp | ||
src/uncompressed_stream.cpp | ||
) | ||
|
||
target_link_libraries(rosbag_storage ${catkin_LIBRARIES} ${Boost_LIBRARIES} ${BZIP2_LIBRARIES} ${console_bridge_LIBRARIES}) | ||
if(WIN32) | ||
add_library(rosbag_storage | ||
src/bag.cpp | ||
src/bag_player.cpp | ||
src/buffer.cpp | ||
src/bz2_stream.cpp | ||
src/lz4_stream.cpp | ||
src/chunked_file.cpp | ||
src/encryptor.cpp | ||
src/message_instance.cpp | ||
src/query.cpp | ||
src/stream.cpp | ||
src/view.cpp | ||
src/uncompressed_stream.cpp | ||
) | ||
target_link_libraries(rosbag_storage ${catkin_LIBRARIES} ${Boost_LIBRARIES} ${BZIP2_LIBRARIES} ${console_bridge_LIBRARIES}) | ||
else() | ||
add_library(rosbag_storage | ||
src/aes_encryptor.cpp | ||
src/bag.cpp | ||
src/bag_player.cpp | ||
src/buffer.cpp | ||
src/bz2_stream.cpp | ||
src/lz4_stream.cpp | ||
src/chunked_file.cpp | ||
src/encryptor.cpp | ||
src/message_instance.cpp | ||
src/query.cpp | ||
src/stream.cpp | ||
src/view.cpp | ||
src/uncompressed_stream.cpp | ||
) | ||
target_link_libraries(rosbag_storage ${catkin_LIBRARIES} ${Boost_LIBRARIES} ${BZIP2_LIBRARIES} ${console_bridge_LIBRARIES} crypto gpgme) | ||
endif() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please do not duplicate large chunks of code like this. Instead create a variable for the optional files, fill that variable based on the platform, and then use it as one argument to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed. Thank you. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The variables should be set as empty outside of the conditional. Otherwise newer CMake versions will report a warning for using an uninitialized variable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed. Thank you. |
||
|
||
install(TARGETS rosbag_storage | ||
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} | ||
|
@@ -50,3 +69,17 @@ install(DIRECTORY include/ | |
DESTINATION ${CATKIN_GLOBAL_INCLUDE_DESTINATION} | ||
FILES_MATCHING PATTERN "*.h" | ||
) | ||
|
||
if(NOT WIN32) | ||
install(FILES encryptor_plugins.xml | ||
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} | ||
) | ||
|
||
if(CATKIN_ENABLE_TESTING) | ||
find_package(rostest) | ||
|
||
catkin_add_gtest(test_aes_encryptor test/test_aes_encryptor.cpp | ||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/test) | ||
target_link_libraries(test_aes_encryptor rosbag_storage ${catkin_LIBRARIES} ${Boost_LIBRARIES} crypto gpgme) | ||
endif() | ||
endif() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put the generic part outside of this conditional block and only create a conditional block for
encrypt
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed.