学習のためC言語でパスワード生成プログラムを作成した。
仕様は以下の通り。
・ランダムで初期パスワード生成後に新しいパスワードを標準入力で受け付ける。
・パスワードは数字,英字(大文字・小文字),記号を含む必要がある。
初期パスワードと同一不可。
・記号は `~!@#$^&*()_-+={}[]|:;'<>,.?/\ が使用可能。
・パスワード文字数は8~256文字で、初期パスワードは8文字とする。
Password_create.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#define LENGTH_MIN 8
#define LENGTH_MAX 256
const char lower[] = "abcdefghijklmnopqrstuvwxyz";
const char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const char digits[] = "0123456789";
const char symbol[] ="`~!@#$^&*()_-+={}[]|:;'<>,.?/\\";
void shuffle(char *a, int n)
{
for (int i = n - 1; i > 0; --i)
{
int j = rand() % (i + 1);
char tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
int validate_password(char init_password[],char new_password[])
{
if (strcmp(init_password, new_password)==0)
{
printf("初期パスワードと同じです。パスワードを変えて下さい。\n");
return -1;
}
if (strlen(new_password) < LENGTH_MIN)
{
printf("文字数が少ないです。%d 文字以上必要です。\n",LENGTH_MIN);
return -1;
}
else if(strlen(new_password) > LENGTH_MAX)
{
printf("文字数が多いです。上限 %d 文字までです。\n",LENGTH_MAX);
return -1;
}
/* 種類チェック */
int has_upper = 0;
int has_lower = 0;
int has_digit = 0;
int has_symbol = 0;
for (int i = 0; new_password[i] != '\0'; i++)
{
unsigned char c = (unsigned char)new_password[i];
if (isupper(c))
has_upper = 1;
else if (islower(c))
has_lower = 1;
else if (isdigit(c))
has_digit = 1;
else if( strchr(symbol,new_password[i]) != NULL)
has_symbol = 1;
else
{
printf("使えない文字 %c が含まれています。\n",new_password[i]);
return -1;
}
}
/* 判定出力 */
if (!has_upper)
printf("英大文字が含まれていません。\n");
if (!has_lower)
printf("英小文字が含まれていません。\n");
if (!has_digit)
printf("数字が含まれていません。\n");
if (!has_symbol)
printf("記号が含まれていません。\n");
if (has_upper && has_lower && has_digit && has_symbol)
{
printf("有効なパスワードです\n");
return 0;
}
else
return -1;
}
int main(void)
{
int c;
char init_password[LENGTH_MAX + 2];
char new_password[LENGTH_MAX + 2];
int pos = 0;
char pool[512];
snprintf(pool, sizeof(pool), "%s%s%s%s", lower, upper, digits, symbol);
srand((unsigned)time(NULL));
/* 必須の1文字ずつを挿入 */
init_password[pos++] = lower[rand() % (strlen(lower))];
init_password[pos++] = upper[rand() % (strlen(upper))];
init_password[pos++] = digits[rand() % (strlen(digits))];
init_password[pos++] = symbol[rand() % (strlen(symbol))];
/* 残りを全候補からランダムに埋める */
while (pos < LENGTH_MIN)
init_password[pos++] = pool[rand() % (strlen(pool))];
/* 位置をランダムにシャッフルして偏りを無くす */
shuffle(init_password, LENGTH_MIN);
init_password[LENGTH_MIN] = '\0';
while (1)
{
printf("初期パスワード: %s\n", init_password);
printf("\n");
printf("新しいパスワードを入力して下さい。\n");
printf("英大文字・小文字・数字・記号をすべて含む%d~%d文字である必要があります。\n",
LENGTH_MIN,LENGTH_MAX);
printf("記号は `~!@#$^&*()_-+={}[]|:;'<>,.?/\\が使えます。\n");
if (fgets(new_password, sizeof(new_password), stdin) != NULL)
{
size_t len = strlen(new_password);
if (len > 0 && new_password[len - 1] == '\n')
new_password[len - 1] = '\0';
else
{
/* 改行が無かった場合は、バッファの残りを捨てる */
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
}
}
if(validate_password(init_password,new_password) == 0)
break;
}
return 0;
}
実行結果の例を以下に示す。
./password_create
初期パスワード: W9*m$NI$
新しいパスワードを入力して下さい。
英大文字・小文字・数字・記号をすべて含む8~256文字である必要があります。
記号は `~!@#$^&*()_-+={}[]|:;'<>,.?/\が使えます。
W9*m$NI$
初期パスワードと同じです。パスワードを変えて下さい。
初期パスワード: W9*m$NI$
新しいパスワードを入力して下さい。
英大文字・小文字・数字・記号をすべて含む8~256文字である必要があります。
記号は `~!@#$^&*()_-+={}[]|:;'<>,.?/\が使えます。
W9*m$NI
文字数が少ないです。8 文字以上必要です。
初期パスワード: W9*m$NI$
新しいパスワードを入力して下さい。
英大文字・小文字・数字・記号をすべて含む8~256文字である必要があります。
記号は `~!@#$^&*()_-+={}[]|:;'<>,.?/\が使えます。
Wa*m$NI$
数字が含まれていません。
初期パスワード: W9*m$NI$
新しいパスワードを入力して下さい。
英大文字・小文字・数字・記号をすべて含む8~256文字である必要があります。
記号は `~!@#$^&*()_-+={}[]|:;'<>,.?/\が使えます。
W9*m$NI$a
有効なパスワードです