def print_dct_diffs(cover, stego): import jpeg_toolbox as jt def print_list(l, ln): mooc = 0 for i in range(0, len(l), ln): print(l[i:i+ln]) v = l[i:i+ln][0][2] if np.abs(v) > 1: mooc += 1 #C_jpeg = JPEG(cover) C_jpeg = jt.load(cover) #S_jpeg = JPEG(stego) S_jpeg = jt.load(stego) #for i in range(C_jpeg.components()): for i in range(C_jpeg["jpeg_components"]): #C = C_jpeg.coeffs(i) #S = S_jpeg.coeffs(i) C = C_jpeg["coef_arrays"][i] S = S_jpeg["coef_arrays"][i] if C.shape!=S.shape: print("WARNING! channels with different size. Channel: ", i) continue D = S-C print("\nChannel "+str(i)+":") pairs = list(zip(C.ravel(), S.ravel(), D.ravel())) pairs_diff = [p for p in pairs if p[2]!=0] print_list(pairs_diff, 5)
def jpeg_lsbr_unhide(image_stego_path, output_msg_path): img = jt.load(image_stego_path) dct = img["coef_arrays"][0] d1, d2 = dct.shape dct_copy = dct.copy() # Do not use 0 and 1 coefficients dct_copy[np.abs(dct_copy) == 1] = 0 # Do not use the DC DCT coefficients dct_copy[::8, ::8] = 0 # 1D array dct = dct.flatten() dct_copy = dct_copy.flatten() # Index of the DCT coefficients we can change idx = np.where(dct_copy != 0)[0] # Select a pseudorandom set of DCT coefficents to hide the message # TODO: payload limit # TODO: use a password as seed random.seed(0) random.shuffle(idx) l = len(idx) # Read and save message msg = dct[idx] % 2 bits_to_msg_file(msg.astype('uint8').tolist(), output_msg_path)
def jpeg_lsbr_hiderandom(image_path, alpha, image_stego_path): img = jt.load(image_path) dct = img["coef_arrays"][0] d1, d2 = dct.shape dct_copy = dct.copy() # Do not use 0 and 1 coefficients dct_copy[np.abs(dct_copy) == 1] = 0 # Do not use the DC DCT coefficients dct_copy[::8, ::8] = 0 # 1D array dct = dct.flatten() dct_copy = dct_copy.flatten() # Index of the DCT coefficients we can change idx = np.where(dct_copy != 0)[0] # Select a pseudorandom set of DCT coefficents to hide the message random.shuffle(idx) l = int(float(alpha) * len(idx)) idx = idx[:l] msg = np.random.choice([0, 1], size=(l, )) # LSB replacement: # Put LSBs to 0 dct[idx] = np.sign(dct[idx]) * (np.abs(dct[idx]) - np.abs(dct[idx] % 2)) # Add the value of the message dct[idx] = np.sign(dct[idx]) * (np.abs(dct[idx]) + msg) # Reshape and save DCTs dct = dct.reshape((d1, d2)) img["coef_arrays"][0] = dct jt.save(img, image_stego_path)
def calibration(path, only_first_channel=False): tmpdir = tempfile.mkdtemp() predfile = os.path.join(tmpdir, 'img.jpg') os.system("convert -chop 4x4 " + path + " " + predfile) im_jpeg = jt.load(path) impred_jpeg = jt.load(predfile) shutil.rmtree(tmpdir) beta_list = [] for i in range(im_jpeg["jpeg_components"]): dct_b = im_jpeg["coef_arrays"][i] dct_0 = impred_jpeg["coef_arrays"][i] b01 = beta_kl(dct_0, dct_b, 0, 1) b10 = beta_kl(dct_0, dct_b, 1, 0) b11 = beta_kl(dct_0, dct_b, 1, 1) beta = (b01 + b10 + b11) / 3 beta_list.append(beta) if only_first_channel: break return beta_list
def calibration_chisquare_mode(path): """ it used jpeg_toolbox """ import jpeg_toolbox as jt tmpdir = tempfile.mkdtemp() predfile = os.path.join(tmpdir, 'img.jpg') os.system("convert -chop 4x4 "+path+" "+predfile) im_jpeg = jt.load(path) impred_jpeg = jt.load(predfile) shutil.rmtree(tmpdir) beta_list = [] for i in range(im_jpeg["jpeg_components"]): dct = im_jpeg["coef_arrays"][i] dct_estim = impred_jpeg["coef_arrays"][i] p_list = [] for k in range(4): for l in range(4): if (k, l) == (0, 0): continue f_exp, f_obs = [], [] for j in range(5): h = H_i(dct, k, l, j) h_estim = H_i(dct_estim, k, l, j) if h<5 or h_estim<5: break f_exp.append(h_estim) f_obs.append(h) #print(f_exp, f_obs) chi, p = scipy.stats.chisquare(f_obs, f_exp) p_list.append(p) p = np.mean(p_list) if p < 0.05: print("Hidden data found in channel "+str(i)+". p-value:", np.round(p, 6)) else: print("No hidden data found in channel "+str(i))
def calibration_f5(path): """ it used jpeg_toolbox """ import jpeg_toolbox as jt tmpdir = tempfile.mkdtemp() predfile = os.path.join(tmpdir, 'img.jpg') os.system("convert -chop 4x4 "+path+" "+predfile) im_jpeg = jt.load(path) impred_jpeg = jt.load(predfile) shutil.rmtree(tmpdir) beta_list = [] for i in range(im_jpeg["jpeg_components"]): dct_b = im_jpeg["coef_arrays"][i] dct_0 = impred_jpeg["coef_arrays"][i] b01 = beta_kl(dct_0, dct_b, 0, 1) b10 = beta_kl(dct_0, dct_b, 1, 0) b11 = beta_kl(dct_0, dct_b, 1, 1) beta = (b01+b10+b11)/3 if beta > 0.05: print("Hidden data found in channel "+str(i)+":", beta) else: print("No hidden data found in channel "+str(i))
def jpeg_lsbr_hide(image_path, msg_path, image_stego_path): msg_bit_list = msg_file_to_bits("msg.txt") img = jt.load(image_path) dct = img["coef_arrays"][0] d1, d2 = dct.shape dct_copy = dct.copy() # Do not use 0 and 1 coefficients dct_copy[np.abs(dct_copy) == 1] = 0 # Do not use the DC DCT coefficients dct_copy[::8, ::8] = 0 # 1D array dct = dct.flatten() dct_copy = dct_copy.flatten() # Index of the DCT coefficients we can change idx = np.where(dct_copy != 0)[0] # Select a pseudorandom set of DCT coefficents to hide the message # TODO: payload limit # TODO: use a password as seed random.seed(0) random.shuffle(idx) l = min(len(idx), len(msg_bit_list)) idx = idx[:l] msg = np.array(msg_bit_list[:l]) # LSB replacement: # Put LSBs to 0 dct[idx] = np.sign(dct[idx]) * (np.abs(dct[idx]) - np.abs(dct[idx] % 2)) # Add the value of the message dct[idx] = np.sign(dct[idx]) * (np.abs(dct[idx]) + msg) # Reshape and save DCTs dct = dct.reshape((d1, d2)) img["coef_arrays"][0] = dct jt.save(img, image_stego_path)
#!/usr/bin/python3 import sys import random import numpy as np # https://github.com/daniellerch/python-jpeg-toolbox import jpeg_toolbox as jt # Read image img = jt.load("lena.jpg") # Modify the coefficient in position (6,6) from channel 0 img["coef_arrays"][0][6, 6] += 1 # Save modified image jt.save(img, "lena_stego.jpg")