Skip to content

Instantly share code, notes, and snippets.

@sekika
Last active May 17, 2017 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sekika/89338aa1a25aebcf2e8698aad6db0080 to your computer and use it in GitHub Desktop.
Save sekika/89338aa1a25aebcf2e8698aad6db0080 to your computer and use it in GitHub Desktop.
パスワード生成プログラム
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# パスワード生成プログラム
#
# このプログラムに関する記事「パスワードの管理について」
# https://sekika.github.io/2017/05/09/Password/
#
# 使い方:プログラムのソースコードに直接サイト情報を書く。
# サイト情報は、サイト名、ハッシュ関数、文字種、文字数、パスワードの種の5つ。
# 引数にサイト名を指定して起動、あるいは起動してからサイト名を指定する。
# マスターパスワードを入力すると、それに対応したパスワードが表示される。
# まずはサイト情報を辞書オブジェクトとして定義する。
# たとえば、
# "google" : ["sha512", "an", 16, "kKkMqYDUIivWLi3WSt3VndHci"],
# の行は、サイト名 google のパスワードはsha512 のハッシュ関数を使い、
# an の文字種(アルファベットと数字)で16文字のパスワードを
# kKkMq... をサイト固有のパスワードの種として生成する。
# 初期設定のままで google のパスワードをマスターパスワードを空にして生成すると
# gak7f1WDmk4jhKRd となる。
# JavaScript 版はこちら
# http://seki.webmasters.gr.jp/password.html
# Python 版と同じようなサイト情報の設定形式を使い、同じパスワードが生成される
# ただし、文字種 ans95 は未対応
sitekey = {
"google" : ["sha512", "an", 16, "kKkMqYDUIivWLi3WSt3VndHci"],
"amazon" : ["sha3_384", "an", 16, "stBuQIQgT9Yp84RBK3HdllnUK"],
"twitter" : ["sha3_512", "an", 14, "UmhvSHT72smO4aI1LMYt7H2el"]
}
# サイト情報の定義終了
##### メインプログラム開始 #####
import hashlib, base64
import sys, re, getpass
# クリップボードを使うときには、次の行をコメントアウト。 pip3 install clipboard が必要。
# import clipboard
# サイトをコマンドライン引数から読み込む。引数がなければ入力させる。
if (len(sys.argv)) == 1:
for key in sitekey.keys():
print (key)
site=input ('サイトを指定してください。')
else:
site = sys.argv[1]
# サイト情報がなければエラーを返して終了する。
if site not in sitekey:
print ('サイト {0} は定義されていません。'.format(site))
sys.exit()
# サイト情報とマスターパスワードから、パスワードの種となる情報を得る。
site = sitekey[site]
has = site[0] # ハッシュ関数の種類
char = site[1] # パスワードで使う文字の種類
plen = site[2] # パスワードの長さ
# サイト情報に必須項目以上の要素がある場合には、それをすべて表示する。
# サイトのユーザーIDなどの情報を入れておくと良い。
for i in range(4,len(site)):
print (site[i]) # コメント情報を表示
# マスターパスワードを入力させる。
master = getpass.getpass('マスターパスワードを入力してください。')
# master = input('マスターパスワードを入力してください。')
# マスターパスワード + サイト固有のパスワードの種
seed = (master + site[3]).encode('utf-8')
# 指定されたハッシュ関数を適用する。
# ハッシュ関数を統一せずにサイトごとに指定しているのは、パスワードを更新するときに
# ハッシュ関数をより新しいものへとアップデートしやすくするためである。
# Python 3 の hashlib ドキュメントは
# https://docs.python.jp/3/library/hashlib.html
if has == ('sha384'):
h = hashlib.sha384(seed)
elif has == ('sha512'):
h = hashlib.sha512(seed)
elif has == ('sha3_384'):
h = hashlib.sha3_384(seed)
elif has == ('sha3_512'):
h = hashlib.sha3_512(seed)
else:
print ('ハッシュ関数 {0} は定義されていません。'.format(has))
sys.exit()
# 指定された文字の種類にしたがって、パスワードの文字列を作る。
# 文字の種類をサイトごとに指定することで、パスワード文字の種類に特殊な
# 要求がある場合に対応する。
base = base64.b64encode(h.digest()).decode("utf-8") # base64 エンコード
if char == ('base64'): # base64: アルファベット、数字、+/
p = base
elif char == ('an'): # an: アルファベットと数字
p = re.sub(r'[+/=]',"", base)
elif char == ('a'): # a: アルファベットのみ
p = re.sub(r'[0-9+/=]',"", base)
elif char == ('n'): # n: 数字のみ
p = re.sub(r'[a-f]',"", (h.hexdigest()))
elif char == ('ans'): # ans: アルファベットと数字と記号
symbol = '#[$-=?@]_!' # + と / 以外で使用可能な記号
p = base.replace('=','')
a = ord(p[0:1]) % len(symbol)
symbol = symbol[a:-1] + symbol[0:a] # 記号の発生確率を均等に
for s in symbol:
p = p.replace(p[0:1], s)[1:-1] + p[0:1]
elif char == ('ans95'): # ans95: アルファベットと数字と記号全95種類 (JavaScript 版未対応)
h = int.from_bytes(h.digest(), byteorder='big')
p = ''
for i in range(plen):
p = p + chr(h % 95 + 32)
h = h // 95
else:
print ('文字種 {0} は定義されていません。'.format(char))
sys.exit()
# 指定された長さのパスワードを表示する。
print (p[0:plen])
# クリップボードにコピーするときには、次の2行をコメントアウト。
# clipboard.copy(p[0:plen])
# print ('パスワードをクリップボードにコピーしました。')
@sekika
Copy link
Author

sekika commented May 9, 2017

このプログラムに関する記事「パスワードの管理について」(一般向け)
https://sekika.github.io/2017/05/09/Password/

Qiita の記事(プログラマー向け)
http://qiita.com/sekik/items/37e283f527301ec50c98

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment