セキュリティ部分について調べるつもりが、何か別の所まで調べてしまった気がする。
C:\Documents and Settings\USERNAME\Application Data\Dropbox\host.db
1行目
16進数表記の文字列。
16進数表記で40バイト。
バイナリ表記で20バイト。
C:\Documents and Settings\USERNAME\Application Data\Dropbox\dropbox.db
sqlite形式のデータベースファイル。
テーブルは以下3個。
block_cache config file_journal
configテーブル
設定が保存されてる。
1行でKeyとValue。
CREATE TABLE config ( id INTEGER PRIMARY KEY, key TEXT NOT NULL UNIQUE, value TEXT );
config.keyカラム
設定項目名。
sqlite> select id, key from config; 1|schema_version 2|last_revision 3|root_ns 4|host_id 5|email 6|ns_p2p_key_map 7|recently_changed3
config.valueカラム
PythonのPickleでシリアライズされたものをBase64でエンコードしてある。
デコードするPythonプログラム。
#!/usr/local/bin/python # set encoding=utf8 import sys, base64, pickle def main(): input = sys.argv[1] input = base64.b64decode(input) print pickle.loads(input) def usage(): print 'Usage: %s encoded_str' % sys.argv[0] if __name__=='__main__': if (len(sys.argv)==2): main() else: usage()
config.value (WHERE key='schema_version')
型 : int
値 : 6
config.value (WHERE key='last_revision')
型 : Dict
値 : {ルートNS: 見せられないlong}
ファイルを追加したりすると増えるのかもしれない。
リビジョンにしては数がでか過ぎる。
全ユーザ共通?とも考えたけど、コミットしても値は変わらない。
config.value (WHERE key='root_ns')
型 : long
いろんな所でキーとして使われている。
見せていいものか悪いものか解らないから、とりあえず「ルートNS」と表現する。
config.value (WHERE key='email')
型 : str
メールアドレス。
config.value (WHERE key='ns_p2p_key_map')
型 : Dict
値 : {ルートNS: (u'-----BEGIN CERTIFICATE-----\n見せられない\n-----END CERTIFICATE-----\n', u'-----BEGIN RSA PRIVATE KEY-----\n見せられない\n-----END RSA PRIVATE KEY-----\n', '見せられない')}
1つ目のstrは、RSA公開鍵。
2つ目のstrは、RSA秘密鍵。
3つ目のstrは、パスフレーズ?初期ベクトル?
MD5っぽい。
詳細不明。
公開鍵と秘密鍵はペアになっていた。
この使い方、公開鍵暗号方式として間違ってる気がする。
このペア、サーバ側にも置いてあるはず。
こんな使い方をするなら、Diffie-Hellmanとかでその都度鍵交換してもいいような気がする。
けど、それだと1回の通信の為に2回接続しなきゃいけない。
多分そこが問題だったから、こういう奇妙な形になったんだと予想。
サーバにサーバ秘密鍵とクライアント公開鍵、クライアントにクライアント秘密鍵とサーバ公開鍵、を入れれば、RSAを使って1回の通信で更にセキュアになる。
サーバとクライアントでRSAキーを分けない理由は不明。
多分面倒だったんだと思う。
再発行出来なくなるし。
クライアントを再インストールしたら、このRSAキーが復活してた。
もしかしたら、サーバから送られてきてるのかもしれない。
ペアになっている事を確認するPHPのプログラム。
<?php $public = '-----BEGIN CERTIFICATE----- 見せられない -----END CERTIFICATE-----'; $private = '-----BEGIN RSA PRIVATE KEY----- 見せられない -----END RSA PRIVATE KEY-----'; // 文字列からキーリソース生成 $public = openssl_pkey_get_public($public); $private = openssl_pkey_get_private($private); // 暗号化するデータ $data = 'あいうえお!'; // public keyで暗号化 openssl_seal($data, $sealed_data, $env_keys, array($public)); // private keyで復号化 openssl_open($sealed_data, $open_data, $env_keys[0], $private); echo $open_data."\n";
公開鍵の詳細。
どうやらこのキーはクライアント側で生成してるらしい。
$ openssl x509 -in public.crt -text Certificate: Data: Version: 4 (0x3) Serial Number: 1 (0x1) Signature Algorithm: sha256WithRSAEncryption Issuer: CN=dropbox-client Validity Not Before: Jan 1 00:00:00 1970 GMT Not After : Jul 18 17:14:19 2030 GMT Subject: CN=dropbox-client Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1536 bit) Modulus (1536 bit): 見せられない Exponent: 見せられない (見せられない) Signature Algorithm: sha256WithRSAEncryption 見せられない -----BEGIN CERTIFICATE----- 見せられない -----END CERTIFICATE-----
$ openssl asn1parse -in public.crt 0:d=0 hl=4 l= 548 cons: SEQUENCE 4:d=1 hl=4 l= 333 cons: SEQUENCE 8:d=2 hl=2 l= 3 cons: cont [ 0 ] 10:d=3 hl=2 l= 1 prim: INTEGER :03 13:d=2 hl=2 l= 1 prim: INTEGER :01 16:d=2 hl=2 l= 13 cons: SEQUENCE 18:d=3 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption 29:d=3 hl=2 l= 0 prim: NULL 31:d=2 hl=2 l= 25 cons: SEQUENCE 33:d=3 hl=2 l= 23 cons: SET 35:d=4 hl=2 l= 21 cons: SEQUENCE 37:d=5 hl=2 l= 3 prim: OBJECT :commonName 42:d=5 hl=2 l= 14 prim: PRINTABLESTRING :dropbox-client 58:d=2 hl=2 l= 30 cons: SEQUENCE 60:d=3 hl=2 l= 13 prim: UTCTIME :700101000000Z 75:d=3 hl=2 l= 13 prim: UTCTIME :300718171419Z 90:d=2 hl=2 l= 25 cons: SEQUENCE 92:d=3 hl=2 l= 23 cons: SET 94:d=4 hl=2 l= 21 cons: SEQUENCE 96:d=5 hl=2 l= 3 prim: OBJECT :commonName 101:d=5 hl=2 l= 14 prim: PRINTABLESTRING :dropbox-client 117:d=2 hl=3 l= 221 cons: SEQUENCE 120:d=3 hl=2 l= 13 cons: SEQUENCE 122:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption 133:d=4 hl=2 l= 0 prim: NULL 135:d=3 hl=3 l= 203 prim: BIT STRING 341:d=1 hl=2 l= 13 cons: SEQUENCE 343:d=2 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption 354:d=2 hl=2 l= 0 prim: NULL 356:d=1 hl=3 l= 193 prim: BIT STRING
config.value (WHERE key='recently_changed3')
型 : list
値 : [(u'ルートNS:/Public/How to use the Public folder.rtf', 0), (u'ルートNS:/Photos/Sample Album/Pensive Parakeet.jpg', 0), (u'ルートNS:/Photos/Sample Album/Costa Rican Frog.jpg', 0), (u'ルートNS:/Photos/Sample Album/Boston City Flow.jpg', 0), (u'ルートNS:/Photos/How to use the Photos folder.rtf', 0)]
file_journal.server_pathが5個入ってた。
keyの通り、最近更新されたファイル。
新しいものが先頭に追加されるらしい。
タプル2つ目はリビジョンかと思ったけど違うらしい。
ファイルを追加・更新したら0。
ファイルを削除したらNULL。
block_cacheテーブル
ファイルのキャッシュ(ログ)。
ファイルを追加・更新すると1行増える。
ファイルを削除しても、追加も削除もされない。
CREATE TABLE block_cache ( id INTEGER PRIMARY KEY, hash VARCHAR(43) NOT NULL UNIQUE, sig TEXT, size INT, delete_after INT, needed_for INT );
block_cache.hashカラム
43文字のASCII文字列。
file_journal.active_blocklistと一致。
Base64エンコードされた文字列かと思いきや、なんとなく違う。
多分プログラムがユニークになるように生成してる。
block_cache.sigカラム
Base64エンコードされた文字列。
ファイルのサイズに応じて長くなるらしい。
keyから察するに、署名だと思われるが、長さが違う気がする。
最初の16文字(バイナリ表記で12バイト)は全ての行で一致していた。
block_cache.sizeカラム
ファイルのサイズ。(バイト数)
コミット時、file_journal.active_sizeと一致。
block_cache.delete_afterカラム
全部0。
詳細不明。
block_cache.needed_forカラム
全部NULL。
詳細不明。
file_journalテーブル
ファイル一覧。
ファイルを追加すると、このテーブルに1行追加される。
ファイルを削除すると、このテーブルから物理削除される。
CREATE TABLE file_journal ( id INTEGER PRIMARY KEY, server_path TEXT NOT NULL UNIQUE, active_server_path TEXT, active_blocklist TEXT, active_mtime INT, active_size INT, active_sjid INT UNIQUE, active_dir INT, active_attrs TEXT, updated_server_path TEXT, updated_blocklist TEXT, updated_mtime INT, updated_size INT, updated_sjid INT, updated_dir INT, updated_attrs TEXT, on_disk TINYINT );
file_journal.server_pathカラム
値 : ルートNS:/photos/how to use the photos folder.rtf
日本語はそのまま日本語で入っていた。
file_journal.active_server_pathカラム
file_journal.server_pathと一致。
file_journal.active_blocklistカラム
block_cache.hashと一致。
file_journal.server_pathがディレクトリの場合は空文字列。
file_journal.active_mtimeカラム
ファイルを最後に更新(コミット?)した時間。
Unixtime。
file_journal.active_sizeカラム
ファイルのサイズ。(バイト数)
最終更新のblock_cache.sizeと一致。
file_journal.active_dirが1の場合は0。
file_journal.active_sjidカラム
詳細不明。
UNIQUEのint。
file_journal.active_dirカラム
ディレクトリだったら1。
ファイルだったら0。
file_journal.active_attrsカラム
config.valueと同様、PickleでシリアライズされたものをBase64でエンコードしたもの。
デフォルトで入ってたファイルは{}で、自分で追加したファイルはNULLだった。
LinuxとかMacとかで使った時に、パーミッションとか属性とかが入るのかも知れない。
file_journal.updated_server_pathカラム
詳細不明。
全部NULLだった。
file_journal.updated_blocklistカラム
詳細不明。
全部NULLだった。
file_journal.updated_mtimeカラム
詳細不明。
全部NULLだった。
file_journal.updated_sizeカラム
詳細不明。
全部NULLだった。
file_journal.updated_sjidカラム
詳細不明。
全部NULLだった。
file_journal.updated_dirカラム
詳細不明。
全部NULLだった。
file_journal.updated_attrsカラム
詳細不明。
全部NULLだった。
file_journal.on_diskカラム
詳細不明。
全部1だった。
登録からセキュアな通信までの流れ(妄想)
通信
・RSA公開鍵でデータ暗号化。
・送る。
・RSA秘密鍵でデータ復号化。
パケットを見る限り、443ポートとやりとりしてる。
暗号化したデータをHTTPSで流してる気がする。(2重で暗号化)
RSA-encryption over HTTP over SSL。
HTTP(アプリケーション層)の上に仮想的なレイヤー(Dropboxの独自仕様)を作ってその上で動かす。
レイヤーと言える程きっちりしたものではないかもしれないけど。
これは前に作ったOAuth Encryptionに似てる。
データ部分は2重で暗号化されているとして、何かユニークなIDを普通のHTTPSで見れる状態で送ってるはず。
考えられるユニークIDは、email位しかなさそう。