CAPICOM で暗号・復化
JavaからVBScriptへのAES暗号化によるデータ渡し (OKWave) から。気になったので試してみた。
Java は javax.crypto.Cipher で、VBS は CAPICOM を利用して、AES 暗号をする。
先に、結論。CAPICOM と他の暗号ライブラリでは、暗号データのやり取りは、簡単には出来ない。
日本語が混じると文字コードが面倒なので ASCII のみで。キーやデータのサイズもパディングとか面倒なので 16 byte (128 bit) 単位で。
VBS(CAPICOM) で暗号
まずは、VBS(CAPICOM) のみで、暗号・復化する。
Const CAPICOM_ENCRYPTION_ALGORITHM_AES = 4 Const CAPICOM_ENCRYPTION_KEY_LENGTH_128_BITS = 3 passwordString = "passwordpassword" contentString = "AES_CBC_128_BITS" encryptString = "MGIGCSsGA〜AvQ==" ' Encrypt Set objCrypt = CreateObject("CAPICOM.EncryptedData") objCrypt.Algorithm.Name = CAPICOM_ENCRYPTION_ALGORITHM_AES objCrypt.Algorithm.KeyLength = CAPICOM_ENCRYPTION_KEY_LENGTH_128_BITS objCrypt.SetSecret passwordString objCrypt.Content = contentString encryptString = objCrypt.Encrypt Set objCrypt = Nothing WScript.Echo " encrypt : " & vbNewLine & encryptString ' Decrypt Set objCrypt = CreateObject("CAPICOM.EncryptedData") objCrypt.Algorithm.Name = CAPICOM_ENCRYPTION_ALGORITHM_AES objCrypt.Algorithm.KeyLength = CAPICOM_ENCRYPTION_KEY_LENGTH_128_BITS objCrypt.SetSecret passwordString objCrypt.Decrypt encryptString contentString = objCrypt.Content Set objCrypt = Nothing WScript.Echo " decrypt : " & vbNewLine & contentString
実行するとこんな感じ。
C:\>cscript Crypt.vbs Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 1996-2001. All rights reserved. encrypt : MIGCBgkrBgEEAYI3WAOgdTBzBgorBgEEAYI3WAMBoGUwYwIDAgABAgJmDgICAIAE EAAAAAAAAAAAAAAAAAAAAAAEENk3JQEmcgvYnbAd/egSfLoEMB0hne2Dg0Tsyn1t gUi8XwRv/4ex8aQZLHjK0zfBhlzQRK54+7tJUMnEPtBFK1KA/A== decrypt : AES_CBC_128_BITS
なぜ「こんな感じ」なのかは、実行する度に encrypt の結果が変わる。
つまり、ECB モードではなく、初期化ベクトル(IV)が必要な CBC, CFB, OFB あたりになる(CTR の可能性もあるけど)。
Java(javax.crypto.Cipher) で暗号
続いて、Java(javax.crypto.Cipher) のみで、CBC モードの暗号・復号する。
import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import sun.misc.BASE64Encoder; public class Crypt { public static void main(String[] args) throws Exception { String passwordString = "passwordpassword"; String contentString = "AES_CBC_128_BITS"; //String encryptString = "MGIGCSsGA〜AvQ=="; byte[] password = passwordString.getBytes("UTF-8"); byte[] content = contentString.getBytes("UTF-8"); byte[] encrypt = null; SecretKey key = new SecretKeySpec(password, "AES"); IvParameterSpec iv = null; // new IvParameterSpec(null); Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); System.out.println("Algorithm : " + cipher.getAlgorithm()); //System.out.println("BlockSize : " + cipher.getBlockSize()); System.out.println(); // Encrypt cipher.init(Cipher.ENCRYPT_MODE, key, iv); encrypt = cipher.doFinal(content); System.out.println(" IV :" + toString(cipher.getIV())); System.out.println(" encrypt :"); System.out.println(toString(encrypt)); System.out.println(); // Decrypt iv = new IvParameterSpec(cipher.getIV()); cipher.init(Cipher.DECRYPT_MODE, key, iv); content = cipher.doFinal(encrypt); System.out.println(" IV :" + toString(cipher.getIV())); System.out.println(" decrypt :"); System.out.println(new String(content, "UTF-8")); System.out.println(); } private static String toString(byte[] data) { if (data == null) return null; return (new BASE64Encoder()).encode(data); } }
実行するとこんな感じ。
Algorithm : AES/CBC/NoPadding IV :LjdcGoe5Va6w5fgXqWbbGg== encrypt : 9H7zkgDCHuKPG0rt0IrzkA== IV :LjdcGoe5Va6w5fgXqWbbGg== decrypt : AES_CBC_128_BITS
VBS - Java 間で暗号
それぞれで暗号・復号が出来るのは確認できたので、言語の垣根を越えてやってみる。
けど、いくつか不明な点がある。
1.暗号データのサイズが違う
VBS と Java とで出力されるデータのサイズが異なる。
2.鍵の値
CAPICOM で鍵として文字列を渡しているが、これがどう扱われているのかが不明。
キー長を 128bit と指定しているので、それに合わせた長さが必要だが、16文字未満でも問題なく動く。ので、パディングされるか、一方向ハッシュ値を求めているのでは?と思う。
3.モード・パディングが不明
CAPICOM で暗号アルゴリズムは指定出来るが、モードやパディングを指定出来ない。また、何を使用しているかもわからない。
実行の都度に結果が変わるので、少なくとも、ECB (Electronic Codebook) ではないと思う。
また、与えるデータが 16文字単位 でなくてもちゃんと動くので、何かしらパディングされているとは思う。