一个玩具程序——测试密码强度(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
checkPass.h
  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 }
checkPass.c
 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 }
main.c
posted @ 2013-06-24 12:28  生无所息  阅读(1068)  评论(0编辑  收藏  举报