HSP3で二段階認証を作った話
なんかよくわかんないけどPythonとHSP3を合体させて二段階認証作りました。
Pythonファイルがウィルス誤検知されるので完成品は非公開とさせていただきます。
コードだけ記載しますね。
必須環境
windows
python 3
hsp 3.5
認証アプリがインストール済みのスマホ
1.構造
二段階認証システム
├system┐
│ └qrcodelib.dll(libqrencodeライブラリを使用しています。)
├main.hsp(本体.exeのコード)
├py1.pyw(秘密鍵生成機)
├py2.pyw(6桁コード生成機)
├seccode.txt(秘密鍵)
├sixcode.txt(6桁コード)
└本体.exe(main.hspをexe化したやつ)
2.[main.hsp]の中身
pythonとhsp3を合体させてるやつです。
;制作:だいちまる
#uselib "system/qrcodelib.dll"
#func QRcode_encodeString "QRcode_encodeString" str,int,int,int,int
#func QRcode_free "QRcode_free" int
username = sysinfo(1)
usercode = ""
screen 0,640,480
title"二段階認証のやつ"
*inputuser
color 32,32,32
pos 20,20
font"BIZ UDゴシック",26
mes"二段階認証サンプル"
font"BIZ UDPゴシック",18
pos 20,100
mes"ユーザー名を入力してください。"
objsize 250,24
font"BIZ UDPゴシック",16
objmode 2
input username,,,12
pos 20,200
font"BIZ UDPゴシック",18
mes"説明\nGoogleとかにある2段階認証をHSPで使えるようにしたくて\nPythonと連携するような形で使えるようにしたものです。\n実質中身はほぼPythonです。\n初めて利用される方は「コード作成」、\nコードを追加済みの方は「二段階認証」を押してください。"
font"BIZ UDゴシック",14
pos 400,420
objsize 100,40
button"二段階認証",*chk
pos 520,420
objsize 100,40
button"コード生成",*make
stop
*make
if username = "":dialog "ユーザー名を入力してください。":stop
clrobj
color 255,255,255:boxf
exec"py1.exe",16
wait 30;exe実行時間
notesel secret
noteload"seccode.txt"
noteget seccode,0
totplink = "otpauth://totp/二段階認証のやつ?secret="+seccode+"&issuer="+username+""
goto*hyoji
stop
*hyoji
;QR生成
// 使用ライブラリ
// libqrencode
// http://fukuchi.org/works/qrencode/index.html
// 入手先(Win32バイナリ)
// qrencode-win32 qrcode-win32-3.1.1.zip を解凍した先のDLLフォルダに入ってます
// http://code.google.com/p/qrencode-win32/
// 参考
// http://fukuchi.org/works/qrencode/manual/qrencode_8h.html
// QRコード化したいURLをいれる
bun = totplink
b = 4 // 倍率
ox = 230 // オフセットX
oy = 150 // オフセットX
QRcode_encodeString bun, 0, 3, 3, 1
qrcode = stat
dupptr res, qrcode, 12, 4
size = res.1
dupptr data, res.2, size*size, 2
// QRコードの描画
color : redraw 0
i = 0 : x = 0
repeat size
x = cnt
repeat size
if peek(data,i)&1{
boxf cnt*b+ox, x*b+oy, cnt*b+b+ox, x*b+b+oy
}
i++
loop
loop
redraw 1
// 終わったら解放
QRcode_free qrcode
font"BIZ UDゴシック",26
pos 30,60
mes"下のコードを認証用アプリで読み取ってください。"
font"BIZ UDゴシック",14
pos 70,90
mes totplink
font"BIZ UDゴシック",14
pos 520,420
objsize 100,40
button"二段階認証",*chk
stop
*chk
ct = 0
clrobj
color 255,255,255:boxf
color 32,32,32
font"BIZ UDゴシック",26
pos 50,60
mes"下の入力欄に6桁のコードを入力してください。"
color 64,64,64
boxf 225,195,444,272
pos 230,200
objsize 210,68
font"BIZ UDゴシック Bold",66
objmode 2
input usercode,,,6
font"BIZ UDゴシック",14
pos 520,420
objsize 100,40
button"OK",*codechk
stop
*codechk
exec"py2.exe",16
pos 20,200
font"BIZ UDPゴシック",18
mes"少々お待ちください..."
wait 30;exe実行時間
notesel sixnum
noteload"sixcode.txt"
noteget sixcode,0
;合ってるか確認
if usercode = sixcode{goto*okdesu}else{dialog"コードが違います。"}
stop
*okdesu
clrobj
color 255,255,255:boxf
color 32,32,32
font"BIZ UDゴシック",26
pos 50,60
mes"認証が完了しました。"
stop
3.[py1.pyw]の中身
秘密鍵生成機です。
# 制作:だいちまる
import hmac, base64, struct, hashlib, time ,random, string
# ランダムな秘密鍵を生成
def randomname(n):
randlst = [random.choice(string.ascii_letters + string.digits) for i in range(n)]
return ''.join(randlst)
# 秘密鍵
secret = randomname(10)
# 秘密鍵を2進数(バイナリ)に変換
binary_secret = ''.join(format(ord(c), '08b') for c in secret)
# 5ビットずつ配列に分割
binary_secret_array = [binary_secret[i:i+5] for i in range(0, len(binary_secret), 5)]
# base32に変換
base32alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
base32_secret = ''
for binary in binary_secret_array:
bin_pad = binary.ljust(5, '0') # 5ビットに満たない場合は0パディング
base32_secret += base32alphabet[int(bin_pad, 2)]
# base32でエンコードした秘密鍵を保存
f = open('seccode.txt', 'w')
f.write(base32_secret)
f.close()
警告
拡張子はpywにしてください。pyでも動きますがHSPとの組み合わせをしたときにちょっと気持ち悪い動きになってしまうので...
4.[py2.pyw]の中身
秘密鍵を6桁コードにするやつです。
# 制作:だいちまる
import hmac, base64, struct, hashlib, time
f = open('seccode.txt', 'r')
b = f.read()
secretcodes = b
secret = secretcodes
def get_hotp_token(secret: str, intervals_no: int) -> str:
# まずシークレットキーをデコード
key = base64.b32decode(secret, True)
# PythonのデータをCの構造体に変換
msg = struct.pack(">Q", intervals_no)
# ハッシュ値を計算
h = hmac.new(key, msg, hashlib.sha1).digest()
o = h[19] & 15
h = (struct.unpack(">I", h[o:o+4])[0] & 0x7fffffff) % 1000000
return str(h)
def get_totp_token(secret):
# unix時間を30で割った整数をいれている
x = get_hotp_token(secret=secret, intervals_no=int(time.time())//30)
# 6桁に満たない場合は6桁になるまでパディング
while len(x)!=6:
x+='0'
return x
secretk = (get_totp_token(secret))
print (get_totp_token(secret))
f = open('sixcode.txt', 'w')
f.write(secretk)
f.close()
5.[seccode.txt]の中身
空です。
py1.pywを実行すると秘密鍵が生成されます。
秘密鍵がないとpy2.pywは動きません。
6.[sixcode.txt]の中身
こっちも空です。
py2.pywを実行するとコードが生成されます。
秘密鍵がないと動きません。
7.実行方法
警告
[1.構造]で説明したのと同じ配置でファイルを作ってください。
そうでないと動きません。
libqrencodeのdllのdlもお忘れなく
HSPでQR生成する僕が参考にしたページ
dllのダウンロードページ
py1.pywとpy2.pywは一部のセキュリティソフトに誤検知される可能性があるので気をつけてください。
まずはmain.hspをふつうに実行してください。
多分こんな画面が出てくると思います。
初回起動時はコード生成ボタンを押してください。
py1によって秘密鍵が生成されます。
そしてその鍵のQRコードが表示されるのでスマホの認証アプリで読み込んでください。
こんなQRコードです。
これで秘密鍵の登録は終わりです。
スマホ側に6桁のコードが表示されているはずです。
そしたら右下の二段階認証ボタンを押してみましょう!
こんな感じのコード入力欄が出てくると思います!
そこにスマホで表示されている6桁のコードを入力してください!
入力し終わったらOKボタンを押してください!
やったね!
認証できていればOKです!
たま~に認証できないことがあるのでその時は6桁のコードが変わるまでまつか秘密鍵から作り直してみてください。
8.おわりに
今回はじめてQiitaで記事を投稿してみました。
まぁHSP3で二段階認証を作ろうとする変態はなかなかいないとは思いますがもし二段階認証を作りたいならがんがんこのコードをコピーしちゃってください~
以上
だいちまるでした~!
9.開発環境
- Windows 11
- HSP 3.6
- VScode 1.76.0
- Python 3.10.0