古典密碼學

  • 古典密碼學種類


  • 移位密碼(凱撒密碼)

    對於一個密碼體制,必須知足必定的條件,下面所述的兩個條件必須的:
  
  
  
  
    1. 對於加密體制而言,其加解密函數都要易於計算
    2. 對於任何敵手而言,即便他獲取了密文Y,也很難由此肯定出對應的密鑰K或密文
    移位密碼屬於最簡單的一種加密方法,其實現和原理都很簡單,可是因爲自己的問題,其密鑰空間很小,並且又屬於單表替換,因此安全性不高,易受來自窮舉
以及詞頻等簡單的密碼攻擊破解.

  • 代換密碼

代換密碼也屬於單表替換,其原理很簡單,先製做出一張替換的表格,而後加密時根據表格替換明文,解密的時候,須要先製做出解密的替換表格,這個表格和 加密表格是對應的,對於26個字母而言,全部可能的替換方法達到26!種,密鑰空間很大,因此利用窮舉法不是很容易破解.可是,因爲這種加密算法仍然屬於單表替 換,因此仍然不能抵抗根據詞頻來破解密碼這種方法.

  • 仿射密碼

仿射密碼是移位密碼的擴展,仿射密碼是利用線性函數的一一對應的原理來實現的,其加密函數爲e(x)=(ax+b) mod nMax (nMax爲常數).對於加密函數而言,算法

其中的a是有限制的,須要a和nMax的最大公約數爲1. 對於a的取值空間大小,能夠由nMax的值計算出來,其值爲φ(nMax)可由歐拉公式得到,因此其密鑰空間大小安全

爲nMax*φ(nMax).ide

對於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的乘法逆.spa

因爲仿射密碼仍然屬於單表替換,因此不容易抵抗來自根據詞頻的密碼攻擊..net


  • 維吉利亞密碼

維吉利亞密碼採用的是循環使用密鑰串來來加解密,屬於多表替換,可是因爲密鑰長度通常有限,因此根據窮舉密鑰長度以及利用詞頻攻擊仍然比較容易破解該類密碼.code

  • 希爾密碼

希爾密碼採用引入矩陣來加解密,其密鑰空間大,沒有單表替換的特色,因此通常的密碼的安全性比較高,不易受到來自窮舉以及根據詞頻破解的攻擊.可是,其實現方blog

法比較複雜,須要考慮矩陣的特性(可逆?),又須要求得加密矩陣的逆矩陣.ip

  • 置換密碼

置換密碼和前面的加解密方法相差比較大,加解密的時候不會改變處理數據的總體內容,只是調整數據的順序以達到加密效果.因爲只是改變順序,因此不易受到來

自根據詞頻的密碼攻擊.對於密鑰長度爲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      : http://blog.csdn.net/jiejiaozhufu
 *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;
}
相關文章
相關標籤/搜索