民生用DVDプレーヤーで再生できるDVDをつくる2007/05/10 15:35

我が家のiMac G5 (iSight)にはスーパードライブが搭載されている。システムプロファイルで確認すると、このドライブは松下製で、DVD+R DL※1の書き込みに対応している。ローカルディスクに放り込んであるVIDEO_TSフォルダを民生用のDVDプレーヤーで再生するためにDVD+R DLのメディアに焼こうと試みて、ドツボにはまった。Toastなどの特別なソフトを購入せずにやろうとすると、素人にはなかなか難しい。

DVD+R DLはDVD-ROM化する。

まず結論から言って、ドライブはLacie D2を新調した。内蔵の松下製ドライブでDVD+R DLへの書き込みができるにもかかわらず、わざわざ二重投資してまでドライブを購入したのにはいくつか理由がある。我が家のiMac G5はただでさえ稼働時の放熱に心配を抱えているので、CPUとドライブに同時に負荷のかかりそうなDVDの書き込み処理は、できれば外部のドライブに押し出したかったからだ。また、外部ドライブを導入すれば、Combo Drive(DVD書き込み機能なし)のiBook G4からでもDVDへの書き込みができるようになる、という利点もある。

もう一つ、外部ドライブにした理由は、ネットを漁ってもiMac G5(iSight)に搭載されている松下製のドライブがDVD+R DLをROM化してくれるかどうかわからなかったからだ。我が家のテレビにつながっているDVDプレ−ヤーはパイオニアのDVR-515H-Sというハードディスクレコーダーで、DVD-R系にしか対応していない。DVD+R DLに焼いただけでは、おそらく再生できない。未検証だけれど...

Lacie D2はDVD+R DLの焼き込み完了時にbook typeをDVD-ROMにする機能がある※2ので、パイオニアのDVDプレーヤーとの互換性が期待できる。

hdiutilでUDFフォーマットに変換。

最初、VIDEO_TSフォルダの上位フォルダからCD/DVDマスター形式のディスクイメージを作成し、それをDVDに焼けばいいだろう、と考えていた。どちらの作業もディスクユーティリティからおこなえる。

... が、そうではない。ネットの情報を漁っていると、とある掲示板にディスクユーティリティでISO9660形式のボリュームの作成が可能、と書かれていた。だがいろいろディスクユーティリティを試してみたが、ディスクユーティリティでは望む結果は得られないようだ。拡張子が.cdrのCD/DVDマスター形式のディスクイメージは作成できる。これをDVD+R DLやDVD-Rといったメディアにそのまま焼く。最後に焼き上がったメディアをいったん排出して再度DVDドライブに射し込むと... 期待する動作はDVDプレーヤーが起動して再生がはじまることだが... 結果はデスクトップにマウントされるだけ。DVDプレーヤーを手動で起動してマウントされたボリュームを読み込ませようとしても拒絶される。どうやら、このディスクはMac OS拡張フォーマットとして認識されてしまっているのが問題のようだ。ちなみにVLCでも再生できない。素人の知識では、VLCで認識できないのであれば、何をどのようにしてもこのディスクからビデオを再生する術はない。

ディスクユーティリティに見切りを付けてさらにネットを徘徊していると、mkisofsというコマンドをMac OS Xに入れると、Mac OS拡張フォーマットではなくDVD-Videoフォーマットのディスクイメージを作成できるらしい、ということがわかった。 使い方は、

mkisofs -f -dvd-video -udf -V <volume_name> \
    -o <image_name>.img <folder>/
である。

ここで、それぞれのオプションは次の通り。

-f: シンボリックリンクを追跡する
-dvd-video: DVD-Videoフォーマット互換のUDFフォーマットにする
-udf: 生成されるイメージにUDFサポートを含める
-V: ボリューム名
-o: 出力ファイル名

最後の<folder>はVIDEO_TSを含むフォルダの名前。

mkisofsで作成されたディスクイメージをファインダからダブルクリックすると、デスクトップにマウントされる。ダブルクリックするだけではDVDプレーヤーは起動しない。が、DVDプレーヤーを手動で起動すると、マウントされているボリュームにDVD-Video形式のものがあると認識するらしく、再生が始まる。このディスクイメージをディスクユーティリティでDVD-RやDVD+R DLに焼くと、すくなくとも我が家のパイオニアDVR-515H Sでは問題なく再生できた。

ところで、ネットを徘徊していると、わざわざmkisofsを拾ってこなくても、Mac OS Xに標準でついているhdiutilというツールでUDFフォーマットのディスクイメージをつくれるらしい。

hdiutilでmkisofsと同じことができるか実際に試してみたら... できた。使い方は下記の通り。

hdiutil makehybrid -o <output_name> \
    <folder> -iso -udf \
    -udf-volume-name <volume_name>

-o オプションには、生成されるディスクイメージの名前を指定する。つづく<folder>はVIDEO_TSフォルダを含むフォルダの名前。<volume_name>にはディスクのボリューム名を指定する。

hdiutilが生成するディスクイメージをファインダからダブルクリックすると、デスクトップにマウントされる。この状態でDVDプレーヤーを立ち上げると、自動的に再生が始まる。mkisofsと同じことができるようだ。

よくは知らないが、ディスクユーティリティーも下回りでhdiutilを呼んでるのだと思う。なぜにディスクユーティリティでDVD-Video(あるいはUDF)形式のディスクイメージを作成できないようになってるのかわからない。ハリウッドと仲良くするためにわざとそうなっているのかもしれない。

2層書き込みはディスクユーティリティで。

片面2層の書き込みに関しては、Mac OS X 10.4.9以降はディスクユーティリティが対応しているようで、問題なく行える。Lacie D2にはToast 6 Liteがついてきたが、これでToast 6 Liteは出番なし。

まとめ

結局、手順としては次の通り。

  1. VIDEO_TSフォルダを準備する。
  2. 4.7Gを超えるデータを扱う場合には、DVD+R DLのメディアと対応しているドライブを用意する。Mac OS Xのシステムプロファイラのハードウェアセクションで、「ディスク作成」の「書き込み方法」にDVD+R DLがリストされていれば、そのドライブは DVD+R DLを扱える。
  3. hdiutilでISO9660かつDVD-Video(UDF)形式のディスクイメージを作成する。VIDEO_TSフォルダのひとつ上のフォルダから作成する。
  4. ディスクユーティリティでメディアに焼く。

 

※1: DVD+R DL
DVD+Rで、片面2層に焼くための企画。DLはDouble Layerの頭文字。ちなみにDVD-Rのほうの片面2層の規格はDVD-R DLだが、こちらのDLはDual Layerだそうな。DVD+R DLは、DVD+R9 と書かれていることもある。

※2: DVD-ROMにする機能がある
最近の大抵のドライブでは民生用のDVDプレーヤーとの互換性を重視して、ROM化機能を搭載している -- と、秋葉原ソフマップの店員さんが教えてくれた。

公開鍵の秘密 -追補- 32007/02/09 15:32

次に ssh-keygen が実際に秘密鍵を作成する部分のコードを見てみる。
ssh-keygen.c をたどっていくと、

   1338         private = key_generate(type, bits);
   1339         if (private == NULL) {
   1340                 fprintf(stderr, "key_generate failed");
   1341                 exit(1);
   1342         }

となっている。private は Key 型へのポインタである。key_generate() は key.c で定義されている。

    594 Key *
    595 key_generate(int type, u_int bits)
    596 {
    597         Key *k = key_new(KEY_UNSPEC);
    598         switch (type) {
    599         case KEY_DSA:
    600                 k->dsa = dsa_generate_private_key(bits);
    601                 break;
    602         case KEY_RSA:
    603         case KEY_RSA1:
    604                 k->rsa = rsa_generate_private_key(bits);
    605                 break;
    606         default:
    607                 fatal("key_generate: unknown type %d", type);
    608         }
    609         k->type = type;
    610         return k;
    611 }

key_generate() はとても短い。key->type が KEY_RSA のときには、rsa_generate_private_key() を呼び出す。この関数は key.c で定義されている。

    569 static RSA *
    570 rsa_generate_private_key(u_int bits)
    571 {
    572         RSA *private;
    573
    574         private = RSA_generate_key(bits, 35, NULL, NULL);
    575         if (private == NULL)
    576                 fatal("rsa_generate_private_key: key generation failed.");
    577         return private;
    578 }

鍵が RSA 形式の時には、rsa_generate_private_key() の中で RSA_generate_key() を呼んでいる。紛らわしいが、大文字で始まるほうの RSA_generate_key() は、openssl のソースに含まれているので、これ以上 OpenSSH のソースコードを漁っても何も得られない。

openssl-0.9.8d を展開したあと、crypto ディレクトリに移動するとそこに rsa_depr.c というソースコードがある。RSA_generate_key() はそこに定義されている。

     71 RSA *RSA_generate_key(int bits, unsigned long e_value,
     72              void (*callback)(int,int,void *), void *cb_arg)
     73         {
...中略
     92         if(RSA_generate_key_ex(rsa, bits, e, &cb)) {
     93                 BN_free(e);
     94                 return rsa;
     95         }

とまぁ、RSA_generate_key() のなかでは今度は RSA_generate_key_ex() を呼び出している。_ex つきの関数は rsa_gen.c の定義されている。これで何度目のリダイレクトだ?

rsa_gen.c では、

    78 int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb)
     79         {
     80         if(rsa->meth->rsa_keygen)
     81                 return rsa->meth->rsa_keygen(rsa, bits, e_value, cb);
     82         return rsa_builtin_keygen(rsa, bits, e_value, cb);
     83         }

RSA_generate_key_ex() の関数は、これがすべてである。

本当の鍵の生成は rsa_builtin_keygen() を呼び出しておこなっており、rsa_builtin_keygen() は RSA_generate_key() の直後から定義されている。この関数は長いので割愛。

さて、話を元に戻すと、key_generate() の結果を private (Key 型へのポインタ)に保存すると、その先の処理は大きく分けて二つある。一つは private から公開鍵を生成すること、そしてもうひとつは private を秘密鍵として保存することである。

もう一度 key_generate() の部分を ssh-keygen.c から抜き出すと下記のとおりで、これは今回の冒頭に挙げているものと同じだ。

   1338         private = key_generate(type, bits);
   1339         if (private == NULL) {
   1340                 fprintf(stderr, "key_generate failed");
   1341                 exit(1);
   1342         }

private = key_generate(type, bits); の処理で、private には RSA の鍵情報が入っている。この直後に、

   1343         public  = key_from_private(private);

として、private の内容から公開鍵の情報を取り出して、やはり Key 型へのポインタである public へ代入している。

そして、最終的に、

   1405         if (!key_save_private(private, identity_file, passphrase1, comment)) {
   1406                 printf("Saving the key failed: %s.\n", identity_file);
   1407                 memset(passphrase1, 0, strlen(passphrase1));
   1408                 xfree(passphrase1);
   1409                 exit(1);
   1410         }

と、key_save_private() で identity_file に設定されているファイルへ書き出すのである。

最後に見るのは、key_save_private() だ。この関数は OpenSSH の authfile.c で定義されている。

    204         switch (key->type) {
    205         case KEY_DSA:
    206                 success = PEM_write_DSAPrivateKey(fp, key->dsa,
    207                     cipher, passphrase, len, NULL, NULL);
    208                 break;
    209         case KEY_RSA:
    210                 success = PEM_write_RSAPrivateKey(fp, key->rsa,
    211                     cipher, passphrase, len, NULL, NULL);
    212                 break;
    213         }

と、key->type が KEY_RSA なら PEM_write_RSAPrivateKey() を呼び出す。この PEM_write_RSAPrivateKey() はマクロで、openssl-0.9.8d/crypto/pem/pem.h に次のように定義されている。

    409 #define PEM_write_RSAPrivateKey(fp,x,enc,kstr,klen,cb,u) \
    410                 PEM_ASN1_write((int (*)())i2d_RSAPrivateKey,PEM_STRING_RSA,fp,\
    411                         (char *)x,enc,kstr,klen,cb,u)

つまり、PEM_ASN1_write である、と。

openssl-0.8.9d/crypto/pem/pem_lib.c に実際の PEM_ASN1_write() が定義されている。

結果から言うと、PEM_ASN1_write() からは更に PEM_ASN1_write_bio() を呼び出しており、正真正銘、これが最終最後の場所なのだが、はっきりいって、中身をみても良くわからん... 結局、ssh-keygen で id_rsa を生成するときに、p、q、d、n、e の情報を格納していると確信できる部分までだ取り付けていない。今後の宿題かなぁ...

暗号関連、嫌いです。

公開鍵の秘密 -5- 完結編2007/02/09 00:19

完結編。

やはり,まずは標準にあたるべきである。

RFC 2313 - PKCS #1: RSA Encryption Version 1.5のセクション 7.2 にこうある。

7.2 Private-key syntax

   An RSA private key shall have ASN.1 type RSAPrivateKey:

   RSAPrivateKey ::= SEQUENCE {
     version Version,
     modulus INTEGER, -- n
     publicExponent INTEGER, -- e
     privateExponent INTEGER, -- d
     prime1 INTEGER, -- p
     prime2 INTEGER, -- q
     exponent1 INTEGER, -- d mod (p-1)
     exponent2 INTEGER, -- d mod (q-1)
     coefficient INTEGER -- (inverse of q) mod p }

   Version ::= INTEGER

   The fields of type RSAPrivateKey have the following meanings:
        o    version is the version number, for compatibility
             with future revisions of this document. It shall
             be 0 for this version of the document.
        o    modulus is the modulus n.
        o    publicExponent is the public exponent e.
        o    privateExponent is the private exponent d.
        o    prime1 is the prime factor p of n.
        o    prime2 is the prime factor q of n.
        o    exponent1 is d mod (p-1).
        o    exponent2 is d mod (q-1).
        o    coefficient is the Chinese Remainder Theorem
             coefficient q-1 mod p.

つまり,秘密鍵には encryption exponent も decryption exponent も両方格納されている。ご丁寧に,直後の note には,

        2.   The presence of the public exponent e is intended
             to make it straightforward to derive a public key from the
             private key.

ここで public exponent といっているのは,encryption exponent と同義だ。つまりは,public exponent(公開指数,暗号化指数)がここにあるのは,秘密鍵から公開鍵を容易に生成できるようにするためであると明解に書かれている。

あー。すっきりした。

つまりは,秘密鍵から公開鍵を生成できないというのは,僕の単なる思い込みなのであった。

正確には decryption exponent (d) と moduli (n) の組み合わせ(これが厳密な意味での秘密鍵だ)からは,encryption exponent (e) と moduli (n) の組み合わせ -- 公開鍵 -- は推測できない。だが,秘密鍵を格納しているファイルには,公開鍵を生成するための encryption exponent (public exponent)が仕込まれていたんである。

ソースを追いかけること 3時間。無駄だったのか,楽しかったのか...

すっきり2006/01/19 10:28

仕事のメールが 1,000 通ほど INBOX に溜まっていたのを、ぜーんぶ消したらすっきりした。

年賀状2006/01/09 00:03

やっと年賀状を書き終わった。

年が明ける前に年賀を書かないのが我が家の決まりだ。
そもそも,年が改まる前に「旧年中は...」と書くとはどういう魂胆だ?
新年を迎えてから,気持ちを新たにして年賀の挨拶に取り組むべきではないか。

... などと理由を並べてみても,年が明けて年賀状が届いていよいよ切羽詰まらないと思い腰があがらないという,つまりはたんにグータラなだけなのであった。

あーあ。なんで年賀状なんて風習があるんだろう?

年甲斐もなく2005/12/23 00:45

忘年会でオリエンタルラジオなんてやったら,もう体が動きません。
えぇ,ムリです。年齢上。
部下の手前,クレームメールを打たにゃならんときもあるとです。
えぇ,ムリです。精神衛生上。

折れそうなとき2005/12/07 00:02

仕事が立て込んで余裕がなくなってくると,心が折れてくる。
仕事の対象が技術から人に移ってから,心が折れる兆候ははっきりしている。
人の,良い面ではなく悪い面ばかりを探し,それにどう対処しようか考え始めるのだ。

悪い面ばかりを思いあぐねても,いい考えは浮かばない。仕事の嵐が過ぎ去るのを待つしかない。

mini って安い?2005/11/25 14:55

さて,G4 Cube の代替品を何にしようかとアップルストアをうろついていた。

【買い替え条件】

- メモリ 1G。
- G4 Cube と一緒に購入したディスプレイはリプレース。
- ハードディスクは 80G バイト以上。
- DVD が焼ける光学ドライブ。
- AirMac Express で Music On The Air したいので,無線 LAN 必須。
- iMac にするなら,思い切ってワイアレスキーボード & マウス。
- アップル・ケア必須。

この条件で Mac mini と iMac G5 を比較する。

■Mac Mini の場合。
 - Mac Mini (1.25GHz PowerPC G4)
* 1GB DDR333 SDRAM - 1 DIMM
* 80GB Ultra ATA HDD
* 4x SuperDrive(DVD±RW/CD-RW)
* Bluetooth + AirMac Extreme カード
* 56K V.92 モデム
* アクセサリキット
* 20inch Cinema Display
* AppleCare Protection Plan - Mac mini
--------------------
計: 215,810円。

■iMac G5 の場合。
* 1GB 533 DDR2 SDRAM - 2x512
* 160GB Serial ATA drive
* SuperDrive(DVD+R DL/DVD±RW/CD-RW)
* Wireless Keyboard & Mouse (JIS) + Mac OS X
* AppleCare Protection Plan - iMac/eMac
--------------------
計: 193,960円。

問題は,単純な比較が難しいこと。
ガジェットさん曰く, mini の G4 に比べて iMac の G5 のほうが圧倒的に速いとのこと。CPU の処理性能の面では,iMac G5 のほうが圧倒的に有利だ。
一方で,写真のレタッチを考えると iMac の 17インチディスプレイよりも mini と一緒に買う 20" Cinema Display のほうが圧倒的に色のりが良いらしい。(これもガジェットさん情報)。

さぁ。あなたならどちらを買う?

生きてる実感2005/11/21 23:09

トラブルが多発すればするほど,悪だくみが冴えてくる。

三季2005/11/05 17:00

帰国前日,Palo Alto の Three Season というアジア料理の店に連れて行ってもらった。アヒルとかラムとか普段あんまり食べる機会のない肉を貪る。なかなかいけてる。店の雰囲気も落ち着いていていい感じ。なによりも,Samuel Adams はないけど青島ならおいてあるという思い切り感がいい。ここは「アジア料理」の店なのだ。

ところで,大学やショッピングセンターは存在するのにどうして地図上に Stanford という町がないんだろうと思っていたら,どうやら町の名前は Palo Alto でそこにある大学の名前が Stanford なんだとか。あ,そうですか。

にしても,Willow Street。素敵すぎ。