39 #include <openssl/rand.h> 60 static std::string
encryptStringGpg(std::string& user, std::basic_string<unsigned char>
const& input) {
62 gpgme_error_t err = gpgme_new(&ctx);
64 throw BagException((boost::format(
"Failed to create a GPG context: %1%") % gpgme_strerror(err)).str());
67 gpgme_key_t keys[2] = {NULL, NULL};
69 if (user == std::string(
"*")) {
70 user = std::string(keys[0]->uids->name);
73 gpgme_data_t input_data;
74 err = gpgme_data_new_from_mem(&input_data, reinterpret_cast<const char*>(input.c_str()), input.length(), 1);
78 (boost::format(
"Failed to encrypt string: gpgme_data_new_from_mem returned %1%") % gpgme_strerror(err)).str());
80 gpgme_data_t output_data;
81 err = gpgme_data_new(&output_data);
83 gpgme_data_release(input_data);
86 (boost::format(
"Failed to encrypt string: gpgme_data_new returned %1%") % gpgme_strerror(err)).str());
88 err = gpgme_op_encrypt(ctx, keys, static_cast<gpgme_encrypt_flags_t>(GPGME_ENCRYPT_ALWAYS_TRUST), input_data, output_data);
90 gpgme_data_release(output_data);
91 gpgme_data_release(input_data);
93 throw BagException((boost::format(
"Failed to encrypt: %1%. Have you installed a public key %2%?") % gpgme_strerror(err) % user).str());
95 gpgme_key_release(keys[0]);
96 std::size_t output_length = gpgme_data_seek(output_data, 0, SEEK_END);
97 std::string output(output_length, 0);
98 gpgme_data_seek(output_data, 0, SEEK_SET);
99 ssize_t bytes_read = gpgme_data_read(output_data, &output[0], output_length);
101 gpgme_data_release(output_data);
102 gpgme_data_release(input_data);
104 if (-1 == bytes_read) {
118 static std::basic_string<unsigned char>
decryptStringGpg(std::string
const& user, std::string
const& input) {
120 gpgme_error_t err = gpgme_new(&ctx);
122 throw BagException((boost::format(
"Failed to create a GPG context: %1%") % gpgme_strerror(err)).str());
125 gpgme_data_t input_data;
126 err = gpgme_data_new_from_mem(&input_data, input.c_str(), input.length(), 1);
130 (boost::format(
"Failed to decrypt bag: gpgme_data_new_from_mem returned %1%") % gpgme_strerror(err)).str());
132 gpgme_data_t output_data;
133 err = gpgme_data_new(&output_data);
135 gpgme_data_release(input_data);
138 (boost::format(
"Failed to decrypt bag: gpgme_data_new returned %1%") % gpgme_strerror(err)).str());
140 err = gpgme_op_decrypt(ctx, input_data, output_data);
142 gpgme_data_release(output_data);
143 gpgme_data_release(input_data);
145 throw BagException((boost::format(
"Failed to decrypt bag: %1%. Have you installed a private key %2%?") % gpgme_strerror(err) % user).str());
147 std::size_t output_length = gpgme_data_seek(output_data, 0, SEEK_END);
148 if (output_length != AES_BLOCK_SIZE) {
149 gpgme_data_release(output_data);
150 gpgme_data_release(input_data);
152 throw BagException(
"Decrypted string length mismatches");
154 std::basic_string<unsigned char> output(output_length, 0);
155 gpgme_data_seek(output_data, 0, SEEK_SET);
156 ssize_t bytes_read = gpgme_data_read(output_data, reinterpret_cast<char*>(&output[0]), output_length);
158 gpgme_data_release(output_data);
159 gpgme_data_release(input_data);
161 if (-1 == bytes_read) {
162 throw BagException(
"Failed to read decrypted symmetric key");
168 ros::M_string::const_iterator it = header_fields.find(field_name);
169 if (it == header_fields.end()) {
170 return std::string();
192 (boost::format(
"Encryption user has already been set to %s") %
gpg_key_user_.c_str()).str());
198 std::basic_string<unsigned char> compressed_chunk(chunk_size, 0);
199 file.
seek(chunk_data_pos);
200 file.
read((
char*) &compressed_chunk[0], chunk_size);
202 std::size_t pad_size = AES_BLOCK_SIZE - chunk_size % AES_BLOCK_SIZE;
203 compressed_chunk.resize(compressed_chunk.length() + pad_size, pad_size);
205 std::basic_string<unsigned char> encrypted_chunk(compressed_chunk.length(), 0);
206 std::basic_string<unsigned char> iv(AES_BLOCK_SIZE, 0);
207 if (!RAND_bytes(&iv[0], AES_BLOCK_SIZE)) {
208 throw BagException(
"Failed to build initialization vector");
210 file.
seek(chunk_data_pos);
211 file.
write((
char*) &iv[0], AES_BLOCK_SIZE);
212 AES_cbc_encrypt(&compressed_chunk[0], &encrypted_chunk[0], encrypted_chunk.length(), &
aes_encrypt_key_, &iv[0], AES_ENCRYPT);
214 file.
write((
char*) &encrypted_chunk[0], encrypted_chunk.length());
215 file.
truncate(chunk_data_pos + AES_BLOCK_SIZE + encrypted_chunk.length());
216 return AES_BLOCK_SIZE + encrypted_chunk.length();
228 std::basic_string<unsigned char> iv(AES_BLOCK_SIZE, 0);
229 file.
read((
char*) &iv[0], AES_BLOCK_SIZE);
230 std::basic_string<unsigned char> encrypted_chunk(chunk_header.
compressed_size - AES_BLOCK_SIZE, 0);
234 AES_cbc_encrypt(&encrypted_chunk[0], (
unsigned char*) decrypted_chunk.
getData(), chunk_header.
compressed_size - AES_BLOCK_SIZE,
236 if (decrypted_chunk.
getSize() == 0) {
266 std::size_t pad_size = AES_BLOCK_SIZE - header_len % AES_BLOCK_SIZE;
267 uint32_t encrypted_buffer_size = header_len + pad_size;
268 std::basic_string<unsigned char> header_buffer_with_pad(encrypted_buffer_size, pad_size);
269 memcpy(&header_buffer_with_pad[0], header_buffer.get(), header_len);
271 std::basic_string<unsigned char> encrypted_buffer(encrypted_buffer_size, 0);
272 std::basic_string<unsigned char> iv(AES_BLOCK_SIZE, 0);
273 if (!RAND_bytes(&iv[0], AES_BLOCK_SIZE)) {
274 throw BagException(
"Failed to build initialization vector");
276 encrypted_buffer_size += AES_BLOCK_SIZE;
277 file.
write((
char*) &encrypted_buffer_size, 4);
278 encrypted_buffer_size -= AES_BLOCK_SIZE;
279 file.
write((
char*) &iv[0], AES_BLOCK_SIZE);
280 AES_cbc_encrypt(&header_buffer_with_pad[0], &encrypted_buffer[0], encrypted_buffer_size, &
aes_encrypt_key_, &iv[0], AES_ENCRYPT);
282 file.
write((
char*) &encrypted_buffer[0], encrypted_buffer_size);
287 uint32_t encrypted_header_len;
288 file.
read((
char*) &encrypted_header_len, 4);
289 if (encrypted_header_len % AES_BLOCK_SIZE != 0) {
290 throw BagFormatException((boost::format(
"Error in encrypted header length: %d") % encrypted_header_len).str());
292 if (encrypted_header_len < AES_BLOCK_SIZE) {
293 throw BagFormatException((boost::format(
"No initialization vector in encrypted header: %d") % encrypted_header_len).str());
296 std::basic_string<unsigned char> iv(AES_BLOCK_SIZE, 0);
297 file.
read((
char*) &iv[0], AES_BLOCK_SIZE);
298 encrypted_header_len -= AES_BLOCK_SIZE;
299 std::basic_string<unsigned char> encrypted_header(encrypted_header_len, 0);
300 file.
read((
char*) &encrypted_header[0], encrypted_header_len);
302 header_buffer.
setSize(encrypted_header_len);
303 AES_cbc_encrypt(&encrypted_header[0], (
unsigned char*) header_buffer.
getData(), encrypted_header_len, &
aes_decrypt_key_, &iv[0], AES_DECRYPT);
304 if (header_buffer.
getSize() == 0) {
309 std::string error_msg;
void read(void *ptr, size_t size)
read size bytes from the file into ptr
BagMode getMode() const
Get the mode the bag is in.
ChunkedFile reads and writes files which contain interleaved chunks of compressed and uncompressed da...
void write(std::string const &s)
void initialize(Bag const &bag, std::string const &gpg_key_user)
Initialize encryptor.
Base class for rosbag exceptions.
bool truncate(uint64_t length)
void seek(uint64_t offset, int origin=std::ios_base::beg)
seek to given offset from origin
static const std::string ENCRYPTOR_FIELD_NAME
static std::string readHeaderField(ros::M_string const &header_fields, std::string const &field_name)
static const std::string GPG_USER_FIELD_NAME
std::basic_string< unsigned char > symmetric_key_
std::map< std::string, std::string > M_string
static std::basic_string< unsigned char > decryptStringGpg(std::string const &user, std::string const &input)
Decrypt string using GPGME.
void initGpgme()
Initialize GPGME library.
bool readEncryptedHeader(boost::function< bool(ros::Header &)>, ros::Header &header, Buffer &header_buffer, ChunkedFile &)
Read encrypted header from bag file.
std::string gpg_key_user_
void decryptChunk(ChunkHeader const &chunk_header, Buffer &decrypted_chunk, ChunkedFile &file) const
Decrypt chunk.
uint32_t encryptChunk(const uint32_t chunk_size, const uint64_t chunk_data_pos, ChunkedFile &file)
Encrypt chunk.
std::string encrypted_symmetric_key_
static const std::string ENCRYPTED_KEY_FIELD_NAME
static std::string encryptStringGpg(std::string &user, std::basic_string< unsigned char > const &input)
Encrypt string using GPGME.
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
void writeEncryptedHeader(boost::function< void(ros::M_string const &)>, ros::M_string const &header_fields, ChunkedFile &)
Write encrypted header to bag file.
void addFieldsToFileHeader(ros::M_string &header_fields) const
Add encryptor information to bag file header.
void setSize(uint32_t size)
void getGpgKey(gpgme_ctx_t &ctx, std::string const &user, gpgme_key_t &key)
Get GPG key.
void readFieldsFromFileHeader(ros::M_string const &header_fields)
Read encryptor information from bag file header.