2012/05/13

トラノマキ その6

独自に作ったライセンス認証が通らない原因がやっと分かりました(結局SSL通信自体は上手くいってました)。

社内の人にテストしてもらった結果Android2.3端末だけNGだった為、同エミュレータを使って確認してみると、あるデータを複合化する際にjavax.crypto.BadPaddingException が発生している事がわかりました。この例外の説明を読んでも意味不明なのですが、早い話『こんな鍵つかえねーよ』って所でしょうか?

暗号化/復号化の部分はググって一番初めに出てきた 『Hacking My Way ~ itogのhack日記 』を参考にしています。勿論これはあくまでサンプルですし、何の問題も無いと思います。

ここに掲載されているサンプルには、SecretKeySpec のコンストラクタに与えるバイト配列を生成する為のメソッド「getRawKey」があります。
private static byte[] getRawKey(byte[] seed) throws Exception {
  KeyGenerator keygen = KeyGenerator.getInstance("AES");
  SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
  random.setSeed(seed);//これを消すと毎回ランダムになる
  keygen.init(128, random); 
  SecretKey key = keygen.generateKey();
  byte[] raw = key.getEncoded();
  
  return raw;
 }
これは同じバイト配列を種として使うと、生成されるバイト配列は毎度同じになりますが、Android2.2と2.3では結果が違う為、この動作を期待した実装をすると困る場合もあるよ、というお話でした。

…なんの事かわかりませんね。

トラノマキのライセンス認証では、あらかじめ暗号化したデータをサーバーに持たせておき、これを受け取って復号化するのですが、その『あらかじめ』暗号化する際に上記コードを使って鍵を生成している為、開発環境と同じ2.2では復号化できて、それ以外では失敗してしまう、という事でした。

対策としてライセンス認証の部分だけ乱数を使わない鍵で暗号/復号化するようにしました(ついでに違うアルゴリズムに変更)

以下は復号化部分
public static String decrypt(String seed, String encrypted)
 throws Exception {
  byte[] enc = Base64.decode(encrypted.getBytes(), Base64.DEFAULT);
  
  KeySpec keySpec = new PBEKeySpec(seed.toCharArray(), "Hoge".getBytes(), 1024,256);
  SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHSHAAND256BITAES-CBC-BC");
  SecretKey key = factory.generateSecret(keySpec);
  
  Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
  cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec("Hage".getBytes()));
  
  byte[] result = cipher.doFinal(enc);
   
  return new String(result);
 }

0 件のコメント:

コメントを投稿