LoginSignup
16
19

More than 5 years have passed since last update.

python:keyringによるパスワード管理

Last updated at Posted at 2014-03-03

Mac

インストール:

$ pip install keyring

Downloading/unpacking keyring
  Downloading keyring-3.5.zip (88Kb): 88Kb downloaded
  Running setup.py egg_info for package keyring

    warning: no previously-included files found matching '.hg/last-message.txt'
Installing collected packages: keyring
  Running setup.py install for keyring

    warning: no previously-included files found matching '.hg/last-message.txt'
    Installing keyring script to /Users/hide/ve/tact/bin
Successfully installed keyring
Cleaning up...

使ってみる:

    >>> import keyring
    >>> dir(keyring)
    ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 
     'absolute_import', 'backend', 'backends', 'core', 'credentials', 'delete_password', 
     'errors', 'get_keyring', 'get_pass_get_password', 'get_password', 'getpassbackend', 
     'logger', 'logging', 'py27compat', 'set_keyring', 'set_password', 'util']

Macで使えるバックエンド:

    >>> keyring.backend.get_all_keyring()
    [<keyring.backends.OS_X.Keyring object at 0x10b1a9150>, 
     <keyring.backends.file.EncryptedKeyring object at 0x10b1a47d0>, 
     <keyring.backends.file.PlaintextKeyring object at 0x10b1a9590>]

デフォルトでOSXのキーチェーン:

    >>> keyring.get_keyring()
    <keyring.backends.OS_X.Keyring object at 0x10b1a9150>

    >>> keyring.set_password('service','user','password')
    >>> keyring.get_password('service','user')
    u'password'

キーチェーンアクセス

アプリケーション -> ユーティリティ -> キーチェーンアクセスを開いてログイン項目として「service」を確認できる。

securityコマンド

OSXのバックエンドは security コマンドのラッパーです。

$ which security
/usr/bin/security

$ security find-generic-password -a user -s service -g
keychain: "/Users/hide/Library/Keychains/login.keychain"
class: "genp"
attributes:
    0x00000007 <blob>="service"
    0x00000008 <blob>=<NULL>
    "acct"<blob>="user"
    "cdat"<timedate>=0x32303134303330333138303733385A00  "20140303180738Z\000"
    "crtr"<uint32>=<NULL>
    "cusi"<sint32>=<NULL>
    "desc"<blob>=<NULL>
    "gena"<blob>=<NULL>
    "icmt"<blob>=<NULL>
    "invi"<sint32>=<NULL>
    "mdat"<timedate>=0x32303134303330333138303733385A00  "20140303180738Z\000"
    "nega"<sint32>=<NULL>
    "prot"<blob>=<NULL>
    "scrp"<sint32>=<NULL>
    "svce"<blob>="service"
    "type"<uint32>=<NULL>
password: "password"

Debian

同じくpipでインストール。 ウィンドウシステムとか動いていないサーバーなので、ファイルベース:

    >>> keyring.backend.get_all_keyring()
    [<keyring.backends.file.EncryptedKeyring object at 0x28f4a50>, 
     <keyring.backends.file.PlaintextKeyring object at 0x28ebc50>]


    >>> current = _
    >>> dir(current[0])
    ['__abstractmethods__', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_check_file', '_classes', '_create_cipher', '_ensure_file_path', '_get_new_password', '_init_file', '_lock', '_migrate', '_unlock', 'block_size', 'decrypt', 'delete_password', 'encrypt', 'file_path', 'filename', 'get_password', 'keyring_key', 'priority', 'pw_prefix', 'set_password', 'viable']

    >>> current[0].filename
    'crypted_pass.cfg'
    >>> current[0].file_path
    '/home/hdknr/.local/share/python_keyring/crypted_pass.cfg'

    >>> current[1].filename
    'keyring_pass.cfg'
    >>> current[1].file_path
    '/home/hdknr/.local/share/python_keyring/keyring_pass.cfg'

作ってみる。キーストアのパスワードをrootとする:

    >>> keyring.set_password('ubuntu','user','password')
    Please enter password for encrypted keyring: root
    >>> keyring.get_password('ubuntu','user')
    u'password'

    >>> keyring.set_password('ubuntu','user1','password1')

ini ファイル形式のストア

ホーム以下にある:

$ more /home/hdknr/.local/share/python_keyring/crypted_pass.cfg 
[keyring_2Dsetting]
password_20reference = eyJwYXNzd29yZF9lbmNyeXB0ZWQiOiAiUVpqd2I1a2tKem5oMU1tdVpNL3VFTjE3QURFVU9mazg3
    Zm9vXG4iLCAic2FsdCI6ICJ5cTFES3BkeTl1QWtZN1VWSVhkR0JkczR6RUpzQ0UraFFHMjVWa1hL
    MWZFPVxuIiwgIklWIjogIm5uWGFlK0t3L0ErQUg1T2I2eGJiWFE9PVxuIn0=

[ubuntu]
user = eyJwYXNzd29yZF9lbmNyeXB0ZWQiOiAiK3ViUmdaRVYrRURVYTdVPVxuIiwgInNhbHQiOiAidEJt
    OGpaUzhkTnFIYkIzZHlrOU5TZGwvTnFFOGZ6TkttWEZsZVhwYkRkRT1cbiIsICJJViI6ICJxWXFQ
    YkY2TmV5YytFZmtZOVV0b0RRPT1cbiJ9
user1 = eyJwYXNzd29yZF9lbmNyeXB0ZWQiOiAiL2E1Qzl2RlFQR3Y1YU5GSVxuIiwgInNhbHQiOiAidjZV
    a3BIeHR3OGU3RnM5NDRoTTQwc1llL0hjdisrb3F0dktRSHdIeGw0az1cbiIsICJJViI6ICI0aENO
    QWZsTDdUeVBxVW1PSlBIU3FnPT1cbiJ9    

user1を削除

$ vi /home/hdknr/.local/share/python_keyring/crypted_pass.cfg
    >>> import keyring
    >>> keyring.get_password('ubuntu','user')
    Please enter password for encrypted keyring: 
    u'password'
    >>> keyring.get_password('ubuntu','user1')
    >>> 

"root"というパスワードはまずいので、評価おわったら消す。

Json Base64したもの

[keyring_2Dsetting]セクション

    >>> key_data = '''eyJwYXNzd29yZF9lbmNyeXB0ZWQiOiAiazloc1R1bmt3UERnRGo0TFY3UWljcVQybGxoSTRJS3Ns
    ...     Z1BVXG4iLCAic2FsdCI6ICJrcUZYUWhTMkR1ZEZGMjFkK3BpRmVJbll5dVkzY3V4MWlyam5OT3Zt
    ...     azBFPVxuIiwgIklWIjogIkQ0YUhEQ1VJbVhTUnFLZmN4MXRicmc9PVxuIn0='''.replace(' ','').replace('\n','')

    >>> import base64
    >>> import json
    >>> key_param = json.loads(base64.decodestring(key_data))
    >>> key_param
    {u'salt': u'kqFXQhS2DudFF21d+piFeInYyuY3cux1irjnNOvmk0E=\n', 
     u'password_encrypted': u'k9hsTunkwPDgDj4LV7QicqT2llhI4IKslgPU\n', 
     u'IV': u'D4aHDCUImXSRqKfcx1tbrg==\n'}

    >>> lambda d: dict([ (base64.decodestring(k.encode()), base64.decodestring(v.encode())) for k,v in d.items()])
    <function <lambda> at 0x7f4aba18dd70>
    >>> cv = _
    >>> key_param = cv(key_param)
    >>> key_param
    {'password_encrypted': '\x93\xd8lN\xe9\xe4\xc0\xf0\xe0\x0e>\x0bW\xb4"r\xa4\xf6\x96XH\xe0\x82\xac\x96\x03\xd4', 
     'salt': '\x92\xa1WB\x14\xb6\x0e\xe7E\x17m]\xfa\x98\x85x\x89\xd8\xca\xe67r\xecu\x8a\xb8\xe74\xeb\xe6\x93A', 
      'IV': '\x0f\x86\x87\x0c%\x08\x99t\x91\xa8\xa7\xdc\xc7[[\xae'}

pycrypto & AES CBF

pycryptoがあれば使います。
blockサイズ32で CFBブロック暗号化
saltを使ってキーを派生させます


    >>> from Crypto.Protocol.KDF import PBKDF2
    >>> from Crypto.Cipher import AES
    >>> pw_key = PBKDF2('root', key_param['salt'], 32)
    >>> cipher_key = AES.new(pw_key[:32], AES.MODE_CFB, key_param['IV'])
    >>> keyring_password = cipher_key.decrypt(key_param['password_encrypted']).decode('utf8')
    >>> keyring_password
    u'pw:password reference value'

    プレフィックス除く
    >>> p = keyring_password[3:]
    >>> p
    u'password reference value'

同じくユーザーデータ

    >>> user_data ='''eyJwYXNzd29yZF9lbmNyeXB0ZWQiOiAiY1VNVERaT1F4YWh4SElvPVxuIiwgInNhbHQiOiAicTg3
    ...     L0hDcmVOYTk1blBydFlvZVl4czB6aEVlSzVxMWdFTnUvdGtKRUhtYz1cbiIsICJJViI6ICI1TU5G
    ...     RjBZbnZzdyt2elFabWNTNmF3PT1cbiJ9'''.replace(' ','').replace('\n','')

    >>> user_param = cv( json.loads( base64.decodestring(user_data) ) )
    >>> user_param
    {'password_encrypted': 'qC\x13\r\x93\x90\xc5\xa8q\x1c\x8a', 'salt': '\xab\xce\xff\x1c*\xde5\xafy\x9c\xfa\xedb\x87\x98\xc6\xcd3\x84G\x8a\xe6\xad`\x10\xdb\xbf\xb6BD\x1eg', 'IV': "\xe4\xc3E\x17F'\xbe\xcc>\xbf4\x19\x99\xc4\xbak"}


    >>> pw_user = PBKDF2('root', user_param['salt'], 32)
    >>> cipher_user = AES.new(pw_user[:32], AES.MODE_CFB, user_param['IV'])
    >>> cipher_user.decrypt(user_param['password_encrypted']).decode('utf8')[3:]
    u'password'
16
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
19