背景知识
(1)口令字段信息的处理方法
① 接收用户提供的口令Dpw ;
② 生成一个盐值:Dsalt=Arandom( ) ;
③ 生成口令信息:s=Agen(Dsalt,Dpw) ;
④ 把口令信息s 和Dsalt 存入数据库的口令字段中。
(2)口令字段信息的生成算法
① 给口令Dpw 撒盐:Dpw=Asalt(Dsalt,Dpw) ;
② 用撒盐结果做密钥:K=Dpw ;
③ 用一个64 位的全0 的二进制位串构造一个数据块Dp ;
④ 设循环次数初值:i=0 ;
⑤ 对数据块加密:Dc=Acrypt(K,Dp) ;
⑥ Dp=Dc, i=i+1 ;
⑦ 如果i<25 ,则回到⑤;
⑧ 把数据块变换成字符串:s=Atrans(Dc) ;
⑨ 返回s 。
(3)给口令撒盐的算法
① 把盐值附加到口令上:Dtmp=Dpw||Dsalt ;
② 生成哈希值:Dhash=Ahash(Dtmp) ;
③ 以Dhash 作为返回结果。
(4)身份认证算法
① 接收用户提供的账户名Dname 和口令Dpw ;
② 在账户信息数据库中检查Dname 的合法性,如果合法,则找出其对
应的s 和Dsalt ;
③ 生成临时口令信息:sr=Agen(Dsalt,Dpw) ;
④ 如果sr=s ,则认证成功,否则,认证失败。
具体操作过程
编写代码pwprocessing.py
import random import string #给口令加盐 def addsalt(salt, pw): print("Adding salt...") pw = pw + salt print("Salt added.") return hash(pw) #加密的实现 def ecrypt(dp, key, i): print("Ecrypting data using your password...(round " + str(i+1) + ")") for i in range(0, len(dp)): index = i % len(key) if(key[index] == '-'): dp[i] = str(int(dp[i]) % 10) else: dp[i] = str((int(dp[i]) + int(key[index])) % 10) return dp #口令字段信息的生成算法 def generate(salt, pw): print("Generating data ecrypted by your password...") #给口令Dpw 撒盐,用撒盐结果做密钥 saltedpw = str(addsalt(salt, pw)) dp = [] #用一个64 位的全0 的二进制位串构造一个数据块 for i in range(0, 64): dp.append('0') #对数据块加密 for i in range(0, 25): dp = ecrypt(dp, saltedpw, i) print("Data ecrypted by your password generated.") return dp #创建用户 def createuser(database): print("Creating user...") print("Input 'q' as username if you want to quit.") while(1): name = input("username: ") if name == 'q': break pw = input("password: ") salt = ''.join(random.sample(string.ascii_letters + string.digits, 8)) s = generate(salt, pw) dic = {} dic['name'] = name dic['salt'] = salt dic['pw'] = s database.append(dic) print("User " + name + " is created.") #直接通过字典匹配用户,检查此用户是否存在 def has_user(database, name): for dic in database: if dic['name'] == name: return 1 return 0 #得到用户的具体信息 def get_info(database, name): for dic in database: if dic['name'] == name: salt = dic['salt'] s = dic['pw'] return salt, s #身份认证算法 def authenticate(database): print("Authenticating user...") print("Input 'q' as username if you want to quit.") while(1): #接收用户提供的账户名Dname ; name = input("username: ") if name == 'q': break flag = has_user(database, name) if flag == 0: print("Sorry, user " + name + " does not exist.") continue #接受用户提供的口令 pw = input("password: ") #在账户信息数据库中检查Dname 的合法性,如果合法,则找出其对 #应的s 和Dsalt salt, s = get_info(database, name) #生成临时口令信息 sr = generate(salt, pw) print("Comparing ecrypted data...") if(s == sr): print("User " + name + " authenticated.") else: print("Sorry, the password is wrong.") database = [] createuser(database) authenticate(database)
创建用户
① 创建第一个用户”csz”,密码为”csz”
② 创建第二个用户”cy”,密码为”cy”
验证用户
① 输入不存在的用户名”feng”
② 输入用户名”csz”和正确的密码”csz”
③ 输入用户名”cy”和错误的密码”521”
③ 输入用户名”cy”和正确的密码”cy”
c++ 实现如下,但思路不同,注意 c++编译时把"-std=c++11"修改为"-std=gnu++0x"
otp.cpp
#include "md5.h" #include<iostream> #include<string> #include<stdlib.h> #include<time.h> #include<fstream> using namespace std; struct inf //系统用户存储信息结构 { char uid[50]; //用户名 int r; //挑战值 char answer[50]; //应答值 char password[50]; //密码 }; inf infor[300]; int n=0; void init() { char uid[50],answer[50],password[50]; int r; fstream file; file.open("lib.txt",ios::in); if(!file); else { while(file>>uid>>r>>answer>>password) { strcpy(infor[n].uid,uid); infor[n].r=r; strcpy(infor[n].answer,answer); strcpy(infor[n].password,password); n++; } } file.close(); } void reg() { char uid[50],password1[50],password2[50],ans[100]={0},answer[50]; int r,i; while(1) { cout<<"请输入用户名: "; cin>>uid; for(i=0;i<n;i++) if(strcmp(infor[i].uid,uid)==0) { cout<<endl<<"该用户名已存在!"<<endl<<endl; break; } if(i==n) break; } while(1) { cout<<"请输入密码: "; cin>>password1; cout<<"请再次输入密码: "; cin>>password2; if(strcmp(password1,password2)==0) break; else { cout<<endl<<"两次密码不一致!"<<endl<<endl; } } srand(time(0)); r=rand(); infor[n].r=r; i=0; while(r!=0) { ans[i]=r%10+'0'; r/=10; i++; } strcat(ans,password1); strcpy(answer,MD5String(ans)); strcpy(infor[n].uid,uid); strcpy(infor[n].answer,answer); strcpy(infor[n].password,password1); n++; cout<<endl<<"用户注册成功!"<<endl<<endl; system("pause"); system("cls"); } void check() { char uid[50],answer[50],ans[100]={0}; int r,i,j; char ch; cout<<"请输入用户名: "; cin>>uid; for(i=0;i<n;i++) { if(strcmp(infor[i].uid,uid)==0) { cout<<"挑战值为: "<<infor[i].r<<endl; cout<<"是否返回进行应答值计算(y/n): "; cin>>ch; if(ch=='y') cout<<endl; else if(ch=='n') { cout<<"请输入应答值: "; cin>>answer; if(strcmp(answer,infor[i].answer)==0) { cout<<endl<<"认证通过!"<<endl<<endl; srand(time(0)); r=rand(); infor[i].r=r; j=0; while(r!=0) { ans[j]=r%10+'0'; r/=10; j++; } strcat(ans,infor[i].password); strcpy(infor[i].answer,MD5String(ans)); } else cout<<endl<<"认证失败!"<<endl<<endl; } else cout<<endl<<"输入错误!"<<endl<<endl; break; } } if(i==n) cout<<endl<<"该用户名不存在!"<<endl<<endl; system("pause"); system("cls"); } void compute() { char password[50],answer[50],ans[100]={0}; int r,i; cout<<"请输入挑战值: "; cin>>r; cout<<"请输入密码: "; cin>>password; i=0; while(r!=0) { ans[i]=r%10+'0'; r/=10; i++; } strcat(ans,password); strcpy(answer,MD5String(ans)); cout<<endl<<"应答值为: "<<answer<<endl<<endl; system("pause"); system("cls"); } int main() { char ch; int i; init(); while(1) { cout<<endl; cout<<" 1.用户注册"<<endl<<endl <<" 2.身份认证"<<endl<<endl <<" 3.口令计算"<<endl<<endl <<" 0.退出"<<endl<<endl; cout<<"请选择: "; cin>>ch; cout<<endl; if(ch=='0') break; switch(ch) { case '1': reg(); break; //用户注册 case '2': check(); break; //身份认证 case '3': compute(); break; //口令计算 default: cout<<"输入错误!"<<endl; system("pause"); system("cls"); } } fstream f; f.open("lib.txt",ios::out); for(i=0;i<n;i++) f<<infor[i].uid<<' '<<infor[i].r<<' '<<infor[i].answer<<' '<<infor[i].password<<endl; return 1; }
md5.h
#ifndef HEADER_FILE #define HEADER_FILE #include <assert.h> #include <stdio.h> #include <string.h> typedef unsigned int uint4; typedef unsigned short int uint2; typedef unsigned char uchar; uint4 m_State[4]; uint4 m_Count[2]; uchar m_Buffer[64]; uchar m_Digest[16]; uchar m_Finalized; char* PrintMD5(uchar md5Digest[16]); char* MD5String(char* szString); char* MD5File(char* szFilename); void Init(); void Update(uchar* chInput, uint4 nInputLen); void Finalize(); uchar* Digest() { return m_Digest; } void Transform(uchar* block); void Encode(uchar* dest, uint4* src, uint4 nLength); void Decode(uint4* dest, uchar* src, uint4 nLength); inline uint4 rotate_left(uint4 x, uint4 n) { return ((x << n) | (x >> (32-n))); } inline uint4 F(uint4 x, uint4 y, uint4 z) { return ((x & y) | (~x & z)); } inline uint4 G(uint4 x, uint4 y, uint4 z) { return ((x & z) | (y & ~z)); } inline uint4 H(uint4 x, uint4 y, uint4 z) { return (x ^ y ^ z); } inline uint4 I(uint4 x, uint4 y, uint4 z) { return (y ^ (x | ~z)); } inline void FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { a += F(b, c, d) + x + ac; a = rotate_left(a, s); a += b; } inline void GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { a += G(b, c, d) + x + ac; a = rotate_left(a, s); a += b; } inline void HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { a += H(b, c, d) + x + ac; a = rotate_left(a, s); a += b; } inline void II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) { a += I(b, c, d) + x + ac; a = rotate_left(a, s); a += b; } static unsigned char PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #define S42 10 #define S43 15 #define S44 21 char* PrintMD5(uchar md5Digest[16]) { char chBuffer[256]; char chEach[10]; int nCount; memset(chBuffer,0,256); memset(chEach, 0, 10); for (nCount = 0; nCount < 16; nCount++) { sprintf(chEach, "%02x", md5Digest[nCount]); strncat(chBuffer, chEach, sizeof(chEach)); } return strdup(chBuffer); } char* MD5String(char* szString) { Init(); int nLen = strlen(szString); Update((unsigned char*)szString, (unsigned int)nLen); Finalize(); return PrintMD5(Digest()); } char* MD5File(char* szFilename) { FILE* file; int nLen; unsigned char chBuffer[1024]; try { memset(chBuffer, 0, 1024); if ((file = fopen (szFilename, "rb")) != NULL) { while (nLen = fread (chBuffer, 1, 1024, file)) Update(chBuffer, nLen); Finalize(); fclose (file); return PrintMD5(Digest()); } } catch(...) { } return NULL; // failed } void Init() { memset(m_Count, 0, 2 * sizeof(uint4)); m_State[0] = 0x67452301; m_State[1] = 0xefcdab89; m_State[2] = 0x98badcfe; m_State[3] = 0x10325476; } void Update(uchar* chInput, uint4 nInputLen) { uint4 i, index, partLen; // Compute number of bytes mod 64 index = (unsigned int)((m_Count[0] >> 3) & 0x3F); // Update number of bits if ((m_Count[0] += (nInputLen << 3)) < (nInputLen << 3)) m_Count[1]++; m_Count[1] += (nInputLen >> 29); partLen = 64 - index; // Transform as many times as possible. if (nInputLen >= partLen) { memcpy( &m_Buffer[index], chInput, partLen ); Transform(m_Buffer); for (i = partLen; i + 63 < nInputLen; i += 64) Transform(&chInput[i]); index = 0; } else i = 0; // Buffer remaining input memcpy( &m_Buffer[index], &chInput[i], nInputLen-i ); } void Finalize() { uchar bits[8]; uint4 index, padLen; // Save number of bits Encode (bits, m_Count, 8); // Pad out to 56 mod 64 index = (unsigned int)((m_Count[0] >> 3) & 0x3f); padLen = (index < 56) ? (56 - index) : (120 - index); Update(PADDING, padLen); // Append length (before padding) Update (bits, 8); // Store state in digest Encode (m_Digest, m_State, 16); memset(m_Count, 0, 2 * sizeof(uint4)); memset(m_State, 0, 4 * sizeof(uint4)); memset(m_Buffer,0, 64 * sizeof(uchar)); } void Transform (uchar* block) { uint4 a = m_State[0], b = m_State[1], c = m_State[2], d = m_State[3], x[16]; Decode (x, block, 64); // Round 1 FF (a, b, c, d, x[ 0], S11, 0xd76aa478); FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); FF (c, d, a, b, x[ 2], S13, 0x242070db); FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); FF (d, a, b, c, x[ 5], S12, 0x4787c62a); FF (c, d, a, b, x[ 6], S13, 0xa8304613); FF (b, c, d, a, x[ 7], S14, 0xfd469501); FF (a, b, c, d, x[ 8], S11, 0x698098d8); FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); FF (c, d, a, b, x[10], S13, 0xffff5bb1); FF (b, c, d, a, x[11], S14, 0x895cd7be); FF (a, b, c, d, x[12], S11, 0x6b901122); FF (d, a, b, c, x[13], S12, 0xfd987193); FF (c, d, a, b, x[14], S13, 0xa679438e); FF (b, c, d, a, x[15], S14, 0x49b40821); // Round 2 GG (a, b, c, d, x[ 1], S21, 0xf61e2562); GG (d, a, b, c, x[ 6], S22, 0xc040b340); GG (c, d, a, b, x[11], S23, 0x265e5a51); GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); GG (a, b, c, d, x[ 5], S21, 0xd62f105d); GG (d, a, b, c, x[10], S22, 0x2441453); GG (c, d, a, b, x[15], S23, 0xd8a1e681); GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); GG (d, a, b, c, x[14], S22, 0xc33707d6); GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); GG (b, c, d, a, x[ 8], S24, 0x455a14ed); GG (a, b, c, d, x[13], S21, 0xa9e3e905); GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); GG (c, d, a, b, x[ 7], S23, 0x676f02d9); GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); // Round 3 HH (a, b, c, d, x[ 5], S31, 0xfffa3942); HH (d, a, b, c, x[ 8], S32, 0x8771f681); HH (c, d, a, b, x[11], S33, 0x6d9d6122); HH (b, c, d, a, x[14], S34, 0xfde5380c); HH (a, b, c, d, x[ 1], S31, 0xa4beea44); HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); HH (b, c, d, a, x[10], S34, 0xbebfbc70); HH (a, b, c, d, x[13], S31, 0x289b7ec6); HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); HH (b, c, d, a, x[ 6], S34, 0x4881d05); HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); HH (d, a, b, c, x[12], S32, 0xe6db99e5); HH (c, d, a, b, x[15], S33, 0x1fa27cf8); HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); // Round 4 II (a, b, c, d, x[ 0], S41, 0xf4292244); II (d, a, b, c, x[ 7], S42, 0x432aff97); II (c, d, a, b, x[14], S43, 0xab9423a7); II (b, c, d, a, x[ 5], S44, 0xfc93a039); II (a, b, c, d, x[12], S41, 0x655b59c3); II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); II (c, d, a, b, x[10], S43, 0xffeff47d); II (b, c, d, a, x[ 1], S44, 0x85845dd1); II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); II (d, a, b, c, x[15], S42, 0xfe2ce6e0); II (c, d, a, b, x[ 6], S43, 0xa3014314); II (b, c, d, a, x[13], S44, 0x4e0811a1); II (a, b, c, d, x[ 4], S41, 0xf7537e82); II (d, a, b, c, x[11], S42, 0xbd3af235); II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); II (b, c, d, a, x[ 9], S44, 0xeb86d391); m_State[0] += a; m_State[1] += b; m_State[2] += c; m_State[3] += d; memset(x, 0, sizeof(x)); } void Encode(uchar* dest, uint4* src, uint4 nLength) { uint4 i, j; //assert(nLength % 4 == 0); for (i = 0, j = 0; j < nLength; i++, j += 4) { dest[j] = (uchar)(src[i] & 0xff); dest[j+1] = (uchar)((src[i] >> 8) & 0xff); dest[j+2] = (uchar)((src[i] >> 16) & 0xff); dest[j+3] = (uchar)((src[i] >> 24) & 0xff); } } void Decode(uint4* dest, uchar* src, uint4 nLength) { uint4 i, j; //assert(nLength % 4 == 0); for (i = 0, j = 0; j < nLength; i++, j += 4) { dest[i] = ((uint4)src[j]) | (((uint4)src[j+1])<<8) | (((uint4)src[j+2])<<16) | (((uint4)src[j+3])<<24); } } #endif;
编译运行结果如下