替人写的C语言作业…
介绍:
程序名称:
密码强度检测程序
注释风格:
doxygen
测试环境:
linux3.6, gcc4.7
window7, vs2012
已知问题:
1. 算法与参考链接不一致,结果会有差别,详见代码注释。
2. 在vs下可能会编译不通过,将后缀改为cpp就可以了。vs的C编译器实现对C90支持不佳,gcc4.5以上可以正常编译通过。
#ifndef CHECKPASS_H_INCLUDED
#define CHECKPASS_H_INCLUDED /*!
* \brief 本程序用于检测密码强度
* \details 请根据提示输入密码,程序会自动输出对应的强度
*
* 程序会根据是否满足一定的条件对密码进行打分,然后区分出档次。
* 得分最低0分,最高100分;等级分为很弱-弱-一般-好-强-极强几个档次。
* 判断标准(参考[链接](http://goo.gl/wuQdN):
* 1. 最低要求包括
* * 长度>8位
* * 以下四种元素至少有三种:
* - 大写英文字母
* - 小写英文字母
* - 数字
* - 特殊符号
* 2. 加分条件
* * 密码总字数 +(次数*4)
* * 大写字母数 +(长度-字数)*2 [字数必须>0]
* * 小写字母数 +(长度-字数)*2 [同上]
* * 数字个数 +(次数*4)
* * 特殊符号数 +(次数*6)
* * 数字或符号出现在密码中间部分 +(次数*2)
* * 达到最低需求 +(次数*2)
* 3. 减分条件
* * 只有字母 -次数
* * 只有数字 -次数
* * 出现重复单元,对每个重复的字符 -次数*(次数-1) [不计大小写]
* * 连续大写字母 -次数*2
* * 连续小写字母 -次数*2
* * 连续多个数字 -次数*2
* * 字母顺序递增/减(三个及以上) -次数*3
* * 数字顺序递增/减(三个及以上) -次数*3
*
* \author
* \date 2013-06-22
* \copyright GNU Public License
*/ /** 字符数目,取char的最大值+1*/
#define CHARNUM 256 /** 强度评价*/
extern const char *g_pPasswordLevel[]; /** 强度枚举*/
typedef enum _PasswordLevel {
VERYWEEK,
WEEK,
AVERAGE,
GOOD,
STRONG,
VERYSTRONG
} PasswordLevel; /** 计算得分需要的参数*/
typedef struct _RuleParameter {
int nLength; ///< 密码长度
int nUpper; ///< 大写字母个数
int nLower; ///< 小写字母个数
int nDigit; ///< 数字个数
int nSymbol; ///< 特殊字符个数
int nMidDigitSymbol; ///< 中间部分的数字或字符个数
int nRequirement; ///< 达到最低需求的次数
int RepeatChar[CHARNUM]; ///< 每个字符重复的次数
int nConsecUpper; ///< 连续大写字母个数
int nConsecLower; ///< 连续小写字母个数
int nConsecDigit; ///< 连续数字个数
int nSequence; ///< (三个及以上)顺序字母/数字次数
} RuleParameter; /**
* \brief 求密码得分
* \param[in] password 密码
* \return 得分
*/
int GetPasswordScore(const char *password); /**
* \brief 求密码等级
* \param[in] password 密码得分
* \return 密码等级
*/
PasswordLevel GetPasswordLevel(int score); #endif // CHECKPASS_H_INCLUDED
checkPass.h
#include "checkPass.h" #include <stdlib.h>
#include <string.h>
#include <ctype.h> /** 强度评价*/
const char *g_pPasswordLevel[]= {
"很弱",
"弱",
"一般",
"好",
"强",
"很强"
}; /**
* \defgroup prototypes
* @{
*/ /**
* \brief 负责调用其他计算函数,填充了长度字段
* \param[in] password 密码
* \param[out] rp 待填充的规则参数结构指针
*/
void beginProcess(const char *password,RuleParameter *rp); /**
* \brief 填充大写、小写、数字、符号及他们的连续值字段
* \param[in] password 密码
* \param[out] rp 待填充的规则参数结构指针
*/
void countNumbers(const char *password,RuleParameter *rp); /**
* \brief 填充连续递增/减字符的个数字段
* \param[in] password 密码
* \param[out] rp 待填充的规则参数结构指针
*/
void countSeqNumbers(const char *password,RuleParameter *rp); /**
* \brief 填充重复单元字段
* \param[in] password 密码
* \param[out] rp 待填充的规则参数结构指针
*/
void countRepeat(const char *password, RuleParameter *rp); /**
* \brief 计算密码得分
* \param[in] rp 已经填充的规则参数结构指针
* \return 得分
*/
int countScore(const RuleParameter *rp); /** @}*/ PasswordLevel GetPasswordLevel(int score)
{
if(score<) {
return VERYWEEK;
}
if(score<) {
return WEEK;
}
if(score<) {
return AVERAGE;
}
if(score<) {
return STRONG;
}
return VERYSTRONG;
} int GetPasswordScore(const char *password)
{
RuleParameter rp= {};
beginProcess(password,&rp);
return countScore(&rp);
} void beginProcess(const char *password,RuleParameter *rp)
{
if(password==NULL || rp==NULL) return; int i,j; char *pass_nospace=(char *)malloc(strlen(password)+);
char *pass_nospace_lower=(char *)malloc(strlen(password)+); if(!pass_nospace) exit(EXIT_FAILURE); for(i=,j=; password[i]!='\0'; i++) {
if(!isspace(password[i])) {
pass_nospace[j]=password[i];
pass_nospace_lower[j]=tolower(password[i]);
++j;
}
}
pass_nospace[j]='\0'; rp->nLength=strlen(pass_nospace); countRepeat(pass_nospace_lower,rp);
countNumbers(pass_nospace,rp);
countSeqNumbers(pass_nospace,rp); free(pass_nospace);
free(pass_nospace_lower);
} void countRepeat(const char *password, RuleParameter *rp)
{
if(!password || !rp)return; int i;
for(i=; i<rp->nLength; i++) {
++rp->RepeatChar[password[i]];
}
} void countNumbers(const char *password, RuleParameter *rp)
{
if(!password || !rp)return; int i;
int last_upper_pos=-;
int last_lower_pos=-;
int last_digit_pos=-; for(i=; i<rp->nLength; i++) {
if(isupper(password[i])) {
if(last_upper_pos!=- && last_upper_pos+==i) {
++rp->nConsecUpper;
}
last_upper_pos=i;
++rp->nUpper;
} else if(islower(password[i])) {
if(last_lower_pos!=- && last_lower_pos+==i) {
++rp->nConsecLower;
}
last_lower_pos=i;
++rp->nLower;
} else if(isdigit(password[i])) {
if(last_digit_pos!=- && last_digit_pos+==i) {
++rp->nConsecDigit;
}
if(i> && i< rp->nLength-) {
++rp->nMidDigitSymbol;
}
last_digit_pos=i;
++rp->nDigit;
} else {
if(i> && i<rp->nLength-) {
++rp->nMidDigitSymbol;
}
++rp->nSymbol;
}
} if(rp->nLower>) ++rp->nRequirement;
if(rp->nUpper>) ++rp->nRequirement;
if(rp->nDigit>) ++rp->nRequirement;
if(rp->nSymbol>) ++rp->nRequirement;
} /**
* \note 注意,此处计算重复数字的算法与参考链接处并不相同!
* 经过反复测试,参考链接中测试算法与其描述并不相符,
* 此处的实现中,字符不能同时被统计在上升序列和下降序列中!
*/
void countSeqNumbers(const char *password,RuleParameter *rp)
{
if(!password || !rp || rp->nLength<)return; int inc_count=;
int dec_count=;
int i=; for(; i<rp->nLength; i++) {
if(isalnum(password[i]) && isalnum(password[i-])) {
if(password[i]-password[i-]==) {
if(dec_count<)++inc_count;
dec_count=;
} else if(password[i]-password[i-]==-) {
if(inc_count<)++dec_count;
inc_count=;
} else {
inc_count=dec_count=;
}
} else {
inc_count=dec_count=;
} if(inc_count>= || dec_count>=) {
++rp->nSequence;
}
}
} int countScore(const RuleParameter *rp)
{
if(!rp || rp->nLength==)return ; int score=;
int i;
int n; score+=rp->nLength * ;
if(rp->nUpper!=)score+=(rp->nLength - rp->nUpper) *;
if(rp->nLower!=)score+=(rp->nLength - rp->nLower) *;
if(rp->nLength!=rp->nDigit)score+=rp->nDigit *;
score+=rp->nSymbol *;
score+=rp->nMidDigitSymbol *;
if(rp->nLength>= && rp->nRequirement>=) {
score+=(rp->nRequirement+)*;
} if(rp->nDigit==rp->nLength || rp->nLower+rp->nUpper==rp->nLength)
score-=rp->nLength; for(i=; i<CHARNUM; ++i) {
n=rp->RepeatChar[i];
if(n>) {
score-=n*(n-);
}
}
score-=rp->nConsecDigit * ;
score-=rp->nConsecLower *;
score-=rp->nConsecUpper *;
score-=rp->nSequence *; if(score<) score=;
if(score>) score=;
return score;
}
checkPass.c
#include <stdio.h>
#include "checkPass.h" /**缓冲区最大长度*/
# define BUFFERLEN int main()
{
char password[BUFFERLEN];
int score;
PasswordLevel level; while() {
printf("请输入密码:\n");
if(fgets(password,BUFFERLEN,stdin)==NULL)continue; score=GetPasswordScore(password);
level=GetPasswordLevel(score); printf("该密码得分为 %d, 评价为 %s\n",score,g_pPasswordLevel[level]);
}
return ;
}
main.c