替人寫的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
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 }