C++ でパスワード生成機を作る

(1/1)
C++でパスワード生成機を作る
PHPでパスワードを生成」で作ったパスワード生成機をC++に移植する。
パスワード文字は、英大文字、英小文字、数字、記号の1つまたは複数を組み合わせ、任意の長さのパスワードを生成する。生成したパスワードはクリップボードにコピーできるようにする。

作ったパスワードは、「C++ でパスワードの強度を調べる」で強さを調べてみてほしい。
CUI版 "mkpsw.exe" を用意した。GUI版と同じディレクトリにインストールされる。コマンドラインから実行することを想定している。
たとえば "mkpsw -l11 -u -a -n -s -p" のようなバッチを用意しておくと、このバッチを実行するだけで、「英大文字・小文字、数字、記号を混在させた11桁のパスワードをクリップボードにコピーする」という処理ができる。あとは、パスワード入力テキストボックスに、[ctrl+P]でペーストしてやるだけでいい。

(2025年2月24日)記号の文字種を指定できるようにした,使用ライブラリ更新
(2024年11月3日)使用ライブラリ更新
(2024年7月7日)使用ライブラリ更新

目次

サンプル・プログラム

圧縮ファイルの内容
makepassword.msiインストーラ
bin/makepassword.exe実行プログラム本体
bin/etc/help.chmヘルプ・ファイル
sour/makepassword.cppソース・プログラム
sour/resource.hリソース・ヘッダ
sour/resource.rcリソース・ファイル
sour/application.icoアプリケーション・アイコン
sour/makefileGUI版ビルド
sour/makefile_cmdCUI版ビルド
makepassword.cpp 更新履歴
バージョン 更新日 内容
1.3.0 2025/02/24 記号の文字種を指定できるようにした,使用ライブラリ更新
1.2.7 2024/11/03 使用ライブラリ更新
1.2.6 2024/07/07 使用ライブラリ更新
1.2.5 2024/02/17 使用ライブラリ更新
1.2.4 2023/10/09 使用ライブラリ更新

リソースの準備

Eclipse を起動し、新規プロジェクト makepassword を用意する。
ResEdit を起動し、resource.rc を用意する。
Eclipse に戻り、ソース・プログラム "makepassword.cpp" を追加する。
リンカー・フラグを "-mwindows -static -lole32 -lboost_program_options-mt -lpthread -lwinpthread" に設定する。

MSYS2 コマンドラインからビルドするのであれば、"makefile" と "makefile_cmd" を利用してほしい。

使用ライブラリ

今回は、オープンソースのライブラリ Boost C++ライブラリを使用する。導入方法等については、「C++ 開発環境の準備」をご覧いただきたい。

解説:乱数

makepassword.cpp

  41: // char*バッファサイズ
  42: #define SIZE_BUFF       512
  43: 
  44: // 標準フォント
  45: #define FONT_FACE       "MS UI Gothic"
  46: 
  47: // 現在のインターフェイス
  48: HINSTANCE hInst;
  49: 
  50: // アプリケーション・ウィンドウ
  51: HWND hParent;
  52: 
  53: // アプリケーション・ウィンドウ位置
  54: unsigned hParent_X, hParent_Y;
  55: 
  56: // エラー・メッセージ格納用
  57: string ErrorMessage;
  58: 
  59: // ヘルプ・ファイル
  60: #define HELPFILE    ".\\etc\\help.chm"
  61: 
  62: // オプション
  63: #define OPTION_UPPER    'u'     // 英大文字
  64: #define OPTION_LOWER    'a'     // 英小文字
  65: #define OPTION_NUMBER   'n'     // 数字
  66: #define OPTION_SYMBOL   's'     // 記号
  67: 
  68: // パスワードに使う文字セット
  69: const string Seed[] = {
  70:     "ABCDEFGHIJKLMNOPQRSTUVWXYZ",       // 英大文字
  71:     "abcdefghijklmnopqrstuvwxyz",       // 英小文字
  72:     "0123456789"                        // 数字
  73: };
  74: // パスワードに使う記号
  75: #define DEF_SYMBOL  "()%$#+-*"
  76: string Symbol = DEF_SYMBOL;
  77: 
  78: // オプションの初期値
  79: #define OPTION_INIT     "an"
  80: 
  81: // 生成するパスワードの最小桁数と最大桁数
  82: #define MIN_PASSWORD    4
  83: #define MAX_PASSWORD    20
  84: 
  85: // パスワード長
  86: unsigned PswLen = MIN_PASSWORD;
  87: 
  88: // 乱数関係
  89: std::random_device rnd;         // 非決定的な乱数生成器を生成
  90: std::mt19937 mt((int)time(0));  // メルセンヌ・ツイスタの32ビット版+シード

パスワードに使う文字セットは配列 Seed に用意する。ただし、記号だけは任意に設定できるよう、変数 Symnbol に分離した。
生成するパスワードの最小桁数と最大桁数を定義する。
文字列を操作するために、char*バッファのサイズを SIZE_BUFF に定義する。

疑似乱数としてC++のrand関数を使おうとしたが、偏りがあるので、randomライブラリにあるメルセンヌ・ツイスタ乱数を使うことにする。

解説:クリップボード

makepassword.cpp

 137: /**
 138:  * クリップボードに文字列をセット
 139:  * @param   string str 文字列
 140:  * @return  なし
 141: */
 142: void setClipboardData(string str) {
 143:     char buff[str.size() + 1];
 144:     char_traits<char>::copy(buff, str.c_str(), str.size() + 1);
 145: 
 146:     OpenClipboard(NULL);
 147:     EmptyClipboard();
 148: 
 149:     HGLOBAL hText = GlobalAlloc(GHND | GMEM_SHARE, SIZE_BUFF);
 150:     PTSTR pText = (PTSTR)GlobalLock(hText);
 151:     lstrcpy(pText, buff);
 152:     GlobalUnlock(hText);
 153:     SetClipboardData(CF_TEXT, hText);
 154:     CloseClipboard();
 155: }

クリップボードに文字列をセットするユーザー関数 setClipboardData を用意した。Win32APIを利用する。

解説:メインダイアログ

isleap2.cpp

  31: /**
  32:  * ダイアログボックス
  33:  * @param   HWND hDlg
  34:  * @paramm  UINT uMsg
  35:  * @param   WPARAM wParam
  36:  * @paramL  PARAM lParam
  37:  * @return  INT_PTR CALLBACK
  38: */
  39: INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  40:     char buff[255];
  41: 
  42:     time_t t = time(0);                 //現在時刻
  43:     tm* now = localtime(&t);            //ローカルタイム
  44:     int year = now->tm_year + 1900;     //西暦年を取り出す
  45:     bool res = isleap(year);            //閏年かどうか判定する
  46: 
  47:     switch(uMsg) {
  48:         case WM_INITDIALOG:
  49:             snprintf(buff, sizeof(buff), "%d年は 閏年%s", year, (res ? "です." : "ではありません."));
  50:             SetDlgItemText(hDlg, IDC_LABEL, buff);
  51:             break;
  52:         case WM_CLOSE:
  53:             EndDialog(hDlg, 0);
  54:             break;
  55:     }
  56:     return 0;
  57: }

ダイアログボックス関数にイベントが増えた。
ボタンをクリックすると、WM_COMMAND イベントが発生する。クリックされたボタンのIDで処理を場合分けする。

参考サイト

(この項おわり)
header