一个玩具程序——测试密码强度(pure C)
替人写的C语言作业…
介绍:
程序名称:
密码强度检测程序
注释风格:
doxygen
测试环境:
linux3.6, gcc4.7
window7, vs2012
已知问题:
1. 算法与参考链接不一致,结果会有差别,详见代码注释。
2. 在vs下可能会编译不通过,将后缀改为cpp就可以了。vs的C编译器实现对C90支持不佳,gcc4.5以上可以正常编译通过。
1 #ifndef CHECKPASS_H_INCLUDED 2 #define CHECKPASS_H_INCLUDED 3 4 /*! 5 * \brief 本程序用于检测密码强度 6 * \details 请根据提示输入密码,程序会自动输出对应的强度 7 * 8 * 程序会根据是否满足一定的条件对密码进行打分,然后区分出档次。 9 * 得分最低0分,最高100分;等级分为很弱-弱-一般-好-强-极强几个档次。 10 * 判断标准(参考[链接](http://goo.gl/wuQdN): 11 * 1. 最低要求包括 12 * * 长度>8位 13 * * 以下四种元素至少有三种: 14 * - 大写英文字母 15 * - 小写英文字母 16 * - 数字 17 * - 特殊符号 18 * 2. 加分条件 19 * * 密码总字数 +(次数*4) 20 * * 大写字母数 +(长度-字数)*2 [字数必须>0] 21 * * 小写字母数 +(长度-字数)*2 [同上] 22 * * 数字个数 +(次数*4) 23 * * 特殊符号数 +(次数*6) 24 * * 数字或符号出现在密码中间部分 +(次数*2) 25 * * 达到最低需求 +(次数*2) 26 * 3. 减分条件 27 * * 只有字母 -次数 28 * * 只有数字 -次数 29 * * 出现重复单元,对每个重复的字符 -次数*(次数-1) [不计大小写] 30 * * 连续大写字母 -次数*2 31 * * 连续小写字母 -次数*2 32 * * 连续多个数字 -次数*2 33 * * 字母顺序递增/减(三个及以上) -次数*3 34 * * 数字顺序递增/减(三个及以上) -次数*3 35 * 36 * \author 37 * \date 2013-06-22 38 * \copyright GNU Public License 39 */ 40 41 /** 字符数目,取char的最大值+1*/ 42 #define CHARNUM 256 43 44 /** 强度评价*/ 45 extern const char *g_pPasswordLevel[]; 46 47 /** 强度枚举*/ 48 typedef enum _PasswordLevel { 49 VERYWEEK, 50 WEEK, 51 AVERAGE, 52 GOOD, 53 STRONG, 54 VERYSTRONG 55 } PasswordLevel; 56 57 58 /** 计算得分需要的参数*/ 59 typedef struct _RuleParameter { 60 int nLength; ///< 密码长度 61 int nUpper; ///< 大写字母个数 62 int nLower; ///< 小写字母个数 63 int nDigit; ///< 数字个数 64 int nSymbol; ///< 特殊字符个数 65 int nMidDigitSymbol; ///< 中间部分的数字或字符个数 66 int nRequirement; ///< 达到最低需求的次数 67 int RepeatChar[CHARNUM]; ///< 每个字符重复的次数 68 int nConsecUpper; ///< 连续大写字母个数 69 int nConsecLower; ///< 连续小写字母个数 70 int nConsecDigit; ///< 连续数字个数 71 int nSequence; ///< (三个及以上)顺序字母/数字次数 72 } RuleParameter; 73 74 /** 75 * \brief 求密码得分 76 * \param[in] password 密码 77 * \return 得分 78 */ 79 int GetPasswordScore(const char *password); 80 81 /** 82 * \brief 求密码等级 83 * \param[in] password 密码得分 84 * \return 密码等级 85 */ 86 PasswordLevel GetPasswordLevel(int score); 87 88 89 #endif // CHECKPASS_H_INCLUDED
1 #include "checkPass.h" 2 3 #include <stdlib.h> 4 #include <string.h> 5 #include <ctype.h> 6 7 /** 强度评价*/ 8 const char *g_pPasswordLevel[]= { 9 "很弱", 10 "弱", 11 "一般", 12 "好", 13 "强", 14 "很强" 15 }; 16 17 /** 18 * \defgroup prototypes 19 * @{ 20 */ 21 22 /** 23 * \brief 负责调用其他计算函数,填充了长度字段 24 * \param[in] password 密码 25 * \param[out] rp 待填充的规则参数结构指针 26 */ 27 void beginProcess(const char *password,RuleParameter *rp); 28 29 /** 30 * \brief 填充大写、小写、数字、符号及他们的连续值字段 31 * \param[in] password 密码 32 * \param[out] rp 待填充的规则参数结构指针 33 */ 34 void countNumbers(const char *password,RuleParameter *rp); 35 36 /** 37 * \brief 填充连续递增/减字符的个数字段 38 * \param[in] password 密码 39 * \param[out] rp 待填充的规则参数结构指针 40 */ 41 void countSeqNumbers(const char *password,RuleParameter *rp); 42 43 /** 44 * \brief 填充重复单元字段 45 * \param[in] password 密码 46 * \param[out] rp 待填充的规则参数结构指针 47 */ 48 void countRepeat(const char *password, RuleParameter *rp); 49 50 /** 51 * \brief 计算密码得分 52 * \param[in] rp 已经填充的规则参数结构指针 53 * \return 得分 54 */ 55 int countScore(const RuleParameter *rp); 56 57 /** @}*/ 58 59 PasswordLevel GetPasswordLevel(int score) 60 { 61 if(score<20) { 62 return VERYWEEK; 63 } 64 if(score<40) { 65 return WEEK; 66 } 67 if(score<60) { 68 return AVERAGE; 69 } 70 if(score<80) { 71 return STRONG; 72 } 73 return VERYSTRONG; 74 } 75 76 int GetPasswordScore(const char *password) 77 { 78 RuleParameter rp= {0}; 79 beginProcess(password,&rp); 80 return countScore(&rp); 81 } 82 83 void beginProcess(const char *password,RuleParameter *rp) 84 { 85 if(password==NULL || rp==NULL) return; 86 87 int i,j; 88 89 char *pass_nospace=(char *)malloc(strlen(password)+1); 90 char *pass_nospace_lower=(char *)malloc(strlen(password)+1); 91 92 if(!pass_nospace) exit(EXIT_FAILURE); 93 94 for(i=0,j=0; password[i]!='\0'; i++) { 95 if(!isspace(password[i])) { 96 pass_nospace[j]=password[i]; 97 pass_nospace_lower[j]=tolower(password[i]); 98 ++j; 99 } 100 } 101 pass_nospace[j]='\0'; 102 103 rp->nLength=strlen(pass_nospace); 104 105 countRepeat(pass_nospace_lower,rp); 106 countNumbers(pass_nospace,rp); 107 countSeqNumbers(pass_nospace,rp); 108 109 free(pass_nospace); 110 free(pass_nospace_lower); 111 } 112 113 void countRepeat(const char *password, RuleParameter *rp) 114 { 115 if(!password || !rp)return; 116 117 int i; 118 for(i=0; i<rp->nLength; i++) { 119 ++rp->RepeatChar[password[i]]; 120 } 121 } 122 123 void countNumbers(const char *password, RuleParameter *rp) 124 { 125 if(!password || !rp)return; 126 127 int i; 128 int last_upper_pos=-1; 129 int last_lower_pos=-1; 130 int last_digit_pos=-1; 131 132 for(i=0; i<rp->nLength; i++) { 133 if(isupper(password[i])) { 134 if(last_upper_pos!=-1 && last_upper_pos+1==i) { 135 ++rp->nConsecUpper; 136 } 137 last_upper_pos=i; 138 ++rp->nUpper; 139 } else if(islower(password[i])) { 140 if(last_lower_pos!=-1 && last_lower_pos+1==i) { 141 ++rp->nConsecLower; 142 } 143 last_lower_pos=i; 144 ++rp->nLower; 145 } else if(isdigit(password[i])) { 146 if(last_digit_pos!=-1 && last_digit_pos+1==i) { 147 ++rp->nConsecDigit; 148 } 149 if(i>0 && i< rp->nLength-1) { 150 ++rp->nMidDigitSymbol; 151 } 152 last_digit_pos=i; 153 ++rp->nDigit; 154 } else { 155 if(i>0 && i<rp->nLength-1) { 156 ++rp->nMidDigitSymbol; 157 } 158 ++rp->nSymbol; 159 } 160 } 161 162 if(rp->nLower>0) ++rp->nRequirement; 163 if(rp->nUpper>0) ++rp->nRequirement; 164 if(rp->nDigit>0) ++rp->nRequirement; 165 if(rp->nSymbol>0) ++rp->nRequirement; 166 } 167 168 /** 169 * \note 注意,此处计算重复数字的算法与参考链接处并不相同! 170 * 经过反复测试,参考链接中测试算法与其描述并不相符, 171 * 此处的实现中,字符不能同时被统计在上升序列和下降序列中! 172 */ 173 void countSeqNumbers(const char *password,RuleParameter *rp) 174 { 175 if(!password || !rp || rp->nLength<3)return; 176 177 int inc_count=1; 178 int dec_count=1; 179 int i=1; 180 181 for(; i<rp->nLength; i++) { 182 if(isalnum(password[i]) && isalnum(password[i-1])) { 183 if(password[i]-password[i-1]==1) { 184 if(dec_count<3)++inc_count; 185 dec_count=1; 186 } else if(password[i]-password[i-1]==-1) { 187 if(inc_count<3)++dec_count; 188 inc_count=1; 189 } else { 190 inc_count=dec_count=1; 191 } 192 } else { 193 inc_count=dec_count=1; 194 } 195 196 if(inc_count>=3 || dec_count>=3) { 197 ++rp->nSequence; 198 } 199 } 200 } 201 202 int countScore(const RuleParameter *rp) 203 { 204 if(!rp || rp->nLength==0)return 0; 205 206 int score=0; 207 int i; 208 int n; 209 210 score+=rp->nLength * 4; 211 if(rp->nUpper!=0)score+=(rp->nLength - rp->nUpper) *2; 212 if(rp->nLower!=0)score+=(rp->nLength - rp->nLower) *2; 213 if(rp->nLength!=rp->nDigit)score+=rp->nDigit *4; 214 score+=rp->nSymbol *6; 215 score+=rp->nMidDigitSymbol *2; 216 if(rp->nLength>=8 && rp->nRequirement>=3) { 217 score+=(rp->nRequirement+1)*2; 218 } 219 220 if(rp->nDigit==rp->nLength || rp->nLower+rp->nUpper==rp->nLength) 221 score-=rp->nLength; 222 223 for(i=0; i<CHARNUM; ++i) { 224 n=rp->RepeatChar[i]; 225 if(n>1) { 226 score-=n*(n-1); 227 } 228 } 229 score-=rp->nConsecDigit * 2; 230 score-=rp->nConsecLower *2; 231 score-=rp->nConsecUpper *2; 232 score-=rp->nSequence *3; 233 234 if(score<0) score=0; 235 if(score>100) score=100; 236 return score; 237 }
1 #include <stdio.h> 2 #include "checkPass.h" 3 4 /**缓冲区最大长度*/ 5 # define BUFFERLEN 1000 6 7 int main() 8 { 9 char password[BUFFERLEN]; 10 int score; 11 PasswordLevel level; 12 13 while(1) { 14 printf("请输入密码:\n"); 15 if(fgets(password,BUFFERLEN,stdin)==NULL)continue; 16 17 score=GetPasswordScore(password); 18 level=GetPasswordLevel(score); 19 20 printf("该密码得分为 %d, 评价为 %s\n",score,g_pPasswordLevel[level]); 21 } 22 return 0; 23 }