zindosteg 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +92 -0
- data/Rakefile +11 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ext/zindosteg/aes.cpp +73 -0
- data/ext/zindosteg/aes.h +36 -0
- data/ext/zindosteg/bmp.cpp +100 -0
- data/ext/zindosteg/bmp.h +39 -0
- data/ext/zindosteg/device.cpp +244 -0
- data/ext/zindosteg/device.h +69 -0
- data/ext/zindosteg/extconf.rb +10 -0
- data/ext/zindosteg/file_utils.h +36 -0
- data/ext/zindosteg/hmac.h +82 -0
- data/ext/zindosteg/jpeg.cpp +111 -0
- data/ext/zindosteg/jpeg.h +39 -0
- data/ext/zindosteg/jpeg_helpers.cpp +149 -0
- data/ext/zindosteg/jpeg_helpers.h +54 -0
- data/ext/zindosteg/key_generator.cpp +36 -0
- data/ext/zindosteg/key_generator.h +23 -0
- data/ext/zindosteg/loader.cpp +72 -0
- data/ext/zindosteg/permutator.cpp +129 -0
- data/ext/zindosteg/permutator.h +39 -0
- data/ext/zindosteg/png_provider.cpp +304 -0
- data/ext/zindosteg/png_provider.h +87 -0
- data/ext/zindosteg/provider.h +40 -0
- data/ext/zindosteg/steg_defs.h +24 -0
- data/ext/zindosteg/steg_endian.h +168 -0
- data/ext/zindosteg/zindosteg.cpp +704 -0
- data/lib/zindosteg/version.rb +3 -0
- data/lib/zindosteg.rb +18 -0
- data/zindosteg.gemspec +28 -0
- metadata +108 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <ios>
|
4
|
+
#include "provider.h"
|
5
|
+
#include "permutator.h"
|
6
|
+
#include <stdexcept>
|
7
|
+
#include "steg_defs.h"
|
8
|
+
|
9
|
+
namespace zindorsky {
|
10
|
+
namespace steganography {
|
11
|
+
|
12
|
+
class payload_extraction_error : public std::runtime_error {
|
13
|
+
public:
|
14
|
+
payload_extraction_error() : std::runtime_error{"invalid payload data"} {}
|
15
|
+
};
|
16
|
+
|
17
|
+
class device_t {
|
18
|
+
public:
|
19
|
+
using char_type = char;
|
20
|
+
|
21
|
+
//If "open_existing_payload" is true, a check will be made for a valid payload length (and possibly other parameters).
|
22
|
+
//If the check fails then if throw_on_open_existing_fail is true a payload_extraction_error exception will be thrown. If throw_on_open_existing_fail is false, the intitial size will be set to zero.
|
23
|
+
//If "open_existing_payload" is false, no check will be made and a new length will be written when the device is closed.
|
24
|
+
device_t(filesystem::path const& carrier_file, std::string const& password, bool open_existing_payload, bool throw_on_open_existing_fail = true);
|
25
|
+
//Takes ownership of provider:
|
26
|
+
device_t(std::unique_ptr<provider_t> provider, std::string const& password, bool open_existing_payload, bool throw_on_open_existing_fail = true);
|
27
|
+
|
28
|
+
//Non-copyable
|
29
|
+
device_t(device_t const&) = delete;
|
30
|
+
device_t & operator = (device_t const&) = delete;
|
31
|
+
//Movable
|
32
|
+
device_t( device_t && ) = default;
|
33
|
+
device_t & operator = (device_t &&) = default;
|
34
|
+
|
35
|
+
// I/O streams seekable, closable interface:
|
36
|
+
std::streamsize read(char * s, std::streamsize n);
|
37
|
+
std::streamsize write(char const* s, std::streamsize n);
|
38
|
+
std::streampos seek(std::streamoff off, std::ios::seekdir way);
|
39
|
+
void close();
|
40
|
+
|
41
|
+
//Not part of the I/O streams interface, but sometimes handy:
|
42
|
+
std::streamsize size() const { return payload_sz_; }
|
43
|
+
std::streamsize capacity() const { return max_sz_; }
|
44
|
+
std::streamsize truncate(); //sets eof to current position
|
45
|
+
void flush();
|
46
|
+
|
47
|
+
void write_to_file(filesystem::path const& outfile);
|
48
|
+
byte_vector write_to_memory();
|
49
|
+
|
50
|
+
//Returns salt derived from the carrier.
|
51
|
+
byte_vector salt_for_encryption() const;
|
52
|
+
|
53
|
+
private:
|
54
|
+
std::unique_ptr<provider_t> provider_;
|
55
|
+
filesystem::path carrier_file_;
|
56
|
+
permutator::context shuffler_;
|
57
|
+
std::streamsize max_sz_, payload_sz_;
|
58
|
+
std::streampos pos_;
|
59
|
+
bool dirty_;
|
60
|
+
|
61
|
+
byte get_byte(std::streampos const& pos, provider_t::index_t * lo_start = 0, provider_t::index_t * hi_start = 0) const;
|
62
|
+
void put_byte(byte b, std::streampos const& pos);
|
63
|
+
|
64
|
+
std::streamsize read_payload_length(bool throw_on_fail = true) const;
|
65
|
+
void write_payload_length();
|
66
|
+
|
67
|
+
};
|
68
|
+
|
69
|
+
}} //namespace zindorsky::steganography
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require "mkmf-rice"
|
2
|
+
|
3
|
+
sources = %w{aes key_generator permutator bmp jpeg_helpers jpeg png_provider loader device}
|
4
|
+
$srcs = sources.map { |file| "#{file}.cpp" }
|
5
|
+
$objs = sources.map { |file| "#{file}.o" } << "zindosteg.o"
|
6
|
+
$CPPFLAGS << " -std=c++17 -O2"
|
7
|
+
$LDFLAGS << " -lcrypto -ljpeg -lpng"
|
8
|
+
$LDFLAGS << " -lstdc++fs" if have_macro("EXPERIMENTAL_FILESYSTEM", "steg_defs.h")
|
9
|
+
|
10
|
+
create_makefile("zindosteg/zindosteg")
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <fstream>
|
4
|
+
#include "steg_defs.h"
|
5
|
+
#include <vector>
|
6
|
+
|
7
|
+
namespace zindorsky {
|
8
|
+
namespace steganography {
|
9
|
+
namespace utils {
|
10
|
+
|
11
|
+
inline byte_vector load_from_file( filesystem::path const& filename )
|
12
|
+
{
|
13
|
+
std::ifstream f(filename.c_str(), std::ios::binary | std::ios_base::in);
|
14
|
+
std::streampos sz = f.seekg(0, std::ios::end).tellg();
|
15
|
+
f.seekg(0, std::ios::beg);
|
16
|
+
|
17
|
+
byte_vector buffer(static_cast<size_t>(sz));
|
18
|
+
char *d = reinterpret_cast<char*>(buffer.data());
|
19
|
+
size_t remaining = buffer.size();
|
20
|
+
while(remaining > 0) {
|
21
|
+
std::streamsize r = f.read(d, remaining).gcount();
|
22
|
+
if (r < 0) { break; }
|
23
|
+
d += static_cast<size_t>(r);
|
24
|
+
remaining -= static_cast<size_t>(r);
|
25
|
+
}
|
26
|
+
return buffer;
|
27
|
+
}
|
28
|
+
|
29
|
+
inline void save_to_file( filesystem::path const& filename, byte_vector const& data )
|
30
|
+
{
|
31
|
+
std::ofstream f(filename.c_str(), std::ios::binary | std::ios::out);
|
32
|
+
f.write(reinterpret_cast<char const*>(data.data()), data.size());
|
33
|
+
}
|
34
|
+
|
35
|
+
}}} //namespace zinodrsky::steganography::utils
|
36
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#include <openssl/hmac.h>
|
2
|
+
|
3
|
+
namespace zindorsky {
|
4
|
+
namespace crypto {
|
5
|
+
|
6
|
+
//RAII wrapper for OpenSSL HMAC API
|
7
|
+
class hmac {
|
8
|
+
public:
|
9
|
+
enum { digest_sz = 32 };
|
10
|
+
|
11
|
+
hmac(void const* key, int length) noexcept
|
12
|
+
: hmac_{HMAC_CTX_new()}
|
13
|
+
{
|
14
|
+
HMAC_Init_ex(hmac_, key, length, EVP_sha256(), nullptr);
|
15
|
+
}
|
16
|
+
|
17
|
+
hmac( hmac const& rhs ) noexcept
|
18
|
+
: hmac_{HMAC_CTX_new()}
|
19
|
+
{
|
20
|
+
HMAC_CTX_copy(hmac_, const_cast<hmac&>(rhs).hmac_);
|
21
|
+
}
|
22
|
+
|
23
|
+
hmac & operator = (hmac const& rhs) noexcept
|
24
|
+
{
|
25
|
+
if(this != &rhs) {
|
26
|
+
HMAC_CTX_copy(hmac_, const_cast<hmac&>(rhs).hmac_);
|
27
|
+
}
|
28
|
+
return *this;
|
29
|
+
}
|
30
|
+
|
31
|
+
hmac( hmac && rhs ) noexcept
|
32
|
+
{
|
33
|
+
hmac_ = rhs.hmac_;
|
34
|
+
rhs.hmac_ = nullptr;
|
35
|
+
}
|
36
|
+
|
37
|
+
hmac & operator = (hmac && rhs) noexcept
|
38
|
+
{
|
39
|
+
if(this != &rhs) {
|
40
|
+
if(hmac_) {
|
41
|
+
HMAC_CTX_free(hmac_);
|
42
|
+
}
|
43
|
+
hmac_ = rhs.hmac_;
|
44
|
+
rhs.hmac_ = nullptr;
|
45
|
+
}
|
46
|
+
return *this;
|
47
|
+
}
|
48
|
+
|
49
|
+
~hmac()
|
50
|
+
{
|
51
|
+
if(hmac_) {
|
52
|
+
HMAC_CTX_free(hmac_);
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
//HMAC operations:
|
57
|
+
void reset()
|
58
|
+
{
|
59
|
+
HMAC_Init_ex(hmac_, nullptr, 0, nullptr, nullptr);
|
60
|
+
}
|
61
|
+
|
62
|
+
void update( void const* data, std::size_t length )
|
63
|
+
{
|
64
|
+
HMAC_Update(hmac_, static_cast<byte const*>(data), length);
|
65
|
+
}
|
66
|
+
|
67
|
+
void final( byte * digest )
|
68
|
+
{
|
69
|
+
HMAC_Final(hmac_, digest, nullptr);
|
70
|
+
}
|
71
|
+
|
72
|
+
private:
|
73
|
+
HMAC_CTX* hmac_;
|
74
|
+
};
|
75
|
+
|
76
|
+
class hmac_verification_failure : public std::runtime_error {
|
77
|
+
public:
|
78
|
+
hmac_verification_failure() : std::runtime_error("HMAC verification failure.") {}
|
79
|
+
};
|
80
|
+
|
81
|
+
}} //namespace
|
82
|
+
|
@@ -0,0 +1,111 @@
|
|
1
|
+
#include "jpeg.h"
|
2
|
+
#include "steg_endian.h"
|
3
|
+
#include "file_utils.h"
|
4
|
+
#include <stdexcept>
|
5
|
+
|
6
|
+
namespace zindorsky {
|
7
|
+
namespace steganography {
|
8
|
+
|
9
|
+
jpeg_provider::jpeg_provider( filesystem::path const& filename )
|
10
|
+
: jpeg_provider( utils::load_from_file(filename) )
|
11
|
+
{
|
12
|
+
}
|
13
|
+
|
14
|
+
jpeg_provider::jpeg_provider(byte_vector const& data)
|
15
|
+
: jpeg_provider(data.data(), data.size())
|
16
|
+
{
|
17
|
+
}
|
18
|
+
|
19
|
+
jpeg_provider::jpeg_provider(byte const* data, size_t size)
|
20
|
+
: jpeg_provider( byte_vector(data, data+size) )
|
21
|
+
{
|
22
|
+
}
|
23
|
+
|
24
|
+
jpeg_provider::jpeg_provider(byte_vector && data)
|
25
|
+
: jinfo_(std::move(data))
|
26
|
+
, component_count_(0)
|
27
|
+
, sz_(0)
|
28
|
+
{
|
29
|
+
component_count_ = static_cast<std::size_t>( jinfo_.object()->num_components );
|
30
|
+
wib_.resize(component_count_);
|
31
|
+
hib_.resize(component_count_);
|
32
|
+
comp_sz_.resize(component_count_);
|
33
|
+
for(std::size_t i=0; i<component_count_; ++i) {
|
34
|
+
wib_[i] = static_cast<std::size_t>( jinfo_.object()->comp_info[i].width_in_blocks );
|
35
|
+
hib_[i] = static_cast<std::size_t>( jinfo_.object()->comp_info[i].height_in_blocks );
|
36
|
+
comp_sz_[i] = wib_[i]*hib_[i]*DCTSIZE2;
|
37
|
+
sz_ += comp_sz_[i];
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
provider_t::index_t jpeg_provider::size() const
|
42
|
+
{
|
43
|
+
return sz_;
|
44
|
+
}
|
45
|
+
|
46
|
+
#if LITTLE_ENDIAN
|
47
|
+
# define INT16_LSB 0
|
48
|
+
#else
|
49
|
+
# define INT16_LSB 1
|
50
|
+
#endif
|
51
|
+
|
52
|
+
byte & jpeg_provider::access_indexed_data( provider_t::index_t index )
|
53
|
+
{
|
54
|
+
std::size_t comp, row, col, block;
|
55
|
+
index_to_coordinates(index,comp,row,col,block);
|
56
|
+
JBLOCKARRAY rowblock = (*jinfo_.object()->mem->access_virt_barray)( (j_common_ptr)jinfo_.object(), jinfo_.coefficients()[comp], (JDIMENSION)row, 1, TRUE);
|
57
|
+
return reinterpret_cast<byte*>( &rowblock[0][col][block] )[ INT16_LSB ];
|
58
|
+
}
|
59
|
+
|
60
|
+
byte const& jpeg_provider::access_indexed_data( provider_t::index_t index ) const
|
61
|
+
{
|
62
|
+
std::size_t comp, row, col, block;
|
63
|
+
index_to_coordinates(index,comp,row,col,block);
|
64
|
+
JBLOCKARRAY rowblock = (*jinfo_.object()->mem->access_virt_barray)( (j_common_ptr)jinfo_.object(), jinfo_.coefficients()[comp], (JDIMENSION)row, 1, FALSE);
|
65
|
+
return reinterpret_cast<byte const*>( &rowblock[0][col][block] )[ INT16_LSB ];
|
66
|
+
}
|
67
|
+
|
68
|
+
byte_vector jpeg_provider::commit_to_memory()
|
69
|
+
{
|
70
|
+
return jinfo_.save_to_memory();
|
71
|
+
}
|
72
|
+
|
73
|
+
void jpeg_provider::commit_to_file(filesystem::path const& file)
|
74
|
+
{
|
75
|
+
jinfo_.save_to_file(file);
|
76
|
+
}
|
77
|
+
|
78
|
+
byte_vector jpeg_provider::salt() const
|
79
|
+
{
|
80
|
+
byte salt[8] = {0};
|
81
|
+
std::size_t salt_index=0;
|
82
|
+
|
83
|
+
for(std::size_t i=0; i<component_count_; ++i) {
|
84
|
+
for(std::size_t j=0; j<hib_[i]; ++j) {
|
85
|
+
JBLOCKARRAY rowblock = (*jinfo_.object()->mem->access_virt_barray)( (j_common_ptr)jinfo_.object(), jinfo_.coefficients()[i], (JDIMENSION)j, 1, FALSE);
|
86
|
+
salt[ salt_index++ % sizeof(salt) ] += static_cast<byte>( rowblock[0][j%wib_[i]][j%DCTSIZE2]>>1 );
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
return byte_vector(salt, salt+sizeof(salt));
|
91
|
+
}
|
92
|
+
|
93
|
+
void jpeg_provider::index_to_coordinates(provider_t::index_t index, std::size_t & comp, std::size_t & row, std::size_t & col, std::size_t & block) const
|
94
|
+
{
|
95
|
+
if(index >= sz_) { throw std::out_of_range("index out of range"); }
|
96
|
+
for(comp=0; comp<component_count_; ++comp) {
|
97
|
+
if( index < comp_sz_[comp] ) {
|
98
|
+
break;
|
99
|
+
}
|
100
|
+
index -= comp_sz_[comp];
|
101
|
+
}
|
102
|
+
if(comp==component_count_) { throw std::logic_error("computed sizes incorrect"); }
|
103
|
+
|
104
|
+
std::size_t rowsz = wib_[comp] * DCTSIZE2;
|
105
|
+
row = index / rowsz;
|
106
|
+
col = (index % rowsz) / DCTSIZE2;
|
107
|
+
block = index % DCTSIZE2;
|
108
|
+
}
|
109
|
+
|
110
|
+
}} //namespace zindorsky::steganography
|
111
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include "provider.h"
|
4
|
+
#include <exception>
|
5
|
+
#include "jpeg_helpers.h"
|
6
|
+
|
7
|
+
namespace zindorsky {
|
8
|
+
namespace steganography {
|
9
|
+
|
10
|
+
class jpeg_provider : public provider_t {
|
11
|
+
public:
|
12
|
+
explicit jpeg_provider( filesystem::path const& filename );
|
13
|
+
explicit jpeg_provider(byte_vector const& data);
|
14
|
+
explicit jpeg_provider(byte_vector && data);
|
15
|
+
jpeg_provider(byte const* data, size_t size);
|
16
|
+
//Movable:
|
17
|
+
jpeg_provider(jpeg_provider &&) = default;
|
18
|
+
jpeg_provider & operator = (jpeg_provider &&) = default;
|
19
|
+
|
20
|
+
static std::string format() { return "JPG"; }
|
21
|
+
|
22
|
+
virtual index_t size() const override;
|
23
|
+
virtual byte & access_indexed_data( index_t index ) override;
|
24
|
+
virtual byte const& access_indexed_data( index_t index ) const override;
|
25
|
+
virtual byte_vector commit_to_memory() override;
|
26
|
+
virtual void commit_to_file(filesystem::path const& file) override;
|
27
|
+
virtual byte_vector salt() const override;
|
28
|
+
|
29
|
+
private:
|
30
|
+
jpeg::decompress_ctx jinfo_;
|
31
|
+
|
32
|
+
std::size_t component_count_;
|
33
|
+
std::vector<std::size_t> wib_, hib_, comp_sz_;
|
34
|
+
index_t sz_;
|
35
|
+
|
36
|
+
void index_to_coordinates(index_t index, std::size_t & comp, std::size_t & row, std::size_t & col, std::size_t & block) const;
|
37
|
+
};
|
38
|
+
|
39
|
+
}} //namespace zindorsky::steganography
|
@@ -0,0 +1,149 @@
|
|
1
|
+
#include "jpeg_helpers.h"
|
2
|
+
#include "file_utils.h"
|
3
|
+
|
4
|
+
extern "C" void jpeglib_error_handler(j_common_ptr info)
|
5
|
+
{
|
6
|
+
if(info) {
|
7
|
+
jpeg_abort(info);
|
8
|
+
}
|
9
|
+
//can't throw in extern "C" functions.
|
10
|
+
// throw steganography::jpeg::jpeg_exception();
|
11
|
+
}
|
12
|
+
|
13
|
+
namespace zindorsky {
|
14
|
+
namespace steganography {
|
15
|
+
namespace jpeg {
|
16
|
+
|
17
|
+
decompress_ctx::decompress_ctx( filesystem::path const& filename )
|
18
|
+
: decompress_ctx( utils::load_from_file(filename) )
|
19
|
+
{
|
20
|
+
}
|
21
|
+
|
22
|
+
decompress_ctx::decompress_ctx(byte const* data, size_t size)
|
23
|
+
: decompress_ctx( byte_vector(data, data+size) )
|
24
|
+
{
|
25
|
+
}
|
26
|
+
|
27
|
+
decompress_ctx::decompress_ctx(byte_vector const& data)
|
28
|
+
: decompress_ctx(data.data(), data.size())
|
29
|
+
{
|
30
|
+
}
|
31
|
+
|
32
|
+
decompress_ctx::decompress_ctx(byte_vector && data)
|
33
|
+
: data_(std::move(data))
|
34
|
+
{
|
35
|
+
info_.err = jpeg_std_error(&err_mgr_);
|
36
|
+
err_mgr_.error_exit = jpeglib_error_handler;
|
37
|
+
|
38
|
+
jpeg_create_decompress(&info_);
|
39
|
+
//save markers for writing later
|
40
|
+
jpeg_save_markers(&info_,JPEG_COM,0xffff);
|
41
|
+
for(int i=1; i<=15; ++i) {
|
42
|
+
jpeg_save_markers(&info_,JPEG_APP0+i,0xffff);
|
43
|
+
}
|
44
|
+
|
45
|
+
try {
|
46
|
+
jpeg_mem_src(&info_, data_.data(), static_cast<unsigned long>(data_.size()));
|
47
|
+
jpeg_read_header(&info_,TRUE);
|
48
|
+
coeff_ = jpeg_read_coefficients(&info_);
|
49
|
+
if(!coeff_) {
|
50
|
+
throw jpeg_exception();
|
51
|
+
}
|
52
|
+
} catch(...) {
|
53
|
+
jpeg_destroy_decompress(&info_);
|
54
|
+
throw;
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
decompress_ctx::decompress_ctx(decompress_ctx && rhs)
|
59
|
+
: data_( std::move(rhs.data_) )
|
60
|
+
, err_mgr_( std::move(rhs.err_mgr_) )
|
61
|
+
, info_{0}
|
62
|
+
, coeff_( std::move(rhs.coeff_) )
|
63
|
+
{
|
64
|
+
std::swap(info_, rhs.info_);
|
65
|
+
}
|
66
|
+
|
67
|
+
decompress_ctx & decompress_ctx::operator = (decompress_ctx && rhs)
|
68
|
+
{
|
69
|
+
data_ = std::move(rhs.data_);
|
70
|
+
err_mgr_ = std::move(rhs.err_mgr_);
|
71
|
+
std::swap(info_, rhs.info_);
|
72
|
+
coeff_ = std::move(rhs.coeff_);
|
73
|
+
return *this;
|
74
|
+
}
|
75
|
+
|
76
|
+
decompress_ctx::~decompress_ctx()
|
77
|
+
{
|
78
|
+
if (info_.src) {
|
79
|
+
jpeg_destroy_decompress(&info_);
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
void decompress_ctx::save_to_file( filesystem::path const& filename )
|
84
|
+
{
|
85
|
+
FILE* file = ::fopen( filename.c_str(), "wb" );
|
86
|
+
if(!file) {
|
87
|
+
throw std::ios_base::failure("file open fail");
|
88
|
+
}
|
89
|
+
|
90
|
+
jpeg_error_mgr err_mgr;
|
91
|
+
jpeg_compress_struct info;
|
92
|
+
|
93
|
+
info.err = jpeg_std_error(&err_mgr);
|
94
|
+
err_mgr.error_exit = jpeglib_error_handler;
|
95
|
+
|
96
|
+
jpeg_create_compress(&info);
|
97
|
+
info.optimize_coding = TRUE;
|
98
|
+
|
99
|
+
jpeg_stdio_dest(&info, file);
|
100
|
+
|
101
|
+
jpeg_copy_critical_parameters(object(), &info);
|
102
|
+
jpeg_write_coefficients(&info, coefficients());
|
103
|
+
//copy markers and comments
|
104
|
+
for(jpeg_saved_marker_ptr curr=object()->marker_list; curr; curr=curr->next) {
|
105
|
+
if(curr->data && curr->data_length>0)
|
106
|
+
jpeg_write_marker(&info, curr->marker, curr->data, curr->data_length);
|
107
|
+
}
|
108
|
+
jpeg_finish_compress(&info);
|
109
|
+
jpeg_destroy_compress(&info);
|
110
|
+
::fclose(file);
|
111
|
+
}
|
112
|
+
|
113
|
+
byte_vector decompress_ctx::save_to_memory()
|
114
|
+
{
|
115
|
+
byte *mem = nullptr;
|
116
|
+
unsigned long memsz = 0;
|
117
|
+
|
118
|
+
jpeg_error_mgr err_mgr;
|
119
|
+
jpeg_compress_struct info;
|
120
|
+
|
121
|
+
info.err = jpeg_std_error(&err_mgr);
|
122
|
+
err_mgr.error_exit = jpeglib_error_handler;
|
123
|
+
|
124
|
+
jpeg_create_compress(&info);
|
125
|
+
info.optimize_coding = TRUE;
|
126
|
+
|
127
|
+
jpeg_mem_dest(&info, &mem, &memsz);
|
128
|
+
|
129
|
+
jpeg_copy_critical_parameters(object(), &info);
|
130
|
+
jpeg_write_coefficients(&info, coefficients());
|
131
|
+
//copy markers and comments
|
132
|
+
for(jpeg_saved_marker_ptr curr=object()->marker_list; curr; curr=curr->next) {
|
133
|
+
if(curr->data && curr->data_length>0)
|
134
|
+
jpeg_write_marker(&info, curr->marker, curr->data, curr->data_length);
|
135
|
+
}
|
136
|
+
jpeg_finish_compress(&info);
|
137
|
+
jpeg_destroy_compress(&info);
|
138
|
+
|
139
|
+
if (mem && memsz) {
|
140
|
+
byte_vector result{ mem, mem + memsz };
|
141
|
+
::free(mem);
|
142
|
+
return result;
|
143
|
+
}
|
144
|
+
|
145
|
+
return{};
|
146
|
+
}
|
147
|
+
|
148
|
+
}}} //namespace zindorsky::steganography::jpeg
|
149
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
#ifndef steganography_jpeg_helpers_h_included
|
2
|
+
#define steganography_jpeg_helpers_h_included
|
3
|
+
|
4
|
+
#include "steg_defs.h"
|
5
|
+
#include <cstdio>
|
6
|
+
#include <jpeglib.h>
|
7
|
+
#include <vector>
|
8
|
+
|
9
|
+
//error handling callback for jpeg lib
|
10
|
+
extern "C" void jpeglib_error_handler(j_common_ptr);
|
11
|
+
|
12
|
+
namespace zindorsky {
|
13
|
+
namespace steganography {
|
14
|
+
namespace jpeg {
|
15
|
+
|
16
|
+
class jpeg_exception : public std::runtime_error {
|
17
|
+
public:
|
18
|
+
jpeg_exception() : std::runtime_error("JPEG file error") {}
|
19
|
+
};
|
20
|
+
|
21
|
+
class decompress_ctx {
|
22
|
+
public:
|
23
|
+
explicit decompress_ctx( filesystem::path const& filename );
|
24
|
+
decompress_ctx(byte const* data, size_t size);
|
25
|
+
explicit decompress_ctx(byte_vector const& data);
|
26
|
+
explicit decompress_ctx(byte_vector && data);
|
27
|
+
|
28
|
+
//Non-copyable
|
29
|
+
decompress_ctx(decompress_ctx const&) = delete;
|
30
|
+
decompress_ctx & operator = (decompress_ctx const&) = delete;
|
31
|
+
//Movable
|
32
|
+
decompress_ctx(decompress_ctx &&);
|
33
|
+
decompress_ctx & operator = (decompress_ctx &&);
|
34
|
+
~decompress_ctx();
|
35
|
+
|
36
|
+
jpeg_decompress_struct * object() { return &info_; }
|
37
|
+
jpeg_decompress_struct const* object() const { return &info_; }
|
38
|
+
|
39
|
+
jvirt_barray_ptr* coefficients() const { return coeff_; }
|
40
|
+
|
41
|
+
void save_to_file( filesystem::path const& filename );
|
42
|
+
byte_vector save_to_memory();
|
43
|
+
|
44
|
+
private:
|
45
|
+
byte_vector data_;
|
46
|
+
jpeg_error_mgr err_mgr_;
|
47
|
+
jpeg_decompress_struct info_;
|
48
|
+
jvirt_barray_ptr *coeff_;
|
49
|
+
};
|
50
|
+
|
51
|
+
}}} //namespace zindorsky::steganography::jpeg
|
52
|
+
|
53
|
+
#endif //include guard
|
54
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#include "key_generator.h"
|
2
|
+
#include <openssl/evp.h>
|
3
|
+
|
4
|
+
namespace zindorsky {
|
5
|
+
namespace crypto {
|
6
|
+
|
7
|
+
key_generator::key_generator(std::string const& password, byte_vector const & salt, int iterations)
|
8
|
+
: password{password}
|
9
|
+
, salt{salt}
|
10
|
+
, iterations{iterations}
|
11
|
+
{
|
12
|
+
}
|
13
|
+
|
14
|
+
key_generator::key_generator(std::string const& password, byte const* salt, std::size_t salt_sz, int iterations)
|
15
|
+
: password{password}
|
16
|
+
, salt{salt,salt+salt_sz}
|
17
|
+
, iterations{iterations}
|
18
|
+
{
|
19
|
+
}
|
20
|
+
|
21
|
+
void key_generator::generate(byte * key, std::size_t length) const
|
22
|
+
{
|
23
|
+
PKCS5_PBKDF2_HMAC_SHA1(password.c_str(), static_cast<int>(password.size()), salt.data(), static_cast<int>(salt.size()), iterations, static_cast<int>(length), key);
|
24
|
+
}
|
25
|
+
|
26
|
+
byte_vector key_generator::generate(std::size_t length) const
|
27
|
+
{
|
28
|
+
byte_vector key(length);
|
29
|
+
if(!key.empty()) {
|
30
|
+
generate(&key[0],length);
|
31
|
+
}
|
32
|
+
return key;
|
33
|
+
}
|
34
|
+
|
35
|
+
}} //namespace zindorsky::crypto
|
36
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include "steg_defs.h"
|
4
|
+
#include <string>
|
5
|
+
|
6
|
+
namespace zindorsky {
|
7
|
+
namespace crypto {
|
8
|
+
|
9
|
+
class key_generator {
|
10
|
+
public:
|
11
|
+
key_generator(std::string const& password, byte_vector const& salt, int iterations = 10000);
|
12
|
+
key_generator(std::string const& password, byte const* salt, std::size_t salt_sz, int iterations = 10000);
|
13
|
+
|
14
|
+
void generate(byte * key, std::size_t length) const;
|
15
|
+
byte_vector generate(std::size_t length) const;
|
16
|
+
|
17
|
+
private:
|
18
|
+
std::string password;
|
19
|
+
byte_vector salt;
|
20
|
+
int iterations;
|
21
|
+
};
|
22
|
+
|
23
|
+
}} //namespace zindorsky::crypto
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#include <fstream>
|
2
|
+
#include "provider.h"
|
3
|
+
//Currently implemented providers:
|
4
|
+
#include "bmp.h"
|
5
|
+
#include "jpeg.h"
|
6
|
+
#include "png_provider.h"
|
7
|
+
#include "string.h"
|
8
|
+
|
9
|
+
namespace zindorsky {
|
10
|
+
namespace steganography {
|
11
|
+
|
12
|
+
namespace {
|
13
|
+
const size_t min_header_sz = 0x40;
|
14
|
+
}
|
15
|
+
|
16
|
+
std::unique_ptr<provider_t> provider_t::load(filesystem::path const& file)
|
17
|
+
{
|
18
|
+
std::ifstream source(file.c_str());
|
19
|
+
//read first few bytes for header
|
20
|
+
byte header[min_header_sz];
|
21
|
+
source.read(reinterpret_cast<char*>(header),sizeof(header));
|
22
|
+
source.close();
|
23
|
+
|
24
|
+
if( header[0]=='B' && header[1]=='M' ) {
|
25
|
+
return std::make_unique<bmp_provider>( file );
|
26
|
+
}
|
27
|
+
if( header[0]==0xff && header[1]==0xd8 && header[2]==0xff
|
28
|
+
&& (memcmp(&header[6],"JFIF",4)==0 || memcmp(&header[6],"Exif",4)==0) )
|
29
|
+
{
|
30
|
+
return std::make_unique<jpeg_provider>( file );
|
31
|
+
}
|
32
|
+
if( memcmp(header, png_provider::signature, sizeof(png_provider::signature)) == 0 ) {
|
33
|
+
return std::make_unique<png_provider>(file);
|
34
|
+
}
|
35
|
+
|
36
|
+
throw invalid_carrier{};
|
37
|
+
}
|
38
|
+
|
39
|
+
std::unique_ptr<provider_t> provider_t::load(void const* data, size_t size)
|
40
|
+
{
|
41
|
+
byte const* d = static_cast<byte const*>(data);
|
42
|
+
|
43
|
+
if (!d || size < min_header_sz) {
|
44
|
+
throw invalid_carrier{};
|
45
|
+
}
|
46
|
+
|
47
|
+
if( d[0]=='B' && d[1]=='M' ) {
|
48
|
+
return std::make_unique<bmp_provider>( d, size );
|
49
|
+
}
|
50
|
+
if( d[0]==0xff && d[1]==0xd8 && d[2]==0xff
|
51
|
+
&& (memcmp(&d[6],"JFIF",4)==0 || memcmp(&d[6],"Exif",4)==0) )
|
52
|
+
{
|
53
|
+
return std::make_unique<jpeg_provider>( d, size );
|
54
|
+
}
|
55
|
+
if( memcmp(data, png_provider::signature, sizeof(png_provider::signature))==0 ) {
|
56
|
+
return std::make_unique<png_provider>(d, size);
|
57
|
+
}
|
58
|
+
|
59
|
+
throw invalid_carrier{};
|
60
|
+
}
|
61
|
+
|
62
|
+
std::vector<std::string> provider_t::supported_formats()
|
63
|
+
{
|
64
|
+
return{
|
65
|
+
bmp_provider::format()
|
66
|
+
, jpeg_provider::format()
|
67
|
+
, png_provider::format()
|
68
|
+
};
|
69
|
+
}
|
70
|
+
|
71
|
+
}} //namespace zindorsky::steganography
|
72
|
+
|