Hatena::ブログ(Diary)

そこはかとなく書くよ。

2010-10-03

keepass v1 DB ツール

keepassというパスワード保存ツールがあります。Windows/Linux/Mac/Androidと幅広いプラットフォームで使えるのが魅力です。

これのLinux版はkeepassxという名前であるのですが、ビルドにはQTが必要で、ターミナルからは使えません。というわけで、ターミナルから使えるツールが欲しいな、と思い、調査と実装をしてみました。

ヘッダの構造

ヘッダは124byte。

 0123 4567 89AB CDEF 0123 4567 89AB CDEF
+----+----+----+----+---------+----+----+
|sig1|sig2|flag|ver |    seed_rand      |
+----+----+----+----+----+----+----+----+
|  encription IV    |gron|entn|checksum |
+----+----+----+----+----+----+----+----+
| check_sum (cont)            |seed_key |
+----+----+----+----+----+----+----+----+
| seed_key (cont)             |seed_rotn|
+----+----+----+----+----+----+----+----+
  • gron
    • group number
  • entn
    • entity number
  • seed_rotn
    • seed rot number

Python的なunpackで書くとこんな感じ。

format = '<L L L L 16s 16s L L 32s 32s L'

Signature 1 は0x9AA2D903 で、Signature 2 は 0xB54BFB65 。

flagsは

  • DB_FLAG_SHA2 = 1
  • DB_FLAG_RIJNDAEL = 2
  • DB_FLAG_ARCFOUR = 4
  • DB_FLAG_TWOFISH = 8

Decrypt

decryptはこんな感じで行われます。

# headerをparse
header = parse_db(buffer)
# masterpassをsha256
key = hashlib.sha256(masterpass).digest()
# seed_keyを使ってECBモードなAESを作成
cipher = AES.new(header.seed_key,  AES.MODE_ECB)
# seed_rot_n回 keyをAESでencrypt
for i in range(1, self.header.seed_rot_n):
  key = self.cipher.encrypt(key)
# keyをsha256
finalkey = hashlib.sha256(key).digest()

# headerのencription ivを使ってCBCモードなAESを作成
cipher = AES.new(finalkey, AES.MODE_CBC, header.enc_iv)
# 複号
buf = cipher.decrypt(buf)
# 最後の一文字の文字コードを取得
extra = ord(buf[-1])
# その文字コードの数分だけ削る
buf = buf[:len(buf)-extra] # last len(extra) becomes blank                      

groupとentry

decryptしたあとは、groupとentryの情報を読み出して行きます。

これは、

  • type: 2byte
  • length: 4byte
  • value: length分

という構造になります。

typeの詳細はここでは省きますが、typeが0xFFFFがgroupとentryの終わりになります。これを、headerにある、n_groupsとn_entriesの数だけ繰り返します。

source

という辺りを実装したものをgithubに上げておきました。

http://github.com/shirou/kptool

まだDBへの書き出しなどは実装していませんが、自分的にはこれで十分だったりします。

参考文献

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証