返回信息流求大牛知道F5 隐写算法的代码~~~
这是一条镜像帖。来源:北邮人论坛 / security / #35130同步于 2012/9/12
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Security机器人发帖
F5 隐写算法
zlnbobo
2012/9/12镜像同步4 回复
订阅后,新回复会通过你的通知中心匿名送达。
4 条回复
F5.cpp
#include "StdAfx.h"
#include "F5.h"
#include <iostream>
using namespace std;
/**********************************
F5算法《变化密度、嵌入率和嵌入效率之间的关系》表
k n change density embedding rate embedding efficiency
1 1 50.00% 100.00% 2
2 3 25.00% 66.67% 2.67
3 7 12.50% 42.86% 3.43
4 15 6.25% 26.67% 4.27
5 31 3.12% 16.13% 5.16
6 63 1.56% 9.52% 6.09
7 127 0.78% 5.51% 7.06
8 255 0.39% 3.14% 8.03
9 511 0.20% 1.76% 9.02
我们假设有有一半的 -1、1会在编码后消耗为0
根据JPEG系数柱图,系数1、-1占1/2,所以实际上 [embedding rate] = [embedding rate] * 3 / 4;
**********************************/
#define PERCENTAGE 4/3
struct
{
int _n;
int _k;
double _rate;
}Mode[9]=
{{0, 0, 0.0000},
{1, 1, 0.6667*PERCENTAGE},
{3, 2, 0.4286*PERCENTAGE},
{7, 3, 0.2667*PERCENTAGE},
{15, 4, 0.1613*PERCENTAGE},
{31, 5, 0.0952*PERCENTAGE},
{63, 6, 0.0551*PERCENTAGE},
{127, 7, 0.0314*PERCENTAGE},
{511, 8, 0.0176*PERCENTAGE}
};
CF5::CF5(void)
{
fAValue = -1;
index = -1;
n = -1;
k = -1;
r = -1;
message = 0x0;
msgRStart = 7;
msgWStart = 7;
tmpCode = 0x0;
}
CF5::~CF5(void)
{
}
// 获得HASH函数f(a)
// 返回f(a)的值fAValue,若出错返回-1
int CF5::makeHash(COEF** A, int lthN, int lthK)
{
//最多只能完成8位的矩阵编码
if(lthK > 8)
return -1;
int tmp;
fAValue = 0;
bool start = true;
for( ; lthK>0; lthK--)
{
cout<<"f( "<<lthK<<" ) = ";
tmp = 0;
for(int i=1; i=lthN; i++)
{
tmp ^= ((*A[i-1])&0x1) * ((i>>(lthK-1)) & 0x1);
if((i>>(lthK-1)) & 0x1)
if(start)
{
cout<<"a"<<i<<"("<<(*A[i-1])<<"|"<<((*A[i-1])&0x1)<<")";
start = false;
}
else
cout<<" + a"<<i<<"("<<(*A[i-1])<<"|"<<((*A[i-1])&0x1)<<")";
}
cout<<" = ";
cout<<tmp<<"\n";
hash[lthK-1] = tmp;
start = true;
fAValue ^= tmp<<(lthK-1);
}
cout<<"\n";
return fAValue;
}
int CF5::makeHash()
{
return makeHash(carrier, n, k);
}
// 嵌入k长信息,消耗bit
// 修改A[]的对应位,返回修改值在数组的位置(1 ~ lthN),如没有修改返回0, 出错返回-1
int CF5::decrement(COEF** A, int lthK, BYTE msg)
{
int tmpL;
BYTE tmpM;
for(tmpL=lthK,tmpM=msg; tmpM!=0; tmpL--,tmpM>>=1);
if(tmpL 0) //消息过长
return -1;
if(fAValue == -1) //f(a)未计算出
return -1;
index = msg ^ fAValue;
if(index>0) //翻转最低位
*A[index-1] ^= 0x1;
return index;
}
int CF5::decrement()
{
return decrement(carrier, k, message);
}
// 压缩测试
// 如果未生成0,返回0,如果生成0,则消除0位,返回1,如果无法消除0位,返回-1
int CF5::shrinkage(COEF **A, int lthN, COEF **Arest, COEFLENGTH* lArest)
{
int i;
if(index == -1) //index未计算出
return -1;
if(index == 0) //无改变
return 0;
if((*A[index-1])==0) //生成0
{
//消除0位
for(i=index-1; i<lthN-1; i++)
A[i] = A[i+1];
for(; *lArest>0; (*lArest)--, (*Arest)++)
if(**Arest != 0)
{
A[lthN-1] = *Arest;
(*Arest)++;
(*lArest)--;
break;
}
if(0 > *lArest) //数据不够嵌入
return -1;
return 1;
}
return 0;
}
int CF5::shrinkage(COEF **Arest, COEFLENGTH* lArest)
{
return shrinkage(carrier, n, Arest, lArest);
}
// 根据载体和密文容量确定n、k的值
// 若无合适值,返回-1,否则返回编码方式
int CF5::initPara(COEF** cof, COEFLENGTH lthCof, MSGLENGTH lthMsg)
{
//计算载体的有效容量
COEFLENGTH effective_coefficients_length = 0;
for(COEFLENGTH i=0; i<lthCof; i++)
if(0 != (*((*cof)+i)))
effective_coefficients_length ++;
double rate = (double)lthMsg / effective_coefficients_length;
r = -1;
for(int i=0; i<9; i++)
if(rate Mode[i]._rate)
{
n = Mode[i]._n;
k = Mode[i]._k;
r = i;
}
return r;
}
// 嵌入算法
// 调用前需先调用initPara/setPara初始化模式
// 如嵌入成功,返回1;嵌入成功但仍有未嵌入的密文,返回0;嵌入失败返回-1
int CF5::embed(COEF** cof, COEFLENGTH* lthCof, BYTE** msg, MSGLENGTH* lthMsg)
{
CHK(r);
msgRStart = 7;
while((*lthCof)*Mode[r]._rate>(COEFLENGTH)k && (*lthMsg)>0)
{
CHK(getOneBuffer(cof, lthCof));
CHK(readMsg(msg, lthMsg));
do
{
CHK(makeHash());
CHK(decrement());
}while(1==shrinkage(cof, lthCof));
//密文已嵌入整数个字节,而剩下的载体不足以嵌入整数个字节或剩余的密文位剩下的长度
if(0==(*lthMsg)%8 && ((*lthCof)*Mode[r]._rate<8 || (*lthCof)*Mode[r]._rate<(*lthMsg)))
break;
}
if((*lthMsg)>0)
return 0;
else
return 1;
}
// 提取算法
// 调用前需先调用initPara/setPara初始化模式
// 如提取成功,返回1;提取失败返回-1
int CF5::distill(COEF** cof, COEFLENGTH* lthCof, BYTE** msg, MSGLENGTH lthMsg)
{
CHK(r);
msgWStart = 7;
MSGLENGTH lthWMsg = 0;
while(lthWMsg<lthMsg)
{
CHK(getOneBuffer(cof, lthCof));
makeHash();
message = 0x0;
for(int i=k-1; i>=0; i--)
message ^= hash[i]<<i;
writeMsg(msg, ((lthMsg-lthWMsg)<(MSGLENGTH)k)?(lthMsg-lthWMsg):k, <hWMsg);
}
return 0;
}
// 返回编码方式
int CF5::getMode(void)
{
return r;
}
// 从密文中读出本次矩阵编码的单位密文,长度为k
// 成功返回 1,失败返回 -1
int CF5::readMsg(BYTE** msg, MSGLENGTH* lthMsg )
{
if(*lthMsg=0)
return -1;
BYTE colander = 0x80;
int i = 0;
colander >>= 7-msgRStart;
message = 0;
while(i<k && (*lthMsg)>0)
{
message = (message<<1) ^ (((**msg)&colander)>>msgRStart);
colander >>= 1;
msgRStart --;
i ++;
(*lthMsg) --;
if(colander == 0)
{
colander = 0x80;
msgRStart = 7;
(*msg) ++;
}
}
if((*lthMsg) == 0) //剩余密文不够一次编码,用0补齐
message <= (k-i);
return 1;
}
// 矩阵解码的单位密文写入密文流
// 成功返回 1,失败返回 -1
int CF5::writeMsg(BYTE** msg, int lthMsg, MSGLENGTH* lthTotleMsg)
{
int i = k-1;
while(i>=0)
{
tmpCode |= ((message>>i)&0x1)<<msgWStart;
msgWStart --;
i --;
if(msgWStart<0)
{
msgWStart = 7;
*(*msg) ++ = tmpCode;
tmpCode = 0x0;
}
}
if(lthMsg<k)
{
msgWStart = 7;
*(*msg) ++ = tmpCode;
tmpCode = 0x0;
}
(*lthTotleMsg) += lthMsg;
return 1;
}
// 设置编码模式
// 成功返回 1,失败返回 -1
int CF5::setPara(int _r)
{
if(r<0 || r>=9)
return -1;
r = _r;
n = Mode[_r]._n;
k = Mode[_r]._k;
return 1;
}
// 返回编码模式
// 成功返回 1,失败返回 -1
int CF5::getPara(int* on, int* ok)
{
if(n==-1||k==-1)
return -1;
*on = n;
*ok = k;
return 1;
}
// 得到一单位长度的载体流
// 从系数数据中取出一个单位长度(n)的buffer用于矩阵编码
int CF5::getOneBuffer(COEF** cof, COEFLENGTH* lthCof)
{
for(int i=0; i<n; )
{
if(0 != **cof)
carrier[i++] = *cof;
(*cof) ++;
(*lthCof) --;
if(*lthCof 0)
{
*cof = NULL;
return -1;
}
}
return 1;
}
F5.h
#pragma once
#ifndef BYTE
typedef unsigned char BYTE;
#endif
#define CHK(n) if(-1==n) return -1;
typedef int COEF;
typedef unsigned long COEFLENGTH;
typedef unsigned long MSGLENGTH;
class CF5
{
public:
CF5(void);
~CF5(void);
// 嵌入
int embed(COEF** cof, COEFLENGTH* lthCof, BYTE** msg, MSGLENGTH* lthMsg);
// 提取
int distill(COEF** cof, COEFLENGTH* lthCof, BYTE** msg, MSGLENGTH lthMsg);
// 返回编码方式
int getMode(void);
// 根据载体和密文容量确定n、k的值
int initPara(COEF** cof, COEFLENGTH lthCof, MSGLENGTH lthMsg);
// 设置编码模式
int setPara(int _r);
// 返回编码模式
int getPara(int* oN, int* oK);
//private:
// 获得HASH函数f(a)
int makeHash(COEF** A, int lthN, int lthK);
int makeHash();
// 嵌入k长信息,消耗bit
int decrement(COEF** A, int lthK, BYTE msg);
int decrement();
// 压缩测试
int shrinkage(COEF** A, int lthN, COEF **Arest, COEFLENGTH* lArest);
int shrinkage(COEF **Arest, COEFLENGTH* lArest);
// 从密文中读出本次矩阵编码的单位密文
int readMsg(BYTE** msg, MSGLENGTH* lthMsg);
// 矩阵解码的单位密文写入密文流
int writeMsg(BYTE** msg, int lthMsg, MSGLENGTH* lthTotleMsg);
// 得到一单位长度的载体流
int getOneBuffer(COEF** cof, COEFLENGTH* lthCof);
//private:
int fAValue;
int index;
int n; /*载体长度*/
int k; /*密文长度*/
int r; /*选择编码方式*/
COEF* carrier[127]; /*一次矩阵编码的单位载体*/
BYTE message; /*矩阵编码的单位密文*/
BYTE hash[8];
int msgRStart, /*密文读写开始位置*/
msgWStart; /*读出或写入的单位密文不一定是BYTE的倍数,用此记录密文开始的位置*/
BYTE tmpCode; /*存放不足写满1 byte的编码*/
};
Hash.cpp
// Hash.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include "F5.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
/*0, 1, 2, 3, 4, 5, 6, 7, 8, 9*/
int a[] = {3, 4,-5,-1, 2, 2, 1, 0,-2, 0,
0, 0, 3, 2, 1,-2,-5, 3, 0, 1,
2 };
COEFLENGTH lengthC = 21;
COEFLENGTH lengthA = lengthC;
MSGLENGTH lengthM = 16;
int* lpA = a;
//BYTE msg = 0x6;
//BYTE msg1[] = {0xf3,0xf2,0x51};
//BYTE msg2[] = {0xff,0x00,0xff};
BYTE msg3[] = {0xa3, 0xbe};
MSGLENGTH lengthM4 = 16;
BYTE* Msg4 = (BYTE*)malloc(sizeof(BYTE)*lengthM4);
BYTE* lpMsg4 = Msg4;
//BYTE* lpMsg1 = msg1;
//BYTE* lpMsg2 = msg2;
BYTE* lpMsg3 = msg3;
unsigned long lthMsgsg1 = 24, lthMsgsg2 = 0;
CF5 f;
//f.setPara(lengthA, lengthX);
//f.getOneBuffer(&lpA, &length);
//while(lthMsgsg1>0)
//{
// f.readMsg(&lpMsg1, <hMsgsg1);
// f.writeMsg(&lpMsg2, <hMsgsg2);
//}
//COEFLENGTH lRest = length-lengthA;
//lpA += lengthA;
//f.makeHash(a, lengthA, lengthX);
//f.decrement(a, lengthX, msg);
//f.shrinkage(a, lengthA, &lpA, &lRest);
f.initPara(&lpA, lengthC, lengthM);
f.embed(&lpA, &lengthC, &lpMsg3, &lengthM);
lpA = a;
f.distill(&lpA, &lengthA, &lpMsg4, lengthM4);
return 0;
}
【 在 Xsetc 的大作中提到: 】
: F5.cpp
: [code=c]
: #include "StdAfx.h"
: ...................
谢谢啦~~~