一個玩具程序——測試密碼強度(pure C)

替人寫的C語言做業…linux

介紹:git

程序名稱:
密碼強度檢測程序算法

註釋風格:
doxygenide

測試環境:
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
相關文章
相關標籤/搜索