算法实现: OTP(One-Time Pad) 一次一密密码本 加解密

按照<<密码学导引>>上描述的OTP算法, 实现了一个OTP算法加解密工具~


src : srcOtpCipher_V2013_0111_0517.rar, 这版的明文只能是 'a'~'z', 以后会改成支持所有可见的Asiic字符.

src: srcOtpCihper_V2013_0111_2317.rar, 变形OTP算法, 支持可见Ascii字符集.

编译环境: win7X64Sp1 + vs2008Sp1


<2013_0111_2251>

将Cipher\Otp\OtpCipherConst.h 中的常量改了, 支持了可见Ascii字符集, 已经可以作为一个玩具使用.

从需求的变化到程序修改的实际效果中可以体会到宏的好处~

/// @file			OtpCipherConst.h
/// @brief			OtpCihper常量定义

#ifndef __OTP_CIPHER_CONST_H__
#define __OTP_CIPHER_CONST_H__

/// @ref http://www.dreamdu.com/xhtml/ascii/
/// 32 ~ 126 是可以打印的字符
#define OTP_FIRST_CHAR_W		L' ' ///< 字符集中第一个字符
#define OTP_LAST_CHAR_W			L'~' ///< 字符集中最后一个字符

#define OTP_FIRST_CHAR			' ' ///< 字符集中第一个字符
#define OTP_LAST_CHAR			'~' ///< 字符集中最后一个字符
#define OTP_MOD					(OTP_LAST_CHAR - OTP_FIRST_CHAR + 1)
#define OTP_FIRST_INDEX			1
#define OTP_LAST_INDEX			OTP_MOD

#define SZ_FILE_NAME_PLAINTEXT	L"OtpPlaintext.txt"
#define SZ_FILE_NAME_OTP_KEY	L"OtpKey.txt"
#define SZ_FILE_NAME_CIPHERTEXT	L"OtpCiphertext.txt"

/// 算法说明
#define SZ_ALG_README	L"算法说明\r\n"\
	L"OTP算法是一次一密的算法\r\n"\
	L"变形的算法支持可见Ascii字符集\r\n"\
	L"明文是' '~'~'的小写字母, 数组为x, 长度为N\r\n"\
	L"密钥是' '~'~'的小写字母, 数组为k, 长度为N\r\n"\
	L"OTP变形加密算法:\r\n"\
	L"模M = '~' - ' '\r\n"\
	L"EK(x) = ((x1 + k1)%M,(x2 + k2)%M,...(xn + kn)%M)\r\n"\
	L"OTP解密算法:\r\n"\
	L"DK(x) = ((x1 - k1)%M,(x2 - k2)%M,...(xn - kn)%M)\r\n"\
	L"\r\n"\
	L"变形后的OTP算法有效字符集为可见Ascii字符, 从' '~'~'\r\n"

#endif	// #ifndef __OTP_CIPHER_CONST_H__



效果图

算法实现: OTP(One-Time Pad) 一次一密密码本 加解密_第1张图片

新的算法说明

算法实现: OTP(One-Time Pad) 一次一密密码本 加解密_第2张图片


<2013_0110>

算法说明:

算法实现: OTP(One-Time Pad) 一次一密密码本 加解密_第3张图片

OTP加密:

算法实现: OTP(One-Time Pad) 一次一密密码本 加解密_第4张图片

OTP解密:

算法实现: OTP(One-Time Pad) 一次一密密码本 加解密_第5张图片

从使用角度, 考虑了以下几点:

* 加密前的明文输入方式: 手工输入明文, 载入明文文件.

* 加密时的OTP密码自动生成.

* 加密后的文件保存(保存明文,密钥,密文).

* 解密前的密文输入方式: 手工输入密文, 载入密文文件.

* 解密前的密钥输入方式: 载入密钥文件.

* 解密后的文件保存(保存明文)

* 考虑到解密时,一般是直接使用密文和密钥文件, 而不会手工输入, 特别是密文较长时的情况.


/// @todo 原版OTP的明文内容只能是小写字母(a~z), 这不实用, 稍后要改成支持全部ascii字符,

/// 这样, 英文较好的使用者,就可以将这个工具作为一个实用工具.


直接按照书里描述的OTP算法, 解密不准确. 要处理一些细节.

e.g.  明文是'a', 密钥是'z', 加密和解密都要处理. 直接按照公式来行不通~


Otp加解密接口的实现如下:

/// @file			OtpCipherConst.h
/// @brief			OtpCihper常量定义

#ifndef __OTP_CIPHER_CONST_H__
#define __OTP_CIPHER_CONST_H__

#define OTP_FIRST_CHAR_W		L'a' ///< 字符集中第一个字符
#define OTP_LAST_CHAR_W			L'z' ///< 字符集中最后一个字符

#define OTP_FIRST_CHAR			'a' ///< 字符集中第一个字符
#define OTP_LAST_CHAR			'z' ///< 字符集中最后一个字符
#define OTP_MOD					(OTP_LAST_CHAR - OTP_FIRST_CHAR + 1)
#define OTP_FIRST_INDEX			1
#define OTP_LAST_INDEX			OTP_MOD

#define SZ_FILE_NAME_PLAINTEXT	L"OtpPlaintext.txt"
#define SZ_FILE_NAME_OTP_KEY	L"OtpKey.txt"
#define SZ_FILE_NAME_CIPHERTEXT	L"OtpCiphertext.txt"

/// 算法说明
#define SZ_ALG_README	L"算法说明\r\n"\
	L"OTP算法是一次一密的算法\r\n"\
	L"明文是a~z的小写字母, 数组为x, 长度为N\r\n"\
	L"密钥是a~z的小写字母, 数组为k, 长度为N\r\n"\
	L"OTP加密算法:\r\n"\
	L"EK(x) = ((x1 + k1)%26,(x2 + k2)%26,...(xn + kn)%26)\r\n"\
	L"OTP解密算法:\r\n"\
	L"DK(x) = ((x1 - k1)%26,(x2 - k2)%26,...(xn - kn)%26)\r\n"

#endif	// #ifndef __OTP_CIPHER_CONST_H__


/// @file			OtpCipher.h
/// @brief			OtpCihper函数定义

#ifndef __OTP_CIPHER_H__
#define __OTP_CIPHER_H__

#include "OtpCipherConst.h"
#include <tchar.h>
#include <string>

/// @fn			isValidPlaintext
/// @brief		判断明文内容是否有效
/// @param		IN const wchar_t * pcPlaintextW, 明文
/// @return		boolen
/// @retval		true, 明文有效
/// @retval		false, 明文无效, 有非法字符
bool isValidPlaintext(IN const wchar_t * pcPlaintextW);

/// @fn			isValidChar
/// @brief		给定的字符是否是有效的明文内容
/// @param		IN char cIn, 给定的字符
/// @return		boolen
/// @retval		true, 入参字符有效
/// @retval		false, 入参字符无效, 不是有效明文字符集中的字符
bool isValidChar(IN char cIn);

char char2Index(char cParam);
char Index2Char(char cParam);
char OtpModX(int iParam, char cMod);

/// @fn			GenerateOtpKey
/// @brief		产生Otp密钥
/// @param		IN const wchar_t * pcPlaintextW, 明文
/// @param		OUT std::wstring & strOtpKeyW, 根据明文长度生成的等长度密钥
/// @return		boolen
/// @retval		true, 密钥产生成功
/// @retval		false, 密钥产生失败
bool GenerateOtpKey(IN const wchar_t * pcPlaintextW, OUT std::wstring & strOtpKeyW);

/// @fn			OtpCipher
/// @brief		Otp加解密
/// @param		IN bool bEncrypt, 是加密还是解密, true = 加密, false = 解密
/// @param		IN OUT std::string & strPlaintext, 明文
/// @param		IN const char * pcOtpKey, 密钥
/// @param		IN OUT std::string & strCiphertext, 密文
bool OtpCipher(IN bool bEncrypt, 
			   IN OUT std::string & strPlaintext, 
			   IN const char * pcOtpKey, 
			   IN OUT std::string & strCiphertext);

#endif	// #ifndef __OTP_CIPHER_H__


/// @file			OtpCipher.cpp
/// @brief			OtpCihper函数实现

#include "stdafx.h"
#include "OtpCipher.h"
#include "Helper/string/stringHelper.h"

bool isValidPlaintext(IN const wchar_t * pcPlaintextW)
{
	std::string				strPlaintextA;
	std::string::iterator	it;

	if(NULL == pcPlaintextW)
		return false;

	Wstring2String(strPlaintextA, pcPlaintextW);
	for(it = strPlaintextA.begin(); it != strPlaintextA.end(); it++)
	{
		if(!isValidChar(*it))
			return false;
	}

	return true;
}

bool isValidChar(IN char cIn)
{
	return (cIn >= OTP_FIRST_CHAR) && (cIn <= OTP_LAST_CHAR);
}

bool GenerateOtpKey(IN const wchar_t * pcPlaintextW, OUT std::wstring & strOtpKeyW)
{
	bool		bPassFirstRand	=	true;
	size_t		nLen			=	0;
	wchar_t		cRandW			=	'\0';

	std::string	strPlaintextA;

	strOtpKeyW = L"";
	if (NULL == pcPlaintextW)
		return false;

	srand(static_cast<UINT>(time(NULL)));

	Wstring2String(strPlaintextA, pcPlaintextW);
	nLen = strPlaintextA.length();

	while (0 != nLen--)
	{
		cRandW = OTP_FIRST_CHAR_W - 1 + RangedRand(OTP_FIRST_INDEX, OTP_LAST_INDEX, bPassFirstRand);
		bPassFirstRand = false;
		strOtpKeyW += cRandW;
	}

	return true;
}

char char2Index(char cParam)
{
	return cParam - OTP_FIRST_CHAR + 1;
}

char Index2Char(char cParam)
{
	/// 字符集中最后一个字符的索引是0
	return (cParam >= 1) ? (cParam - 1 + OTP_FIRST_CHAR) : OTP_LAST_CHAR;
}

char OtpModX(int iParam, char cMod)
{
	if (iParam < 0)
		iParam += cMod; ///< 防止 iParam < 0, e.g. ('a' - 'z') % 26

	return static_cast<char>(iParam % cMod);
}

bool OtpCipher(IN bool bEncrypt, 
			   IN OUT std::string & strPlaintext, 
			   IN const char * pcOtpKey, 
			   IN OUT std::string & strCiphertext)
{
	char					cTmp	=	'\0';
	char					cX		=	'\0';
	char					cK		=	'\0';
	size_t					nIndex	=	0;
	std::string::iterator	it;

	if ((NULL == pcOtpKey)
		|| (bEncrypt && (strlen(strPlaintext.c_str()) != strlen(pcOtpKey)))
		|| (!bEncrypt && (strlen(strCiphertext.c_str()) != strlen(pcOtpKey))))
	{
		return false;
	}

	if (bEncrypt)
	{
		/// OTP加密算法:
		/// EK(x) = ((x1 + k1)%26,(x2 + k2)%26,...(xn + kn)%26)
		strCiphertext = "";
		for (it = strPlaintext.begin(); it != strPlaintext.end(); it++)
		{
			cX = char2Index(*it);
			cK = char2Index(*(pcOtpKey + nIndex++));
			cTmp = OtpModX(cX + cK, OTP_MOD);
			strCiphertext += Index2Char(cTmp);
		}
	}
	else
	{
		/// OTP解密算法:
		/// DK(x) = ((x1 - k1)%26,(x2 - k2)%26,...(xn - kn)%26)
		strPlaintext = "";
		for (it = strCiphertext.begin(); it != strCiphertext.end(); it++)
		{
			cX = char2Index(*it);
			cK = char2Index(*(pcOtpKey + nIndex++));
			cTmp = OtpModX(cX - cK, OTP_MOD);
			strPlaintext += Index2Char(cTmp);
		}
	}

	return true;
}

<2013_0112_1033>

OTP加密的好处: 多表替换.

多表替换: 在整个消息中, 同一个字符通常不会被加密成同一个字符.

你可能感兴趣的:(算法实现: OTP(One-Time Pad) 一次一密密码本 加解密)