mac
「パスワードの管理を避ける」という考え方
その一方でパスワードをきっちり管理することは必ずしも簡単ではありません。平易な内容だと第三者によって類推・導出されるリスクが大きいものの複雑にすると覚えにくい。だからと言って複数のサービスで同じものを使いまわすとそれが漏洩した場合に一斉に攻撃を受ける危険がある。結局、安全度の高いパスワードをサービスごとに使い分けることは人間の記憶だけでは困難なので何らかの外部記憶を利用することになります。ただし、それが何らかのデバイスであれコンピュータデータの形式であれ、情報としてそこへ保存した時点で盗難・流出の可能性はゼロではなくなります。多くの場合、そういった諸々の事情を含んだ上で手元の実用上の便宜とのバランスを判断して管理方法を決めることになりますね。
社内でそういう話をしていた時にふと思いました。一般に秘密文字列の内容は文字の並びとして意味をなさないものであるほど効果的なわけで、そのような情報はあまり「人間向き」とは言えないでしょう。もともと人間向きではない上に内緒にしておきたい情報を人間が丸ごと管理しようとすること自体に無理があるのではないか?その情報を直接管理せずに済ませることはできないか?生々しいパスワードをどこにも保管せずにすむのならそれにこしたことはありません。
ソースコードと実行形式の関係を連想しました。プログラムのソースコードとそれをビルドする環境があればビルドずみの実行形式そのものを保持し続けることは必須ではありません。そのことと同様に所定の情報もまた必要な時に正しく用いることができれば十分であり、それを再現可能とする材料をあらかじめ揃えておけば情報そのものを恒常的に保持することを免れるはずです。
その切り口で方法のひとつを考えてみました。一方向関数の応用です。
- 利用者が任意のフレーズ (A) を灰色の変換器へ投入すると文字列 (D) が出力される
- 処理 (B) の変換規則は決め打ちではなく、ランダムな内容で生成ずみの所定のフィルタ (C) を参照して決定される
- (C) には (D) へ含める文字のバリエーションと (D) の文字列長を定義可能
- 処理に際し利用者は任意の (C) を指定する
- 固有の (A) (B) (C) の組合せは固有の (D) を生成する
- (A) から (D) への変換は不可逆
このようにいたってシンプルな内容ですが、同様のアイディアが形になったものを今のところ知らずこうした話題には興味を感じます。前述のようにパスワードの管理に外部記憶を使わざるを得ない最大の理由は「それがパスワードとして適切な内容であればあるほど人の記憶に馴染まないから」という皮肉な事情にありますが、たとえばこういった方法なら人間の記憶というとても貴重なリソースを最大限に活かせるのではないか?という気がします。
実装例
試みに上のアイディアを Mac OS X 用 / Android 用アプリとして実装してみました。より便利に使うための機能を付加する余地が随所にあるものの この内容でも相応の実用性はありそうです。
2018年6月追記:DropBox API の仕様変更に伴い Android 版アプリは一旦公開停止としています。現時点では改訂の目処が立っておらず、本アプリを利用して下さった皆様には大変ご迷惑をおかけしますが宜しくご了承下さい。
- Mac OS X 版: NoPass100.dmg
(535,655 bytes md5sum: 95bf7543509f4752b2da204fc545106b) - Android 版:
NoPass- Google Play ストア - ソースコード: NoPass - GitHub
- アプリでは前述 (C) のフィルタデータを「マップデータ」の呼称で統一しています
- Max OS X 版は "~/Library/Application Support/NoPass/NoPass.dat" へマップデータを出力します
- Dropbox 経由で複数の環境から同じマップデータを利用できます
- Mac OS X 版はマップデータの 使用/ 作成/ 編集/ 削除/ アップロード/ ダウンロード/ 同期 が可能です
- Android 版はマップデータの 使用/ ダウンロード のみが可能であり Mac OS X 版の併用と Dropbox アカウントが必要です
- 動作の様子(動画 1分19秒 無音)
- アプリ画面
(tanabe)
「stone for iOS」について
オープンソースの多機能パケットリピータ「stone」は数多くの OS プラットフォームで利用されています。スマートフォンまわりでは先年手元で Android 環境向けのポーティングを行いましたが、このところ iPhone を使う機会が増えていることもあり iOS 環境でも動かしたいと考えました。iOS 用 GUI アプリとしてひと通り動作するようになったため次の場所で公開しています。興味のある方はお試し下さい。
iTunes App Store -stone for iOSソースコード: GitHub - stone for iOS
使い方
アプリの使い方を簡単に説明します。
メイン画面
画面最上部のコマンドフィールドに stone パラメータを記述します。パラメータの記述方法は「stone の README」を参照して下さい。
各ボタンの機能
- [Run] - stone の処理を開始します
- [Stop] - 本アプリケーションを終了します
- [Clear] - 表示中のログを消去します
- [History] - コマンド履歴を表示します
- ツールボタン - ツールメニューを表示します
"-dd www.gcd.org:80 1234"
初期状態でコマンドフィールドに表示されている上記のパラメータは stone の効果を確認するためのサンプルです。[Run] で stone の処理を開始し、ブラウザから
http://[この端末の IP アドレス]:1234/
へアクセスすると http://www.gcd.org/ (stone 公式サイト)へ繋がります。
コマンド履歴画面
stone で実行したコマンドパラメータの履歴です。タップするとメイン画面のコマンドフィールドへペーストされます。「編集」ボタンからエントリの削除・並べ替えができます。
ツールメニュー
各種設定やヘルプを表示します。詳細は各画面をご覧下さい。
ローカルファイルの保存
".stone" の拡張子が付与された任意のファイルをメーラ等のアプリケーション上でタップすると、そのファイルを本アプリケーションのローカルファイルとしてコピーすることができます。保存ずみのローカルファイルは stone パラメータへの指定が可能です。
(例)"-C stone.cnf"
※現バージョンの stone for iOS は、iOS キーチェーンへの電子証明書のインポートおよび参照には未対応です。証明書はローカルファイルとして保存した上で使用して下さい。
謝辞
本ソフトウェアは以下のオープンソースソフトウェア資産を使用しています。素晴らしいソフトウェアを公開されている各氏に深謝いたします。
Copyright (c) 1995-2014 by Hiroaki Sengoku
「この stone に関する全ての著作権は、原著作者である仙石浩明が所有します。この stone は、GNU General Public License (GPL) に準ずるフリーソフトウェアです。個人的に使用する場合は、改変・複製に制限はありません。配布する場合は GPL に従って下さい。また、openssl とリンクして使用することを許可します。」
「この stone は無保証です。この stone を使って生じたいかなる損害に対しても、原著作者は責任を負いません。詳しくは GPL を参照して下さい。」
Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
"This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
"THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
"This product includes cryptographic software written by Eric Young (eay@cryptsoft.com). This product includes software written by Tim Hudson (tjh@cryptsoft.com)."
(tanabe)
* Cryptographic Software Notice *This software includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See http://www.wassenaar.org/ for more information.
The U.S. Government Department of Commerce, Bureau of Industry and Security (BIS), has classified this software as Export Commodity Control Number (ECCN) 5D002.C.1, which includes information security software using or performing cryptographic functions with asymmetric algorithms. The form and manner of this distribution makes it eligible for export under the License Exception Technology Software Unrestricted (TSU) for both object code and source code. (see the BIS Export Administration Regulations, Section 740.13)
Mac OSX で vmnet が BIOCSETIF できなくてハマった話し
1年くらいブログ記事書くのをサボっていたので、ちょっとマニアックなネタを投下します。ISUCON3 は予選で敗退してしまった @pandax381 です。
vmnet が BIOCSETIF できない!
Mac OSX(marvericks)で VMware Fusion 6 を使っているのですが、ホスト側の仮想インタフェース(vmnetX)のパケットがキャプチャできないという問題に遭遇しました。具体的には、パケットをキャプチャするためにBPFデバイスをオープンして、vmnetX を ioctl(BIOCSETIF) でアタッチするの処理で失敗してしまうのです。一見普通のEthernetデバイスに見えるのに、どうしてBPFでパケットをキャプチャできないのか調べてみました。
tcpdump で試してみる
僕の作っていたプログラムがイケてないのかもしれないので、まずは tcpdump を使ってキャプチャできるか試してみます。そして、tcpdump先生でもダメならあきらめましょう。
tcpdump に -i オプションで vmnet8 を指定して実行してみます。
$ sudo tcpdump -i vmnet8 tcpdump: vmnet8: No such device exists (BIOCSETIF failed: Device not configured)
あれ、うまくいかない。。そういえば、OSX の tcpdump はインタフェース指定しなければ全てのインタフェースからキャプチャできたはずなので、-i オプションなしで実行してみます。
$ sudo tcpdump tcpdump: data link type PKTAP tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on pktap, link-type PKTAP (Packet Tap), capture size 65535 bytes 18:18:51.715943 IP 192.168.2.128 > 192.168.2.1: ICMP echo request, id 54865, seq 1, length 64 18:18:51.715969 IP 192.168.2.1 > 192.168.2.128: ICMP echo reply, id 54865, seq 1, length 64 18:18:52.715822 IP 192.168.2.128 > 192.168.2.1: ICMP echo request, id 54865, seq 2, length 64 18:18:52.715862 IP 192.168.2.1 > 192.168.2.128: ICMP echo reply, id 54865, seq 2, length 64 18:18:53.716669 IP 192.168.2.128 > 192.168.2.1: ICMP echo request, id 54865, seq 3, length 64 18:18:53.716705 IP 192.168.2.1 > 192.168.2.128: ICMP echo reply, id 54865, seq 3, length 64
ちゃんと vmnet8 に接続されている仮想マシンとのパケットが拾えています。tcpdump は何かしらの方法で vmnet8 を覗けているようです。
なにかオプションを指定する必要があるかもしれないので、マニュアルを見てみると・・・
On Darwin systems version 13 or later, when the interface is unspecified, tcpdump will use a pseudo interface to capture packets on a set of interfaces determined by the kernel (excludes by default loopback and tunnel interfaces). Alternatively, to capture on more than one interface at a time, one may use "pktap" as the interface parameter followed by an optional list of comma separated interface names to include. For example, to capture on the loopback and en0 interface: tcpdump -i pktap,lo0,en0
-i オプションの項目に、ずばり答えが書いてありました...^^;
・OSX(Darwin)の場合には、-i オプションを指定しないと「擬似インタフェース」を使用して全インタフェースからキャプチャする
・任意の複数のインタフェースでキャプチャする場合には -i pktap,lo0,en0 と指定する
どうやら pktap というのが「擬似インタフェース」で、これを使用すれば vmnet8 のパケットがキャプチャできそうなので、早速試してみます。
$ sudo tcpdump -i pktap,vmnet8 tcpdump: data link type PKTAP tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on pktap,vmnet8, link-type PKTAP (Packet Tap), capture size 65535 bytes 18:48:35.799610 IP 192.168.2.128 > 192.168.2.1: ICMP echo request, id 56686, seq 13, length 64 18:48:35.799679 IP 192.168.2.1 > 192.168.2.128: ICMP echo reply, id 56686, seq 13, length 64 18:48:36.802213 IP 192.168.2.128 > 192.168.2.1: ICMP echo request, id 56686, seq 14, length 64 18:48:36.802252 IP 192.168.2.1 > 192.168.2.128: ICMP echo reply, id 56686, seq 14, length 64 18:48:37.803839 IP 192.168.2.128 > 192.168.2.1: ICMP echo request, id 56686, seq 15, length 64 18:48:37.803876 IP 192.168.2.1 > 192.168.2.128: ICMP echo reply, id 56686, seq 15, length 64
ばっちりキャプチャできました!
tcpdump はどんな裏技を使っているのか
tcpdump がどんな処理をしているのかソースを解析してみます。
とりあえず、カレントバージョンの tcpdump と libpcap のソースを grep みるも「pktap」や「PKTAP」というキーワードが見当たらない。。。
仕方ないので、tcpdumpのバージョンを確認してみると
$ tcpdump -h tcpdump version 4.3.0 -- Apple version 56 libpcap version 1.3.0 - Apple version 41 Usage: tcpdump [-aAbdDefhHgIJkKlLnNOpPqQ:RStuUvxX] [ -B size ] [ -c count ] [ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ] [ -i interface ] [ -j tstamptype ] [ -M secret ] [ -Q metadata-filter-expression ] [ -r file ] [ -s snaplen ] [ -T type ] [ -w file ] [ -W filecount ] [ -y datalinktype ] [ -z command ] [ -Z user ] [ expression ]
ほほう、Apple version ですとな。カスタムバージョンのようなので、http://www.opensource.apple.com/source/ から tcpdump と libpcap を探します。
- http://www.opensource.apple.com/source/tcpdump/tcpdump-56/tcpdump/
- http://www.opensource.apple.com/source/libpcap/libpcap-42/libpcap/
この中をひたすら漁っていると、libpcap の中に「pcap-darwin.c」という、いかにもそれっぽいソースファイルが見つかりました。
pcap_setup_pktap_interface() や pcap_cleanup_pktap_interface() などの関数があるので、これで当たりのようです。
ざっとソースを眺めて、以下のことが分かりました。
- ioctl(SIOCIFCREATE) :PKTAPインタフェースを作成
- ioctl(SIOCSDRVSPEC) :PKTAPインタフェースのフィルタを設定(キャプチャするデバイスと除外するデバイスを設定できる)
- ioctl(SIOCIFDESTROY):PKTAPインタフェースを削除
そして、一番の知りたかった BPF で BIOCSETIF する際の処理では、実デバイスではなくPKTAPインタフェースを指定していました。
なるほど、謎は全て解けた!
自力でやってみる
なにをすれば良いか分かったので、早速自分でコードを書いてみました。
https://github.com/pandax381/pktap_demo/
- PKTAPインタフェースを作成
- 引数で指定されたデバイスをキャプチャ対象としてフィルタを設定(複数可、指定がなければ全てのデバイスが対象)
- BPFデバイスをオープンしてPKTAPインタフェース(pktapX)を指定
- 明示的にプロミスキャスモードにはしない(BIOCPROMISC が失敗する)
- BPFからパケットをキャプチャしてデバッグ出力
PKTAPインタフェースから取得したパケットには、struct pktap_header型のリンクヘッダが付いているので、詳細出力します。
※ /usr/include/ 配下に net/pktap.h が見当たらなかったので、XNU のソースツリーから拝借するようにしています
実行結果はこんな感じ
$ sudo ./pktap_demo vmnet8 ### pktap_debug_print ### pth_length: 108 pth_type_next: 1 pth_dlt: 1 pth_ifname: vmnet8 pth_flags: 1 pth_protocol_family: 2 pth_frame_pre_length: 14 pth_frame_post_length: 0 pth_pid: -1 pth_comm: pth_svc: 0 pth_iftype: 6 pth_ifunit: 8 pth_epid: -1 pth_ecomm: +------+-------------------------------------------------+------------------+ | 0000 | 00 50 56 c0 00 08 00 0c 29 6b b6 e9 08 00 45 00 | .PV.....)k....E. | | 0010 | 00 54 00 00 40 00 40 01 b4 d7 c0 a8 02 80 c0 a8 | .T..@.@......... | | 0020 | 02 01 08 00 ac fe ec 31 00 01 1e 14 9b 52 00 00 | .......1.....R.. | | 0030 | 00 00 e5 94 01 00 00 00 00 00 10 11 12 13 14 15 | ................ | | 0040 | 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 | .......... !"#$% | | 0050 | 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 | &'()*+,-./012345 | | 0060 | 36 37 | 67 | +------+-------------------------------------------------+------------------+ ### pktap_debug_print ### pth_length: 108 pth_type_next: 1 pth_dlt: 1 pth_ifname: vmnet8 pth_flags: 2 pth_protocol_family: 2 pth_frame_pre_length: 14 pth_frame_post_length: 0 pth_pid: -1 pth_comm: pth_svc: 0 pth_iftype: 6 pth_ifunit: 8 pth_epid: -1 pth_ecomm: +------+-------------------------------------------------+------------------+ | 0000 | 00 0c 29 6b b6 e9 00 50 56 c0 00 08 08 00 45 00 | ..)k...PV.....E. | | 0010 | 00 54 b5 a8 40 00 40 01 ff 2e c0 a8 02 01 c0 a8 | .T..@.@......... | | 0020 | 02 80 00 00 b4 fe ec 31 00 01 1e 14 9b 52 00 00 | .......1.....R.. | | 0030 | 00 00 e5 94 01 00 00 00 00 00 10 11 12 13 14 15 | ................ | | 0040 | 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 | .......... !"#$% | | 0050 | 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 | &'()*+,-./012345 | | 0060 | 36 37 | 67 | +------+-------------------------------------------------+------------------+
余談
Google先生に聞いても、唯一ヒットする情報は Apple先生のソースコードだけだったので、意地になって動くコードを書く所までやってみました。社内でドヤってみたけど、レイヤが低すぎたのか誰も反応してくれないのでブログを書いてみたという落ちです。後悔はしていない。
なお、PKTAP は ifconfig でも作成できます。pktap_demo のコード書き終わってから ifconfig のコードを読んでいて発見しました...orz
$ sudo ifconfig pktap create pktap0
$ sudo ifconfig pktap destroy
コマンドで PKTAP にフィルタを設定するには、pktapctl を自分でコンパイルすればできます。
http://opensource.apple.com/source/network_cmds/network_cmds-433/pktapctl/pktapctl.c
あと、そもそもの目的は vmnet に対して出力もしたかったのですが、PKTAPだとキャプチャ専用で出力はできないっぽいです。
@pandax381
Exif データにアクセスするコードを自作してみる
先日ちょっとしたアプリを書いていた折に JPEG ファイル内の Exif データを参照する処理が必要になりました。初めての機会だったのでやり方を調べたところ 開発環境向けに用意されたこれこれのライブラリを使うのが常道とのことで、リファレンスを読みながらそういうコードを書きました。プログラムは期待通りに動作しその時はそれで特にどうと言うこともなかったのですが、後日別のプラットフォームで Exif データを利用するアイディアを思いつき、その環境でまた別のライブラリの使い方など調べているうちに何だか面倒になりました。
ここでのターゲットはあくまでも一介のデータ形式です。既存のソフトウェア資産を利用することは生産性の上でも効率の面でも間違った選択ではないものの、「普通のファイルに記録されたデータ」にアクセスするための道具立てにいろいろ左右されることが煩わしく感じられたのです。Exif の規格は公開されているため仕様を確認して必要なコードを自作すれば今後この形式を既存のライブラリごしに「ブラックボックス」として扱う必要はなくなるはずで、また、自作のコードであれば拡張や応用の融通が利きやすく必要なら別のプログラム言語への移植も楽でしょう。
デジタルカメラという今日ではごく身近な道具を通じてその存在を知りながら中身をずっと知らずにいた Exif のしくみに触れることはそれ自体も興味ぶかい経験でした。その一端をご紹介します。C 言語で試作したソースコード一式を記事の最後に掲載しています。
Exif の仕様
まず Exif のデータ形式の仕様をできるだけコンパクトに整理してみます。もっとも詳しく正確なのはもちろん公式の規格書ですから不明な点があればそこでの記述を参照して下さい。
規格書
電子情報技術産業協会 (JEITA) ホームページ上の「JEITA 規格総合検索」フォームから、「規格名」に "Exif" を指定して検索を実行すると「JEITA CP-3451C デジタルスチルカメラ用 画像ファイルフォーマット規格 Exif 2.3」を電子文書として閲覧できます。 ※ 2013年8月31日現在
全体の構造
下の図は規格書をもとに JPEG ファイル中の Exif データの構造をまとめてみたものです。要点をピックアップしてみます。
タグフィールドの扱い方
どこにどのような情報が配置されているかは上の図を追えば把握できるでしょう。構造を順に辿って最後に到着するのは具体的なデータの格納された末端のタグフィールドです。もちろんこれらが最も重要な要素であり、ここではタグの値にアクセスする方法を説明します。
フィールドの構成
一件のタグフィールドには以下の内容が含まれます- タグ 番号 2 バイト 所定のタグを識別するための番号
- タイプ 2 バイト タグの値のデータタイプを示す
- カウント 4 バイト 値の個数
- オフセット 4 バイト 値の格納された位置
タグ名称 Field Name タグ番号(Hex) タイプ カウント Exif バージョン ExifVersion 9000 UNDEFINED 4 色空間情報 ColorSpace A001 SHORT 1 : : : : : ■ Exif バージョン ExifVersion 本規格での対応バージョンを示す。このフィールドが存在しなければ,本規格に準拠していない と判断される。本規格に準拠する場合には,4Byte の ASCII "0230" を記録しなければならない。 Type が UNDEFINED のため最後に NULL は記録してはならない。 Tag = 36864 (9000.H) Type = UNDEFINED Count = 4 Default = "0230" ■ : :
タイプについて
タグの値には以下のタイプがあります。値の取得方法は後述のカウント・オフセットのルールとの組合せで決まります。
カウントについて
カウントは「値の個数」を示します。「バイト数の合計」を表すものではありません。以下に例を示します。
オフセットについて
4 バイトのオフセット領域にはタグの値が記録されている位置(上図中の★が起点)が保持されています。ただし、値が 4 バイト以内で表現できる場合はその値がオフセット領域に直書きされます。4 バイト以内の値の例を以下に示します。
さらに、値の長さが 4 バイト未満の場合、値はオフセット領域に「左詰め」で格納されます。以下の要領です。
■ BYTE タイプの値 1
0 1 2 3 ┌─┬─┬─┬─┐ │01│00│00│00│ データのバイトオーダーがビッグエンディアンの場合 └─┴─┴─┴─┘ ┌─┬─┬─┬─┐ │01│00│00│00│ データのバイトオーダーがリトルエンディアンの場合 └─┴─┴─┴─┘
■ SHORT タイプの値 1, 3
0 1 2 3 ┌─┬─┬─┬─┐ │00│01│00│03│ データのバイトオーダーがビッグエンディアンの場合 └─┴─┴─┴─┘ ┌─┬─┬─┬─┐ │01│00│03│00│ データのバイトオーダーがリトルエンディアンの場合 └─┴─┴─┴─┘
データの実例
図は Exif セグメントを含むある JPEG ファイル冒頭部分の HEX ダンプイメージです。上述のデータ構造とデータ形式を踏まえてここから読み取られる 0th IFD の内容を併記しています。
試作したコード
C 言語で書いたソースコード一式を以下で公開しています。
Windows 用実行形式 (x86)
- 現在のバージョンには以下の機能があります
- 所定の JPEG ファイルの Exif セグメント中の一部またはすべての IFD の内容をダンプ表示
- 指定された IFD タイプ+タグ番号に該当するタグフィールドの情報を取得
- 所定の JPEG ファイルから Exif セグメントを除去した新しい JPEG ファイルを出力
- exif.c, exif.h の二本が実体で sample_main.c は関数呼び出しのサンプルです。
サンプルプログラムのビルドは以下の要領です- gcc の場合: gcc -o exif sample_main.c exif.c
- Microsoft Visual C++ の場合: cl.exe /o exif sample_main.c exif.c
- 標準ライブラリ関数のみを使っているため多くの環境での利用が可能です。手元では以下の組合せでの動作を確認しました
- Windows XP 32bit + Microsoft Visual C++ でビルドした 32bit バイナリ
- Windows 7 64bit + Microsoft Visual C++ でビルドした 64bit バイナリ
- Redhat Linux 32bit + 32bit 版 gcc でビルドしたバイナリ
- Mac OS X 64bit + 64bit 版 gcc でビルドしたバイナリ
- 動作確認用の test.jpg をサンプルプログラムで処理した結果を以下に引用します
$ ./exif test.jpg [test.jpg] createIfdTableArray: result=4 {0TH IFD} - Make: [Apple] - Model: [iPod touch] - Orientation: 1 - XResolution: 72/1 - YResolution: 72/1 - ResolutionUnit: 2 - Software: [6.1.4] - DateTime: [2013:09:01 09:49:00] - YCbCrPositioning: 1 - ExifIFDPointer: 206 - GPSInfoIFDPointer: 576 {EXIF IFD} - ExposureTime: 1/30 - FNumber: 12/5 - ExposureProgram: 2 - PhotographicSensitivity: 400 - ExifVersion: 0 2 2 1 - DateTimeOriginal: [2013:09:01 09:49:00] - DateTimeDigitized: [2013:09:01 09:49:00] - ComponentsConfiguration: 0x01 0x02 0x03 0x00 - ShutterSpeedValue: 4035/821 - ApertureValue: 4845/1918 - BrightnessValue: 2234/1113 - MeteringMode: 5 - Flash: 32 - FocalLength: 77/20 - FlashPixVersion: 0 1 0 0 - ColorSpace: 1 - PixelXDimension: 960 - PixelYDimension: 720 - SensingMethod: 2 - ExposureMode: 0 - WhiteBalance: 0 - FocalLengthIn35mmFormat: 32 - SceneCaptureType: 0 {GPS IFD} -- GPS 経由で得られた撮影地点の座標情報 - GPSLatitudeRef: [S] - GPSLatitude: 69/1 17/100 0/1 - GPSLongitudeRef: [E] - GPSLongitude: 39/1 35/100 0/1 - GPSAltitudeRef: 0 - GPSAltitude: 6151/470 - GPSTimeStamp: 0/1 48/1 3921/100 {1ST IFD} -- 埋め込みサムネイルの情報 〜 サムネイル画像データへ続く - Compression: 6 - XResolution: 72/1 - YResolution: 72/1 - ResolutionUnit: 2 - JPEGInterchangeFormat: 840 - JPEGInterchangeFormatLength: 8648 0th IFD : Model = [iPod touch] Exif IFD : DateTimeOriginal = [2013:09:01 09:49:00] GPS IFD : GPSLatitude = 69/1 17/100 0/1 removeExifSegmentFromJPEGFile: result=1 $ ./exif _noexif.jpg [_noexif.jpg] does not seem to contain the Exif segment.
(tanabe)
親指サイズの USB 赤外線リモコンが面白い
昨年末、調べごとをしていた時にちょっと気になる商品が目に留まりました。 株式会社ビット・トレード・ワン 様の「USB 接続 赤外線リモコン KIT」という製品です。
特徴をざっくりまとめてみるとこんな感じです。
PC から制御可能な学習型赤外線リモコンといえば 2006 年の発売以来ロングセラーを続ける PC-OP-RS1 がとても有名ですが、このキットは昨年(2012年)発売された製品とのことで、ソフトウェア要素の多くがオープンであることに魅力を感じました。一方で 公式フォーラムを覗いてみるとエアコンまわりをはじめいろいろ制約もあるようで、それをどう考えるかは価格とのバランスの解釈次第でしょう。そういった話題も含めて好奇心をそそられ、年明け早々に入手しました。画像は「フリスク」と並べてみた様子です。
- [パソコンから家庭用機器をリモコン操作]、[リモコンでパソコンを操作] の2つの機能を持つ
- 赤外線送信用のライブラリやツール・ファームウェアのソースコードが公開されている
- 家電協/ NEC/ SONY の各リモコンコードフォーマットに対応
- 某清涼菓子のケースにぴったり収まるサイズ
- キットは 1,680 円、組立ずみ製品でも 2,480 円と低価格
- PC 側対応 OS はWindows 7, Vista, XP
PC とは A−miniB タイプの USB ケーブルで接続。Windows 上でヒューマンインターフェイスデバイスとして認識され標準の HID ドライバが使用されます。
とりあえず使ってみると・・
さっそく専用の 送信用設定ツール に手元のいくつかの機器のリモコンコードを学習させ本キットから信号を出力し、それを元の機器が認識できるか否かを試してみると下の図の結果となりました。 続きを読む
ソーシャル携帯電波マップを作ろう
先週出張で東京に来ました。いつものように東北新幹線です。
道中2時間半いつも特に何をすると決めている訳ではなく、まあ寝るか、本を読むか、iPhoneを片手にメールやサイトチェックをするか、うーん、大体は寝ているんじゃないでしょうか私。眠いもの。
ただ、今回いつもとは違いめずらしく眠気がなかったので、おもむろにMacBook Airを開いてcodingなんぞやろうかという気になりました。しかしそれがいけなかった。まだ購入してから間もない状態だったので、環境が全く整ってない。それどころか書こうとしていたソースコードパッケージすら入れてないときたもんだ。…いや、まあ、でもこういうときに備えてMobileMeのストレージにスナップショットを置いてあったりしただろ落ち着け俺、とやおらPocketWifiを取り出してダウンロードを始めた。が、落ちて来ない。
そうだった。東京から宇都宮〜那須塩原あたりまでのだだっ広い関東平野goes onならいざ知らず、上り列車乗り込んですぐの盛岡あたりでは移動の途中で圏外になることも多く、なかなか使い物にならないのである。市街地はそこそこにしてすぐに田園と山林風景のど真ん中を行くことになるわけだから、ビジネス用途の強いイーモバイルの電波は届かなくても仕方が無いのだ。こいつはぎゃふんだ。
というわけで、行きの電車内で大いに苦しめられたこの電波状況、キャリアのサービスマップだけでは分からない、「ほんとにほんとのところどうなのよ?」というあたりを調べてみようと思った。言ってみればユーザ実測によるリアルサービスマップ。ソーシャル時代の今ならこれをみんなで寄せ集めて日本全国くまなく調査することだって夢じゃない。そうそう、時代はパソーシャル…、と、そんなことを妄想しながらその後ほどなく私がふて寝に入ったのは言うまでもない。
概要はこうだ。新幹線で移動する間中、ずっとGPSで現在位置を把握する。そして並行してPINGを打ち続け、GPSでの位置・PING送信・応答これら3つのイベントを時間軸に沿って記録する。後でこれを地図上にプロットしてみようというわけだ。
手元にあるのはiPhoneとMacBook Air。iPhoneにはGPSがついているので問題ない。PINGの実装はちょっと悩んだが、Cocoaのサンプルコードにちょうど"SimplePing"というそのものズバリなものがあるのを見つけた。Mac用となってはいるが、iOS用にも移植できるんじゃないかと見立て、これを持って来てみた。
http://developer.apple.com/library/mac/#samplecode/SimplePing/Listings/SimplePing_m.html
SimplePing: SimplePing.m
幸いADC(Apple Developer Connection)に登録しているので、iPhoneにアプリケーションを転送して実機でアプリを動かすことはできる。ここまで調べたところで出張が終わり、さあ帰りの新幹線の便となった。
帰りの新幹線。シートに座ってMacBook Airを開いて作業を開始。列車も東京駅を出発。途中小山駅を過ぎたあたりで空腹が勝りすぎて弁当を食さずにはいられなくなるなどアクシデントに遭いつつも、白石蔵王を通り過ぎ仙台駅にさしかかったあたりまでで一通りのものが出来た。
やった内容は大まかにこう。
- まず、Xcode上でFile > New > New Projectのメニューを選び、iOS Applicationから新規アプリケーションを作成する。"Navigation-based"でも、"Tab bar"でも何でも良い。名前も何でも良い。
- SimplePingから、SimplePing.{h,m}ファイルを持ってくる。また、SimplePingがPING応答の際にコールバックするdelegateクラスがmain.m中にあるので、それを持ってくる。
- 上記のdelegateクラスを今回新規作成したアプリケーションにおけるNSApplicationのdelegateクラスに対するカテゴリ(Mix-in)として実装に追加する。
- アプリケーション起動時に呼び出されるコールバックメソッド"application:didFinishLaunchingWithOptions:"において、GPSおよびPING送信を開始するためのコードを追加。
- さらに、GPS出力およびPING送受信の結果を記録するデバッグログを追加。
- ↑の情報は、作業工程圧縮のためiPhone上でのデータ書き込み機能を実装せず、とりあえずXcodeデバッガの出力に任せる。iPhoneはMacにUSB接続したまま動かす。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. // Add the navigation controller's view to the window and display. self.window.rootViewController = self.navigationController; [self.window makeKeyAndVisible]; // ↑ここまでテンプレート // ここからGPS準備 _locationManager = [[CLLocationManager alloc] init]; _locationManager.delegate = self; [_locationManager startUpdatingLocation]; // ここからPING準備 self.pinger = [SimplePing simplePingWithHostName:@"www.klab.jp"]; self.pinger.delegate = self; [self.pinger start]; return YES; }
ざっとこのくらい。これで一応デバッグログにPING送受信とGPSの結果がタイムスタンプとともに吐き出されるので、最低限のデータが取れる。本来ならMapKitと組み合わせてリアルタイムに地図表示まで持っていきたかったところだが、敢えなく時間切れ。
さて仙台を抜け、多くの客が降りだいぶ客席にも余裕ができた頃、最初の試行を開始。しかしそのときちょうどトンネルに入ったらしく、あっけなく問題が発生。上記コード例から分かるように"www.klab.jp"へのPING送信のため名前解決をしているのだが、起動時にしくじるとリトライをしない実装になっているため、トンネルを抜けるまで始められないというバグにぶちあたった。
そうなのだ。仙台から北はまさに行きで悩まされた難受信地域。一足遅かったか…と一瞬天を仰ぐも、気をとりなおしてトンネルを抜けてアンテナが立つと共にリトライ。その後も途中何度も圏外になり、細かいデバッグや調整を繰り返しながら、何とかデータを取ることができた。
データを時間軸で残すようにしたのは大正解だった。作業時間の圧縮のため、デバッグログNSLog()関数での出力にせざるを得なかったが、デフォルトでタイムスタンプ込みの出力をしてくれるため大変助かった。
何しろ、PINGの送信時点と応答受信時点のタイムスタンプを計算すればRound Trip Timeが計れるが、そのくらいアプリケーション内で計算できれば本当はよいものの、デバッグログに逃がすことでその計算も後回しにすることができたのだから。お尻の時間が決まっている場合は、「イカにして必要な作業に集中して手間と時間を投入するか」が重要になってくるということじゃなイカ?
さて、この次にデータをいよいよ地図上に表示する作業に移るわけだが、ここまできてはたと気がついた。Macでネットワークがつながらず往生したのはPocketWifiでだったが、今回iPhoneはそのまま3G回線、すなわちソフトバンク経由でPING送っていたということに…。
まあ、そんなこともありますよね。えへ。
(こうら ひろのぶ)