Translate

2013年3月9日土曜日

Google Web Toolkitクライアント側でHmacSHA1変換する

CloudStack APIを呼び出すURLを生成する
Webアプリツールを作っていた。
GWTクライアントから非同期呼び出しして
サーバ上でJavaで処理させれば問題ないなとおもい
さくっとつくったのだけど、
どこの誰とも分からない人間に
自分のAPIキーや秘密キーを送ることはできない
人もいるだろうなあと思い
完全クライアント処理できるように
実装しようと修正しだしたのだけど..

Base64、URLエンコードなどは
クライアントのJava実装→JavaScript変換
で実装できた。
しかし..

HmacSHA1変換がどうしてもGWTのクライアント側で出来ない..

具体的にかくと、
通常のJavaSEが使える環境で
変数messageを秘密キー変数secretPassphraseで
HmacSHA1変換する場合は、

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
...

SecretKeySpec secretKeySpec =
 new SecretKeySpec(secretPassphrase.getBytes(), "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(secretKeySpec);
byte[] hash = mac.doFinal(message.getBytes());

といった実装していた部分を
clientパッケージ以下では動作しない。

結局以下のオープンソースJavaScript関数を
HTMLでロードさせてJSNI(JavaScript Native Interface)で
呼び出す方法を使った。

CryptJS
http://code.google.com/p/crypto-js/


通常のJavaScriptでの使い方は

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-md5.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha1.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha256.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha512.js"></script>
<script>
 var hash = CryptoJS.HmacMD5("Message", "Secret Passphrase");
 var hash = CryptoJS.HmacSHA1("Message", "Secret Passphrase");
 var hash = CryptoJS.HmacSHA256("Message", "Secret Passphrase");
 var hash = CryptoJS.HmacSHA512("Message", "Secret Passphrase");
</script>

である。
なのでGWTを使用するHTMLファイル上に
上記のscriptタグ部分を定義しておく。


変数hashはバイト配列である。

JSNIでは呼び出す側の戻り値が特殊な場合は
JavaScriptObjectに受けないといけない。

なので

GWTクライアント側では

  • private static native JavaScriptObject _hmac_sha1(String org, String secretKey) /*-{
  •  return $wnd.CryptoJS.HmacSHA1(org, secretKey);
  • }-*/;

と受けるしかない。
これをbyte[]に戻すためにイロイロ試したが
一旦Stringで受けて出てきた文字列を
先頭から2文字づつ切り出し
符号つき16進数をそれぞれバイト化して配列にすると
サーバ側で処理した文字列と同じ結果になった。

private static byte[] HmacSHA1(
  String message, String secretPassphrase){
 String org =
  UrlLocalGenerator._hmac_sha1(
   message, secretPassphrase).toString();
 int length = org.length()/2;
 byte[] ret = new byte[length];
 for(int cnt=0;cnt<length;cnt++){
  String tgt = "0x" + org.substring(0, 2);
  org = org.substring(2);
  ret[cnt] = (byte)Integer.decode(tgt).intValue();
 }
 return ret;
}

というなんともかっこわるい実装になってしまった..

0 件のコメント:

o1-previewにナップサック問題を解かせてみた

Azure環境上にあるo1-previewを使って、以下のナップサック問題を解かせてみました。   ナップサック問題とは、ナップサックにものを入れるときどれを何個入れればいいかを計算する問題です。数学では数理最適化手法を使う際の例でよく出てきます。 Azure OpenAI Se...