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

(1/1)
C++でパスワード生成機を作る
PHPでWinAsmを使ってWindowsプログラムをデザイン」で作ったパスワード生成機をC++に移植する。

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

(2022年7月17日)CUI版を追加,ライブラリを更新

目次

サンプル・プログラム

圧縮ファイルの内容
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版ビルド

リソースの準備

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

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

使用ライブラリ

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

プログラムの解説

0009: // 初期化処理 ======================================================
0010: #include <iostream>
0011: #include <stdio.h>
0012: #include <stdlib.h>
0013: #include <tchar.h>
0014: #include <sstream>
0015: #include <string>
0016: #include <fstream>
0017: #include <windows.h>
0018: #include <commctrl.h>
0019: #include <shlobj.h>
0020: #include <richedit.h>
0021: #include <time.h>
0022: #include <random>
0023: #include <boost/format.hpp>
0024: #include <boost/program_options.hpp>
0025: #include <boost/property_tree/xml_parser.hpp>
0026: #include "resource.h"
0027: 
0028: using namespace std;
0029: using namespace boost;
0030: using namespace boost::program_options;
0031: using namespace boost::property_tree;
0032: 
0033: #define APPNAME        "makepassword"            //アプリケーション名(GUI版)
0034: #define APPNAMEJP  "パスワード生成機"        //アプリケーション名
0035: #define APPCMD     "mkpsw"                   //アプリケーション名(CUI版)
0036: #define APPVERSION "1.2"                 //バージョン
0037: #define APPYEAR        "2020-2022"               //作成年
0038: #define REFERENCE  "https://www.pahoo.org/e-soul/webtech/cpp01/cpp01-05-01.shtm" // 参考サイト
0039: 
0040: //char*バッファサイズ
0041: #define SIZE_BUFF      512
0042: 
0043: //標準フォント
0044: #define FONT_FACE      "MS UI Gothic"
0045: 
0046: //現在のインターフェイス
0047: HINSTANCE hInst;
0048: 
0049: //アプリケーション・ウィンドウ
0050: HWND hParent;
0051: 
0052: //アプリケーション・ウィンドウ位置
0053: unsigned hParent_XhParent_Y;
0054: 
0055: //エラー・メッセージ格納用
0056: string ErrorMessage;
0057: 
0058: //ヘルプ・ファイル
0059: #define HELPFILE   ".\\etc\\help.chm"
0060: 
0061: //オプション
0062: #define OPTION_UPPER   'u'       //英大文字
0063: #define OPTION_LOWER   'a'       //英小文字
0064: #define OPTION_NUMBER  'n'       //数字
0065: #define OPTION_SYMBOL  's'       //記号
0066: 
0067: //パスワードに使う文字セット
0068: const string Seed[] = {
0069:     "ABCDEFGHIJKLMNOPQRSTUVWXYZ",      //英大文字
0070:     "abcdefghijklmnopqrstuvwxyz",      //英小文字
0071:     "0123456789",                      //数字
0072:     "()%$#+-*"                          //記号
0073: };
0074: 
0075: //オプションの初期値
0076: #define OPTION_INIT        "an"
0077: 
0078: //生成するパスワードの最小桁数と最大桁数
0079: #define MIN_PASSWORD   4
0080: #define MAX_PASSWORD   20
0081: 
0082: //パスワード長
0083: unsigned PswLen = MIN_PASSWORD;
0084: 
0085: //乱数関係
0086: std::random_device rnd;            //非決定的な乱数生成器を生成
0087: std::mt19937 mt((int)time(0)); //メルセンヌ・ツイスタの32ビット版+シード

パスワードに使う文字セットは配列 Seed に用意する。
生成するパスワードの最小桁数と最大桁数を定義する。
文字列を操作するために、char*バッファのサイズを SIZE_BUFF に定義する。

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

0134: /**
0135:  * クリップボードに文字列をセット
0136:  * @param   string str 文字列
0137:  * @return  なし
0138: */
0139: void setClipboardData(string str) {
0140:     char buff[str.size() + 1];
0141:     char_traits<char>::copy(buffstr.c_str(), str.size() + 1);
0142: 
0143:     OpenClipboard(NULL);
0144:     EmptyClipboard();
0145: 
0146:     HGLOBAL hText = GlobalAlloc(GHND | GMEM_SHARESIZE_BUFF);
0147:     PTSTR pText = (PTSTR)GlobalLock(hText);
0148:     lstrcpy(pTextbuff);
0149:     GlobalUnlock(hText);
0150:     SetClipboardData(CF_TEXThText);
0151:     CloseClipboard();
0152: }

クリップボードに文字列をセットするユーザー関数 setClipboardData を用意した。Win32APIを利用するもので、「PHPでクリップボードにテキスト貼り付け(Windowsアプリ版)」で作ったプログラムをC++に移植した。

0031: /**
0032:  * ダイアログボックス
0033:  * @param   HWND hDlg
0034:  * @paramm  UINT uMsg
0035:  * @param   WPARAM wParam
0036:  * @paramL  PARAM lParam
0037:  * @return  INT_PTR CALLBACK
0038: */
0039: INT_PTR CALLBACK DlgProc(HWND hDlgUINT uMsgWPARAM wParamLPARAM lParam) {
0040:     char buff[255];
0041: 
0042:     time_t t = time(0);                  //現在時刻
0043:     tmnow = localtime(&t);         //ローカルタイム
0044:     int year = now->tm_year + 1900;        //西暦年を取り出す
0045:     bool res = isleap(year);         //閏年かどうか判定する
0046: 
0047:     switch(uMsg) {
0048:         case WM_INITDIALOG:
0049:             snprintf(buffsizeof(buff), "%d年は 閏年%s", year, (res ? "です." : "ではありません."));
0050:             SetDlgItemText(hDlgIDC_LABELbuff);
0051:             break;
0052:         case WM_CLOSE:
0053:             EndDialog(hDlg, 0);
0054:             break;
0055:     }
0056:     return 0;
0057: }

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

参考サイト

(この項おわり)
header