気まぐれメモランダム / でたらめフィードバック

最近のエントリ

ブラウザライブコーディングアプリ"live tone(PoC)"v0.3.0リリース

公開:

Tone.jsを利用したブラウザライブコーディングアプリ"live tone(PoC)"のv0.3.0をリリースしました。

https://github.com/DBC-Works/live-tone/releases/tag/v0.3.0

今回の目玉はコード共有機能の実装。アクセスURLを発行できるWebSocketサーバーを使えるなら(私はフリープランのあるAzure Web PubSubを使いました)、URLを発行して"WebSocket server URL"にペースト、識別用のタグも指定してからの"Connect"ボタン押下でWebSocketサーバーに接続します。接続中は"Share"ボタンを押下するたびに自分のコードを同じく接続している他のユーザーに送信、他のユーザーの送信したコードも随時受信します。コードを受信するとそのユーザーの指定したタグ名のタブが増え、そのタブの選択で受信コードを閲覧できます(読み取り専用です)。"Run"ボタンを押下すればすべてのコードを同時に実行=再生します。

技術的にむずかしいことはまったくしていませんが、実際にできるようにしてみるとちょっとぐっとくるところがありました。

コードを即座に共有、一度に実行して音を鳴らす環境は私の知る限りではなく(探せばどこかにあるに違いありませんが)、この方向性を推し進めていくと新しい可能性が開けそうな予感はたしかにあります。しかしそのためには考えなければならないことが山のようにあることもまた実装していて痛感したところでした。あまり便利でないかたちでリリースしたのはそのあたりを考え始めるときりがなさそうで、あくまでProof of Concept、概念実証に留めようと思ったからでもあります。

最大の課題がTone.jsのAPIにあることはまちがいなく、普通の開発向けで冗長かつ自由度の高いそのAPIをライブコーディング用に無理に使い続けるメリットはありません。

うっかりしていて試してみるまで気づかなかったのですが、同じくらい大きな課題としてはセキュアな実行の確保があります。他人のコードが実行できるということはつまり悪意のあるコードも実行できてしまうわけで、広く使ってもらうためにはその対策は必須。v0.3.0ではコードのバリデーション処理を実装して使えない機能をブラックリスト方式でチェックしていますが、このチェックが十分であるという保証はブラウザ上で動作させるコードではおそらく永遠に得られないでしょう。

上記二点から、実用に耐えるアプリケーションとするためには専用のドメイン特化言語(DSL)が必要という結論が導かれます。しかしこの専用DSLの定義、そしてそのDSLの実行環境の整備にかかる手間がいかほどのものか、いまの私には見当もつきません。

というわけでlive toneの開発はここでふたたび塩漬けにしようかと思っています。ただちょっと別のアイディアが形になりそうな予感もあるので、今回得た知見はそのときに役立てればと考えているところです。作りかけのアプリ増やしてどうするの?という話はありますが……

他にもWebSocketの使いかたも身に着けたし抽象構文木(AST)の理解も深まったし、得るものの多い開発でした。


エントリを表示

多くの矛盾の狭間で - KORG Gadget+GUMI新曲"アンビバレンス・ステップス"

公開:

――誰もが右往左往しながら生きている。

アンビバレンス・ステップス(feat. GUMI, VOCALOID6 AI Megpoid)

KORG Gadget+GUMIの新曲、"アンビバレンス・ステップス"を公開しました。お聴きいただければ幸いです。

すべての権力者はただちに民衆への暴力行使を停止せよ。


エントリを表示

JavaでECDH-ES指定JWEの暗号化と復号を行う方法

公開: / 最終更新日:

暗号化データのフォーマットをJSONベースで規定したJSON Web Encryption(JWE)JSON Web Token(JWT)の一部として取りあつかわれることが多く明示的に処理する機会は少ないと思われますが、仕様としてはJWTとは独立なので単独での使用も可能です。

最近業務でアルゴリズムにECDH-ESを指定したJWE暗号化データの復号処理をJavaで実装することになったのですが、まとまった参考になる情報がなかなか見あたらず難儀しました。同じように苦労される方がいそうなので、暗号化も含めメモとして残しておきます。

ECDH-ESとは?

ECDH-ESはElliptic Curve Diffie-Hellman Ephemeral Staticの略で楕円曲線Diffie-Hellman鍵共有の一種、ECDHE(一時的楕円曲線Diffie-Hellman鍵共有)にカテゴライズされるものです。ハイフン以降のESが鍵の管理方法を示していて、Ephemeralは暗号化側の鍵が一時的であること、Staticは復号側の鍵の管理が永続的であることを示します。

楕円曲線Diffie-Hellman鍵共有は楕円曲線暗号を応用した鍵共有の方法です。

  1. 暗号化側は公開鍵を都度生成、生成した公開鍵と復号側の公開鍵で暗号化
  2. 復号側には暗号化データと生成公開鍵をセットで送信
  3. 復号側は暗号化側から送信されてきた公開鍵と自身で管理する鍵の秘密鍵で復号

Javaで利用できるライブラリ

暗号にかかわる処理は実績と信頼が何よりも大事なので、自作は最後の手段と心得て、利用できるライブラリがあれば利用するのがベストプラクティスです。

JavaでJWTを取り扱うライブラリとしてはNimbus JOSE + JWTがもっとも普及しているようで、サンプルコードも比較的潤沢に確認できます。いまでもJava 7をコードベースとしているので古いシステムでも導入しやすいのではないかと思います。以降のコードではNimbus JOSE + JWTを用いています。

他にもいくつか確認しましたが、その中でもRESTEasyはECDH-ESにはそのままでは対応していないようで簡単に試してみた限りでは素直には使えませんでした。

暗号化処理

暗号化に必要な復号側の(秘密鍵を含まない)公開鍵はなんらかの方法で事前に暗号化側に渡しておきます。JSON Web Key(JWK)で渡した場合は JWK#parse() メソッドで JWK 派生クラスのインスタンスを生成できます。

final var receiverKey = (ECKey) JWK.parse("(復号側公開鍵(秘密鍵は含まない)のJWK文字列)");

暗号化側の鍵は都度生成します。

final var senderKey = new ECKeyGenerator(Curve.P_256).generate();

ペイロードはなんでもよいのですが、Nimbus JOSE + JWT には Map<K, V> インターフェース実装クラスのインスタンスを設定すると Map<K, V> インターフェースで参照できるという便利機能があります。

final var payloadMap = new HashMap<String, Object>();
payloadMap.put("key", "value");

暗号化はこれらを組みあわせて行います。

final var header = new JWEHeader.Builder(JWEAlgorithm.ECDH_ES, EncryptionMethod.A256GCM)
  .ephemeralPublicKey(senderKey.toPublicJWK())
  .build();

final var jweObject = new JWEObject(header, new Payload(payloadMap));
jweObject.encrypt(new ECDHEncrypter(receiverKey.toECPublicKey()));
final var jweCompactSerializationString = jweObject.serialize();

ポイントは次の2点。

  • JWEHeader.Builder クラスによる JWEHeader クラスインスタンス生成時に JWEHeader.Builder#ephemeralPublicKey() メソッドで暗号化側の一時利用公開鍵を設定
  • その JWEHeader クラスインスタンスを指定して JWEObject クラスインスタンスを生成、 復号側の公開鍵 を指定して JWEObject#encrypt() メソッドを呼びだし暗号化

復号処理

JWEは暗号側の公開鍵を含むので、秘密鍵を含む復号側鍵を与えれば復号できます。

final var jweObject = JWEObject.parse(jweCompactSerializationString);

// JWE Headerは復号前に参照可能
final var algorithm = jweObject.getHeader().getAlgorithm();

final var receiverKey = (ECKey) JWK.parse("(復号側鍵(秘密鍵を含む)のJWK文字列)");
jweObject.decrypt(new ECDHDecrypter(receiverKey.toECPrivateKey()));

// JWE Payloadは復号後に参照可能
final var payload = jweObject.getPayload().toJSONObject();

終わりに

本稿では割愛した暗号全般に関する説明は別途信頼できる情報源にあたっていただければと思いますが、個人的にはずいぶん昔に本で得た知識では太刀打ちできなくなっていていろいろとまどいました。たとえば次。

  • RSA鍵交換が推奨されなくなっていた(SSL / TLSのバージョンアップを追いかけて知りました)
  • Diffie-Hellman鍵交換と楕円曲線Diffie-Hellman鍵交換は名前が一部重なるのに処理として考えると別物
  • 楕円曲線暗号と楕円曲線Diffie-Hellman鍵交換も、同じ楕円曲線をベースにしているのにコードの水準で見るとけっこう違って見える

楕円曲線暗号関連に関しては、そもそも考えかた自体がむずかしい上に実装と関連づけられた解説が日本語ではなかなか見当たらず、どうすればよいものか最初は途方に暮れました。その意味では本稿は過去の自分に向けて書いたエントリですが、未来のどなたかの参考になりましたら幸いです。


エントリを表示

Azure Web PubSubはWebSocketサーバーとして利用可能、ただすこし注意が必要

公開:

このところMicrosoft Azureの製品の一つであるAzure Web PubSubをいろいろ試していて、普通のWebSocketサーバーとして使えることを確認できたので気づいた点をメモとして残しておきます。2024年9月現在の話です。

公開されているJavaScript用ライブラリはNode.js用

ブラウザとAzure Web PubSubの通信はWebSocket APIで行えるため専用のライブラリは必要ありません。

Azure Web PubSubのJavaScript用クライアントライブラリとしてマイクロソフトはWeb PubSub client library for JavaScriptを公開しています。

このライブラリはNode.js(およびその互換環境)向けで、ブラウザでは動きません。

サブプロトコルは要指定

専用のライブラリは必要ないのですが、Azure Web PubSubの用意する専用サブプロトコルは指定必須と言えます。

WebSocketにはカスタムの通信ルールと規約を定義できるサブプロトコルという機能があります。サブプロトコルはWebSocket()コンストラクタの第2引数で指定できます。

Azure Web PubSubは専用サブプロトコルとして次の二つを用意しています。

  • json.webpubsub.azure.v1 (JSONで通信する場合)
  • protobuf.webpubsub.azure.v1 (Protocol Buffersで通信する場合)

Azure Web PubSubはこの専用サブプロトコルを指定したクライアントを「PubSub WebSocketクライアント」、指定しないクライアントを「シンプルWebSocketクライアント」と規定しています。

この説明からだとシンプルWebSocketクライアントでも普通に使えるように思えるのですが、2024年9月現在シンプルWebSocketクライアントにはエラーが発生したとき情報を十分把握できないという問題があります。

たとえば私には解決できていない現象として次があります。専用サブプロトコルを指定しないシンプルWebSocketクライアントでWebSocket: send() メソッドを呼び出すとただちにWebSocket: close イベントが送信されて切断してしまうのです。引数のCloseEventを見るかぎりCloseEvent: code プロパティの値は 1000 (通常のクローズ)で、この値からは処理は正常に行われたとしか考えられません。Azure Web PubSubはPubSub WebSocketクライアントからのアクセスを前提としていて、シンプル WebSocket クライアントからのアクセスに対しては十分な対応ができていないということのように思えます。

PubSub WebSocketクライアントはシンプルWebSocketクライアントよりも高度な機能が使えます。その高度な機能が必要か、あったほうがよいかはユースケースによると思いますが、製品の性格から言っても、シンプルWebSocketクライアントでなければならないという強い理由がなければPubSub WebSocketクライアントを選択する(=専用サブプロトコルを指定する)のが無難かと思います。

サブプロトコル指定時はグループへの参加が必要

サブプロトコルを指定してAzure Web PubSubに接続したらまずグループに参加させましょう。

Azure Web PubSubはクライアントの接続をグループという単位で管理します。

PubSub WebSocketクライアントはメッセージの送信をグループに対して行うアーキテクチャになっているため、PubSub WebSocketクライアントを利用する際はグループへの参加は必須です。type: "joinGroup" のメッセージを送信するとグループに参加できます。

AzureポータルのクライアントURLジェネレーターはハブの入力に注意

AzureポータルのクライアントURLジェネレーターを利用する際はまず「ハブ」の入力フィールドを確認、基本ラテン以外の文字が設定されていたら英文字で更新するようにしましょう。

Azure Web PubSubアクセスにはURLに認証用アクセストークンが必要で、一般的なユースケースではWeb APIを別途用意して発行することになりますが、Azureポータルは試験用等の一時的な利用に使えるクライアントURLジェネレーターを提供しています。

しかしこのAzureポータルのクライアントURLジェネレーター、多言語対応が十分でなく、言語・地域設定で日本語を選択していると初期状態で「ハブ」の入力フィールドにカタカナで ハブ と設定されます。ハブとして指定可能な文字種は英大文字・小文字に数字、若干の記号(,._\)だけであるにもかかわらず、です。その上初期状態ではエラーも表示されず、クライアントURLも生成できてしまいます(生成したクライアントURLを指定して接続しようとするとエラーになります)。

最後に

とまあいくつか気をつける点はありますが、WebSocketサーバーを自分で管理するより圧倒的にお手軽なのはまちがいありません。WebSocket APIを使ったWebSocketサーバーアクセスは簡単に実装できるので、クライアント間のリアルタイムコミュニケーションでなにかアイディアのある方はAzure Web PubSubを使って実現してみてはいかがでしょうか。


エントリを表示

儚く流れる希望、 - KORG Gadget新曲"hope flowing ephemerally"公開

公開:

――それすらも求めざるを得ない人々へ。

hope flowing ephemerally(Processing study)

KORG Gadgetでの新作、"hope flowing ephemerally"を公開しました。お聴きいただければ幸いです。

すべての権力者はただちに民衆への暴力行使を停止せよ。

2024-09-02(Mon)追記: KORG Gadget作品の作曲コンテスト、GadgetSonic 2024FIRE RED STAGEに選出していただきました。3回目の挑戦で初選出。ありがとうございます。


エントリを表示

Pick up work

最近のエントリ

アーカイブ

ブログ情報