Skip to content

Commit

Permalink
add J-UNIWARD simulator
Browse files Browse the repository at this point in the history
  • Loading branch information
daniellerch committed Aug 7, 2018
1 parent faf481a commit 7279dea
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 2 deletions.
15 changes: 14 additions & 1 deletion aletheia.py
Expand Up @@ -178,6 +178,7 @@ def main():
" - hugo-sim: Embedding using HUGO simulator.\n" \
" - wow-sim: Embedding using WOW simulator.\n" \
" - s-uniward-sim: Embedding using S-UNIWARD simulator.\n" \
" - j-uniward-sim: Embedding using J-UNIWARD simulator.\n" \
" - hill-sim: Embedding using HILL simulator.\n" \
" - ebs-sim: Embedding using EBS simulator.\n" \
" - ued-sim: Embedding using UED simulator.\n" \
Expand Down Expand Up @@ -521,6 +522,17 @@ def main():
embed_message(stegosim.hill, sys.argv[2], sys.argv[3], sys.argv[4])
# }}}

# {{{ j-uniward-sim
elif sys.argv[1]=="j-uniward-sim":

if len(sys.argv)!=5:
print sys.argv[0], "j-uniward-sim <image/dir> <payload> <output-dir>\n"
sys.exit(0)

embed_message(stegosim.j_uniward, sys.argv[2], sys.argv[3], sys.argv[4],
embed_fn_saving=True)
# }}}

# {{{ ebs-sim
elif sys.argv[1]=="ebs-sim":

Expand All @@ -532,7 +544,7 @@ def main():
embed_fn_saving=True)
# }}}

# {{{ nsf5-sim
# {{{ ued-sim
elif sys.argv[1]=="ued-sim":

if len(sys.argv)!=5:
Expand Down Expand Up @@ -661,6 +673,7 @@ def main():
print " - hugo-sim: Embedding using HUGO simulator."
print " - wow-sim: Embedding using WOW simulator."
print " - s-uniward-sim: Embedding using S-UNIWARD simulator."
print " - j-uniward-sim: Embedding using J-UNIWARD simulator."
print " - hill-sim: Embedding using HILL simulator."
print " - nsf5-sim: Embedding using nsF5 simulator."
print ""
Expand Down
6 changes: 6 additions & 0 deletions aletheia/stegosim.py
Expand Up @@ -32,6 +32,7 @@ def _embed(sim, path, payload, dst_path=None):
m_code+="addpath('"+m_path+"');"
m_code+="warning('off');"
m_code+="pkg load image;"
m_code+="pkg load signal;"

if sim=='wow':
m_code+="X=WOW('"+path+"',"+payload+");"
Expand All @@ -41,6 +42,8 @@ def _embed(sim, path, payload, dst_path=None):
m_code+="X=S_UNIWARD('"+path+"',"+payload+");"
elif sim=='hill':
m_code+="X=HILL('"+path+"',"+payload+");"
elif sim=='j_uniward':
m_code+="J_UNIWARD('"+path+"',"+payload+",'"+dst_path+"');"
elif sim=='nsf5':
m_code+="NSF5('"+path+"',"+payload+",'"+dst_path+"');"
elif sim=='ebs':
Expand Down Expand Up @@ -73,6 +76,9 @@ def wow(path, payload):
def s_uniward(path, payload):
return _embed('s_uniward', path, payload)

def j_uniward(path, payload, dst_path):
return _embed('j_uniward', path, payload, dst_path)

def hugo(path, payload):
return _embed('hugo', path, payload)

Expand Down
203 changes: 203 additions & 0 deletions external/octave/J_UNIWARD.m
@@ -0,0 +1,203 @@
function J_UNIWARD(cover, payload, stego)


% -------------------------------------------------------------------------
% Copyright (c) 2013 DDE Lab, Binghamton University, NY.
% All Rights Reserved.
% -------------------------------------------------------------------------
% Permission to use, copy, modify, and distribute this software for
% educational, research and non-profit purposes, without fee, and without a
% written agreement is hereby granted, provided that this copyright notice
% appears in all copies. The program is supplied "as is," without any
% accompanying services from DDE Lab. DDE Lab does not warrant the
% operation of the program will be uninterrupted or error-free. The
% end-user understands that the program was developed for research purposes
% and is advised not to rely exclusively on the program for any reason. In
% no event shall Binghamton University or DDE Lab be liable to any party
% for direct, indirect, special, incidental, or consequential damages,
% including lost profits, arising out of the use of this software. DDE Lab
% disclaims any warranties, and has no obligations to provide maintenance,
% support, updates, enhancements or modifications.
% -------------------------------------------------------------------------
% Contact: vojtech_holub@yahoo.com | fridrich@binghamton.edu | February
% 2013
% http://dde.binghamton.edu/download/stego_algorithms/
% -------------------------------------------------------------------------
% This function simulates embedding using J-UNIWARD steganographic
% algorithm.
% -------------------------------------------------------------------------
% Input: cover ... ... path to the image
% payload ..... payload in bits per non zero DCT coefficient
% Output: stego ....... resulting JPEG structure with embedded payload
% -------------------------------------------------------------------------

C_SPATIAL = double(imread(cover));
C_STRUCT = jpeg_read(cover);
C_COEFFS = C_STRUCT.coef_arrays{1};
C_QUANT = C_STRUCT.quant_tables{1};

wetConst = 10^13;
sgm = 2^(-6);

%% Get 2D wavelet filters - Daubechies 8
% 1D high pass decomposition filter
hpdf = [-0.0544158422, 0.3128715909, -0.6756307363, 0.5853546837, 0.0158291053, -0.2840155430, -0.0004724846, 0.1287474266, 0.0173693010, -0.0440882539, ...
-0.0139810279, 0.0087460940, 0.0048703530, -0.0003917404, -0.0006754494, -0.0001174768];
% 1D low pass decomposition filter
lpdf = (-1).^(0:numel(hpdf)-1).*fliplr(hpdf);

F{1} = lpdf'*hpdf;
F{2} = hpdf'*lpdf;
F{3} = hpdf'*hpdf;

%% Pre-compute impact in spatial domain when a jpeg coefficient is changed by 1
spatialImpact = cell(8, 8);
for bcoord_i=1:8
for bcoord_j=1:8
testCoeffs = zeros(8, 8);
testCoeffs(bcoord_i, bcoord_j) = 1;
spatialImpact{bcoord_i, bcoord_j} = idct2(testCoeffs)*C_QUANT(bcoord_i, bcoord_j);
end
end

%% Pre compute impact on wavelet coefficients when a jpeg coefficient is changed by 1
waveletImpact = cell(numel(F), 8, 8);
for Findex = 1:numel(F)
for bcoord_i=1:8
for bcoord_j=1:8
waveletImpact{Findex, bcoord_i, bcoord_j} = imfilter(spatialImpact{bcoord_i, bcoord_j}, F{Findex}, 'full');
end
end
end

%% Create reference cover wavelet coefficients (LH, HL, HH)
% Embedding should minimize their relative change. Computation uses mirror-padding
padSize = max([size(F{1})'; size(F{2})']);
C_SPATIAL_PADDED = padarray(C_SPATIAL, [padSize padSize], 'symmetric'); % pad image

RC = cell(size(F));
for i=1:numel(F)
RC{i} = imfilter(C_SPATIAL_PADDED, F{i});
end

[k, l] = size(C_COEFFS);

nzAC = nnz(C_COEFFS)-nnz(C_COEFFS(1:8:end,1:8:end));
rho = zeros(k, l);
tempXi = cell(3, 1);

%% Computation of costs
for row = 1:k
for col = 1:l
modRow = mod(row-1, 8)+1;
modCol = mod(col-1, 8)+1;

subRows = row-modRow-6+padSize:row-modRow+16+padSize;
subCols = col-modCol-6+padSize:col-modCol+16+padSize;

for fIndex = 1:3
% compute residual
RC_sub = RC{fIndex}(subRows, subCols);
% get differences between cover and stego
wavCoverStegoDiff = waveletImpact{fIndex, modRow, modCol};
% compute suitability
tempXi{fIndex} = abs(wavCoverStegoDiff) ./ (abs(RC_sub)+sgm);
end
rhoTemp = tempXi{1} + tempXi{2} + tempXi{3};
rho(row, col) = sum(rhoTemp(:));
end
end

rhoM1 = rho;
rhoP1 = rho;

rhoP1(rhoP1 > wetConst) = wetConst;
rhoP1(isnan(rhoP1)) = wetConst;
rhoP1(C_COEFFS > 1023) = wetConst;

rhoM1(rhoM1 > wetConst) = wetConst;
rhoM1(isnan(rhoM1)) = wetConst;
rhoM1(C_COEFFS < -1023) = wetConst;

%% Embedding simulation
S_COEFFS = EmbeddingSimulator(C_COEFFS, rhoP1, rhoM1, round(payload * nzAC));

S_STRUCT = C_STRUCT;
S_STRUCT.coef_arrays{1} = S_COEFFS;


try
jpeg_write(S_STRUCT, stego);
catch
error('ERROR (problem with saving the stego image)')
end





function [y, pChangeP1, pChangeM1] = EmbeddingSimulator(x, rhoP1, rhoM1, m)

x = double(x);
n = numel(x);

lambda = calc_lambda(rhoP1, rhoM1, m, n);
pChangeP1 = (exp(-lambda .* rhoP1))./(1 + exp(-lambda .* rhoP1) + exp(-lambda .* rhoM1));
pChangeM1 = (exp(-lambda .* rhoM1))./(1 + exp(-lambda .* rhoP1) + exp(-lambda .* rhoM1));

randChange = rand(size(x));
y = x;
y(randChange < pChangeP1) = y(randChange < pChangeP1) + 1;
y(randChange >= pChangeP1 & randChange < pChangeP1+pChangeM1) = y(randChange >= pChangeP1 & randChange < pChangeP1+pChangeM1) - 1;

function lambda = calc_lambda(rhoP1, rhoM1, message_length, n)

l3 = 1e+3;
m3 = double(message_length + 1);
iterations = 0;
while m3 > message_length
l3 = l3 * 2;
pP1 = (exp(-l3 .* rhoP1))./(1 + exp(-l3 .* rhoP1) + exp(-l3 .* rhoM1));
pM1 = (exp(-l3 .* rhoM1))./(1 + exp(-l3 .* rhoP1) + exp(-l3 .* rhoM1));
m3 = ternary_entropyf(pP1, pM1);
iterations = iterations + 1;
if (iterations > 10)
lambda = l3;
return;
end
end

l1 = 0;
m1 = double(n);
lambda = 0;

alpha = double(message_length)/n;
% limit search to 30 iterations
% and require that relative payload embedded is roughly within 1/1000 of the required relative payload
while (double(m1-m3)/n > alpha/1000.0 ) && (iterations<30)
lambda = l1+(l3-l1)/2;
pP1 = (exp(-lambda .* rhoP1))./(1 + exp(-lambda .* rhoP1) + exp(-lambda .* rhoM1));
pM1 = (exp(-lambda .* rhoM1))./(1 + exp(-lambda .* rhoP1) + exp(-lambda .* rhoM1));
m2 = ternary_entropyf(pP1, pM1);
if m2 < message_length
l3 = lambda;
m3 = m2;
else
l1 = lambda;
m1 = m2;
end
iterations = iterations + 1;
end
end

function Ht = ternary_entropyf(pP1, pM1)
pP1 = pP1(:);
pM1 = pM1(:);
Ht = -(pP1.*log2(pP1))-(pM1.*log2(pM1))-((1-pP1-pM1).*log2(1-pP1-pM1));
Ht(isnan(Ht)) = 0;
Ht = sum(Ht);
end

end

end
2 changes: 1 addition & 1 deletion octave-requirements.txt
@@ -1 +1 @@
image
image signal

0 comments on commit 7279dea

Please sign in to comment.