zindosteg 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+