按照<<密码学导引>>上描述的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__
效果图
新的算法说明
<2013_0110>
OTP加密:
OTP解密:
从使用角度, 考虑了以下几点:
* 加密前的明文输入方式: 手工输入明文, 载入明文文件.
* 加密时的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加密的好处: 多表替换.
多表替换: 在整个消息中, 同一个字符通常不会被加密成同一个字符.