- 古典密码学种类
- 移位密码(凯撒密码)
对于一个密码体制,必须满足一定的条件,下面所述的两个条件必须的:
- 对于加密体制而言,其加解密函数都要易于计算
- 对于任何敌手而言,即使他获取了密文Y,也很难由此确定出对应的密钥K或密文
移位密码属于最简单的一种加密方法,其实现和原理都很简单,但是由于本身的问题,其密钥空间很小,而且又属于单表替换,所以安全性不高,易受来自穷举以及词频等简单的密码攻击破解.
- 代换密码
代换密码也属于单表替换,其原理很简单,先制作出一张替换的表格,然后加密时根据表格替换明文,解密的时候,需要先制作出解密的替换表格,这个表格和 加密表格是对应的,对于26个字母而言,所有可能的替换方法达到26!种,密钥空间很大,所以利用穷举法不是很容易破解.但是,由于这种加密算法仍然属于单表替 换,所以仍然不能抵抗根据词频来破解密码这种方法.
- 仿射密码
仿射密码是移位密码的扩展,仿射密码是利用线性函数的一一对应的原理来实现的,其加密函数为e(x)=(ax+b) mod nMax (nMax为常数).对于加密函数而言,
其中的a是有限制的,需要a和nMax的最大公约数为1. 对于a的取值空间大小,可以由nMax的值计算出来,其值为φ(nMax)可由欧拉公式获得,所以其密钥空间大小
为nMax*φ(nMax).
对于nMax=60时,φ(60)=(2的2次方-2的1次方)*(3的1次方-3的0次方)*(5的1次方-5的0次方)=(4-2)*(3-1)*(5-1)=16,所以其密钥空间大小为:16*60=960.
所以对于nMax值够大的时候,密钥空间也还是比较大的,因此对穷举法有一定的抵抗性.
解密函数为d(y)=a'*(y-b) mod 26,a'表示a在nMax的乘法逆.
由于仿射密码仍然属于单表替换,所以不容易抵抗来自根据词频的密码攻击.
- 维吉利亚密码
维吉利亚密码采用的是循环使用密钥串来来加解密,属于多表替换,但是由于密钥长度一般有限,所以根据穷举密钥长度以及利用词频攻击仍然比较容易破解该类密码.
- 希尔密码
希尔密码采用引入矩阵来加解密,其密钥空间大,没有单表替换的特点,所以一般的密码的安全性比较高,不易受到来自穷举以及根据词频破解的攻击.但是,其实现方
法比较复杂,需要考虑矩阵的特性(可逆?),又需要求得加密矩阵的逆矩阵.
- 置换密码
置换密码和前面的加解密方法相差比较大,加解密的时候不会改变处理数据的整体内容,只是调整数据的顺序以达到加密效果.由于只是改变顺序,所以不易受到来
自根据词频的密码攻击.对于密钥长度为6的密钥,其密钥空间大小为6!个,所以密钥空间比较大,不易受到来自穷举法的密码攻击.
事实上,置换密码是希尔密码的一种特殊情形.
- 实现示例
.h文件
//Copyright (c) 2013 hustfisher All Rights Reserved
/*********************************************************************************************
*file name : classic_crypto.h
*description :
*create time : 2013/12/22 18:29:19
*author name : hustfisher
*author email : hustfisher@yeah.net
*author blog :
*version : 1.0
**********************************************************************************************/
#ifndef __CLASSIC_CRYPTO_H__
#define __CLASSIC_CRYPTO_H__
#include <stdio.h>
#include <string.h>
#define ALPHA_NUM (26)
#define IS_ALPHA(a) (a>='a' && a<='z')
/************************************************************************/
/* 移位密码 */
/* E=(x+k)%26 D=(y-k)%26 */
/************************************************************************/
void ShiftCipher(int nKey, char* pData, int nLen, bool bEnc=true)
{
nKey %= ALPHA_NUM;
if(!bEnc)
{
nKey *= -1;
}
/* 保证模运算之前为正数 */
nKey += ALPHA_NUM;
for (int i=0; i<nLen; i++)
{
if(IS_ALPHA(pData[i]))
{
pData[i] = (pData[i] - 'a' + nKey)%ALPHA_NUM+'a';
}
}
}
/************************************************************************/
/* 代换密码 '符号表示逆 */
/* E=π(x) D=π'(x) */
/************************************************************************/
void SubstitutionCipher(char* pData, int nLen, bool bEnc=true)
{
/* 表格根据即为密钥,通过修改表格修改密钥 */
char pEnKey[26] =
{
'f', 'j', 'x', 't', 'a', 'c', 'g', 'y',
'b', 'd', 'k', 'r', 'e', 'z', 'h', 'l',
'i', 'm', 'q', 'o', 'n', 'v', 's', 'w',
'p', 'u'
};
char pDeKey[26] =
{
'e', 'i', 'f', 'j', 'm', 'a', 'g', 'o',
'q', 'b', 'k', 'p', 'r', 'u', 't', 'y',
's', 'l', 'w', 'd', 'z', 'v', 'x', 'c',
'h', 'n'
};
/* 生成对应解密密钥 */
/*for (int i=0; i<26; i++)
{
for (int j=0; j<26; j++)
{
if(pEnKey[j]-'a' == i)
{
if(i%8 == 0)printf("\n");
printf("'%c', ", j+'a');
}
}
}*/
char* pKey = pEnKey;
if(!bEnc)
{
pKey = pDeKey;
}
for (int i=0; i<nLen; i++)
{
if(IS_ALPHA(pData[i]))
{
pData[i] = pKey[pData[i]-'a'];
}
}
}
/************************************************************************/
/* 辗转相除法求最大公约数 */
/************************************************************************/
int Gcd(int m, int n)
{
if(m < n)
{
m ^= n;
n ^= m;
m ^= n;
}
int r = m % n;
while (r != 0)
{
m = n;
n = r;
r = m % n;
}
return n;
}
/************************************************************************/
/* 辗转相除法求乘法的逆元和最大公约数 */
/************************************************************************/
int ExtendedEuclid( int f, int d, int *pnRst )
{
int x1,x2,x3,y1,y2,y3,t1,t2,t3,q;
int nMax = f;
x1 = y2 = 1;
x2 = y1 = 0;
x3 = ( f>=d )?f:d;
y3 = ( f>=d )?d:f;
nMax = x3;
while( 1 )
{
/* 最大公约数 */
if ( y3 == 0 )
{
*pnRst = x3;
return 0;
}
/* 逆元 */
if ( y3 == 1 )
{
if(y2 < 0) y2 += nMax;
*pnRst = y2;
return 1;
}
q = x3/y3;
t1 = x1 - q*y1;
t2 = x2 - q*y2;
t3 = x3 - q*y3;
x1 = y1;
x2 = y2;
x3 = y3;
y1 = t1;
y2 = t2;
y3 = t3;
}
}
/************************************************************************/
/* 仿射密码 */
/* E=(a*x+b)%26 D=a'(y-b)%26 */
/************************************************************************/
void AffineCipher(int nKeyA, int nKeyB, char* pData, int nLen, bool bEnc=true)
{
int nKeyRA = 0;
if(!ExtendedEuclid(nKeyA, ALPHA_NUM, &nKeyRA))
{
printf("Invalide a!\n");
return;
}
if(bEnc)
{
for (int i=0; i<nLen; i++)
{
if(IS_ALPHA(pData[i]))
{
pData[i] = ((pData[i]-'a') * nKeyA + nKeyB) % ALPHA_NUM + 'a';
}
}
}
else
{
for (int i=0; i<nLen; i++)
{
if(IS_ALPHA(pData[i]))
{
pData[i] = nKeyRA * (pData[i]-'a'-nKeyB+ALPHA_NUM) % ALPHA_NUM + 'a';
}
}
}
}
/************************************************************************/
/* 维吉尼亚密码 */
/* E(x1,x2,..,xN) = (x1+k1, x2+k2,...,xN+kN) */
/* D(y1,y2,..,yN) = (y1-k1, y2-k2,...,yN+kN) */
/************************************************************************/
void VigenreCipher(const int* pKey, int nKenLen, char* pData, int nLen, bool bEnc=true)
{
int nEnc = 1;
if(!bEnc)
{
nEnc = -1;
}
for (int i=0; i<nLen; i++)
{
if(IS_ALPHA(pData[i]))
{
pData[i] = ((pData[i]-'a') + nEnc * pKey[i%nKenLen] + ALPHA_NUM) % ALPHA_NUM + 'a';
}
}
}
/************************************************************************/
/* 希尔密码 示例为2阶矩阵且可逆 且数据全为字母 密码有严格要求 */
/* E = x*K D = y*K' */
/************************************************************************/
void HillCipher(const int* pnKey, char* pData, int nLen, bool bEnc=true)
{
if(nLen%2)
{
printf("Invalide data len.\n");
return;
}
int pnRKey[4];
char pTmp[2];
const int* pKey = pnKey;
if(!bEnc)
{
/* 逆矩阵 */
int nDiv = (pnKey[0]*pnKey[3] - pnKey[1]*pnKey[2])%ALPHA_NUM;
pnRKey[0] = (pnKey[3]) / nDiv;
pnRKey[1] = (ALPHA_NUM - pnKey[1]) / nDiv;
pnRKey[2] = (ALPHA_NUM - pnKey[2]) / nDiv;
pnRKey[3] = (pnKey[0]) / nDiv;
pKey = pnRKey;
}
for (int i=0; i<nLen; i += 2)
{
pTmp[0] = pData[i] - 'a';
pTmp[1] = pData[i+1] - 'a';
pData[i] = (pTmp[0]*pKey[0] + pTmp[1]*pKey[2]) % ALPHA_NUM + 'a';
pData[i+1] = (pTmp[0]*pKey[1] + pTmp[1]*pKey[3]) % ALPHA_NUM + 'a';
}
}
/************************************************************************/
/* 置换密码 明文内容不变顺序变化 */
/************************************************************************/
void PermutationCipher(const int* pnKey, int nKeyLen, char* pData, int nLen, bool bEnc=true)
{
if(nLen%nKeyLen)
{
printf("invalide data len.\n");
return;
}
const int* pKey = pnKey;
int* pnRKey = NULL;
char* pTmp = new char[nKeyLen];
/* 获取解密密钥 */
if(!bEnc)
{
pnRKey = new int[nKeyLen];
for (int i=1; i<nKeyLen+1; i++)
{
pnRKey[pKey[i-1]-1] = i;
}
pKey = pnRKey;
}
for (int i=0; i<nLen; i+=nKeyLen)
{
memcpy(pTmp, pData+i, sizeof(pTmp[0])*nKeyLen);
for (int j=0; j<nKeyLen; j++)
{
pData[i+j] = pTmp[pKey[j]-1];
}
}
delete[] pTmp; pTmp = NULL;
delete[] pnRKey; pnRKey = NULL;
}
#endif
.CPP文件
#include "classic_crypto.h"
#include <stdio.h>
#include <string.h>
#include <Windows.h>
int main(int argc, char* argv[])
{
char pData[] = "you are my hero";
int nLen = strlen(pData);
printf("original text: %s\n\n", pData);
/* shift cipher */
printf("移位密码:\n");
ShiftCipher(15, pData, nLen);
printf("cipher text: %s\n", pData);
ShiftCipher(15, pData, nLen, false);
printf("plain text: %s\n", pData);
/* 代换密码 */
printf("\n\n代换密码:\n");
SubstitutionCipher(pData, nLen);
printf("cipher text: %s\n", pData);
SubstitutionCipher(pData, nLen, false);
printf("plain text: %s\n", pData);
/* 仿射密码 */
int a = 11, b = 9;
printf("\n\n仿射密码:\n");
AffineCipher(a, b, pData, nLen);
printf("cipher text: %s\n", pData);
AffineCipher(a, b, pData, nLen, false);
printf("plain text: %s\n", pData);
/* 维吉尼亚密码 */
int pnKey[] = {3, 2, 5, 1};
int nKenLen = 4;
printf("\n\n维吉尼亚密码:\n");
VigenreCipher(pnKey, nKenLen, pData, nLen);
printf("cipher text: %s\n", pData);
VigenreCipher(pnKey, nKenLen, pData, nLen, false);
printf("plain text: %s\n", pData);
/* 希尔密码 */
int pnHillKey[] = {11, 8, 3, 7};
char pHillData[] = "hustfisher";
nLen = strlen(pHillData);
printf("\n\n希尔密码:\n");
printf("original text: %s\n", pHillData);
HillCipher(pnHillKey, pHillData, nLen);
printf("cipher text: %s\n", pHillData);
HillCipher(pnHillKey, pHillData, nLen, false);
printf("plain text: %s\n", pHillData);
/* 置换密码 */
int pnPermuKey[] = {5, 3, 2, 1, 4};
char pPermuData[] = "hello, new a world !";
int nPermuKeyLen = sizeof(pnPermuKey)/sizeof(pnPermuKey[0]);
nLen = strlen(pPermuData);
printf("\n\n置换密码:\n");
printf("original text: %s\n", pPermuData);
PermutationCipher(pnPermuKey, nPermuKeyLen, pPermuData, nLen);
printf("cipher text: %s\n", pPermuData);
PermutationCipher(pnPermuKey, nPermuKeyLen, pPermuData, nLen, false);
printf("plain text: %s\n", pPermuData);
return 0;
}