001 /*
002 * Copyright (c) 2009 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016 package org.opengion.fukurou.security;
017
018 import javax.crypto.spec.SecretKeySpec;
019 import javax.crypto.Cipher;
020
021 import java.security.MessageDigest;
022 import java.security.NoSuchAlgorithmException;
023 import java.security.GeneralSecurityException; // 5.7.2.1 (2014/01/17)
024
025 import java.nio.charset.Charset; // 5.5.2.6 (2012/05/25)
026 import java.nio.channels.FileChannel; // 5.7.2.1 (2014/01/17)
027 import java.nio.ByteBuffer; // 5.5.2.6 (2012/05/25)
028 import java.nio.channels.FileChannel.MapMode; // 5.5.2.6 (2012/05/25)
029
030 import java.io.File;
031 import java.io.FileInputStream;
032 import java.io.IOException;
033
034 import org.opengion.fukurou.util.Closer; // 5.5.2.6 (2012/05/25)
035
036 /**
037 * HybsCryptography は、セキュリãƒ?‚£強化ã?為の Hybs独自の暗号化クラスですã?
038 *
039 * こã?クラスは、暗号化キーを受け取りã?それに基づã�?�¦暗号åŒ?復号化を行いますã?
040 * ここでの暗号化ã?、秘å¯?‚ー方式でバイト文字å?に変換されたものをã??‘6é?アスキーæ–?—に
041 * 直して、扱ってã�?�¾すã?よって、暗号åŒ?復号化å?に、文字å?として扱ã�?�“とが可能ですã?
042 *
043 * @og.rev 4.0.0.0 (2005/08/31) 新規追åŠ?
044 * @og.group ライセンス管ç�?
045 *
046 * @version 4.0
047 * @author Kazuhiko Hasegawa
048 * @since JDK5.0,
049 */
050 public final class HybsCryptography {
051 private final SecretKeySpec sksSpec ;
052 private static final String CIPHER_TYPE = "Blowfish" ;
053
054 /**
055 * プラãƒ?ƒˆフォーãƒ?¾�存ã?ãƒ?ƒ•ォルトã? Charset ですã?
056 * プラãƒ?ƒˆフォーãƒ?¾�存æ?をè?慮する場合ã?エンコード指定で作æ?しておく事をお勧めしますã?
057 *
058 * @og.rev 5.5.2.6 (2012/05/25) findbugs対å¿?
059 */
060 private static final Charset DEFAULT_CHARSET = Charset.defaultCharset() ;
061
062 // 注意:秘å¯?‚ーはã€?¼˜ã?倍数でなã�?�¨ã�?�‘なã�??
063 private static final String HYBS_CRYPT_KEY = "2a5a88891d37ae59" ;
064
065 /**
066 * å†?ƒ¨設定ã?秘å¯?�µを使用して?Œ暗号化を行うオブジェクトを構築しますã?
067 * ここでの暗号化ã?、Java標準ã?セキュリãƒ?‚£パッケージを使用してã�?�¾すã?
068 */
069 public HybsCryptography() {
070 // sksSpec = new SecretKeySpec( HYBS_CRYPT_KEY.getBytes(), CIPHER_TYPE );
071 sksSpec = new SecretKeySpec( HYBS_CRYPT_KEY.getBytes( DEFAULT_CHARSET ), CIPHER_TYPE ); // 5.5.2.6 (2012/05/25) findbugs対å¿?
072 }
073
074 /**
075 * 秘å¯?�µのæ–?—å?を受け取って?Œ暗号化を行うオブジェクトを構築しますã?
076 * ここでの暗号化ã?、Java標準ã?セキュリãƒ?‚£パッケージを使用してã�?�¾すã?
077 * 秘å¯?�µのサイズをã?8 の倍数 (32 以ä¸?448 以ä¸? にするå¿?¦�がありますã?
078 *
079 * @param cryptKey 暗号化を行う秘å¯?�µ
080 */
081 public HybsCryptography( final String cryptKey ) {
082 // sksSpec = new SecretKeySpec( cryptKey.getBytes(), CIPHER_TYPE );
083 sksSpec = new SecretKeySpec( cryptKey.getBytes( DEFAULT_CHARSET ), CIPHER_TYPE ); // 5.5.2.6 (2012/05/25) findbugs対å¿?
084 }
085
086 /**
087 * セキュリãƒ?‚£カラãƒ??DBTyepに対してHybs独自の暗号化を行いますã?
088 * 暗号化されたãƒ??タはã€??常 byte æ–?—ですがã€?¼‘6é?数アスキーæ–?—å?に変換
089 * したもã?を返しますã?
090 * こã?暗号化では、引数ã�?null の場合ã?、ゼロæ–?—å?を返しますã?
091 *
092 * @og.rev 5.7.2.1 (2014/01/17) Exceptionをまとめますã?
093 *
094 * @param org 暗号化を行うå…??æ–?—å?
095 *
096 * @return 暗号化されたæ–?—å?(HEXADECIMALåŒ?
097 */
098 public String encrypt( final String org ) {
099 if( org == null || org.length() == 0 ) { return ""; }
100
101 try {
102 Cipher cipher = Cipher.getInstance( CIPHER_TYPE );
103 cipher.init( Cipher.ENCRYPT_MODE, sksSpec );
104 // byte[] encrypted = cipher.doFinal( org.getBytes() );
105 byte[] encrypted = cipher.doFinal( org.getBytes( DEFAULT_CHARSET ) ); // 5.5.2.6 (2012/05/25) findbugs対å¿?
106
107 return byte2hexa( encrypted );
108 }
109 // 5.7.2.1 (2014/01/17) Exceptionをまとめますã?
110 catch( GeneralSecurityException ex ) {
111 String errMsg = "暗号化å?ç�?�«失敗しましたã€?" + org + "]"
112 + ex.getMessage() ;
113 throw new RuntimeException( errMsg,ex );
114 }
115 // catch( javax.crypto.IllegalBlockSizeException ex ) { throw new RuntimeException( ex ); }
116 // catch( java.security.InvalidKeyException ex ) { throw new RuntimeException( ex ); }
117 // catch( java.security.NoSuchAlgorithmException ex ) { throw new RuntimeException( ex ); }
118 // catch( javax.crypto.BadPaddingException ex ) { throw new RuntimeException( ex ); }
119 // catch( javax.crypto.NoSuchPaddingException ex ) { throw new RuntimeException( ex ); }
120 }
121
122 /**
123 * セキュリãƒ?‚£カラãƒ??DBTyepに対してHybs独自の復号化を行いますã?
124 * ここでの復号化ã?、encrypt で暗号化されたæ–?—を戻すå?合に使用しますã?
125 * こã?復号化では、null は復号化できなã�?�Ÿめã?ゼロæ–?—å?を返しますã?
126 *
127 * @og.rev 5.7.2.1 (2014/01/17) Exceptionをまとめますã?
128 *
129 * @param hex 復号化を行う暗号化された?‘6é?数アスキーæ–?—å?
130 *
131 * @return 復号化されたå…??æ–?—å?
132 */
133 public String decrypt( final String hex ) {
134 if( hex == null || hex.length() == 0 ) { return ""; }
135
136 try {
137 Cipher cipher = Cipher.getInstance( CIPHER_TYPE );
138 cipher.init( Cipher.DECRYPT_MODE, sksSpec );
139 byte[] encrypted = hexa2byte( hex );
140 byte[] decrypted = cipher.doFinal( encrypted );
141 // return new String( decrypted );
142 return new String( decrypted,DEFAULT_CHARSET ); // 5.5.2.6 (2012/05/25) findbugs対å¿?
143 }
144 // 5.7.2.1 (2014/01/17) Exceptionをまとめますã?
145 catch( GeneralSecurityException ex ) {
146 String errMsg = "復号化å?ç�?�«失敗しましたã€?" + hex + "]"
147 + ex.getMessage() ;
148 throw new RuntimeException( errMsg,ex );
149 }
150 // catch( javax.crypto.IllegalBlockSizeException ex ) { throw new RuntimeException( ex ); }
151 // catch( java.security.InvalidKeyException ex ) { throw new RuntimeException( ex ); }
152 // catch( java.security.NoSuchAlgorithmException ex ) { throw new RuntimeException( ex ); }
153 // catch( javax.crypto.BadPaddingException ex ) { throw new RuntimeException( ex ); }
154 // catch( javax.crypto.NoSuchPaddingException ex ) { throw new RuntimeException( ex ); }
155 }
156 /**
157 * 数字から16é?æ–?—に変換するãƒ??ブルですã?
158 */
159 private static final char[] hexadecimal =
160 { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
161 'a', 'b', 'c', 'd', 'e', 'f' };
162
163 /**
164 * バイトé?列を?‘6é?数アスキーæ–?—å?に変換しますã?
165 *
166 * バイトé?列をã€?¼’文字ã?0??,a?žï½??アスキーに変換されますã?
167 * これにより、すべてのæ–?—を、アスキー化できますã?
168 * アスキー化で、上位が0F以下ã?場合でもã?0 をå?すことで、固定長に変換しますã?
169 *
170 * よって、å?力バイトã??’å?のlength()を持ったStringを作æ?しますã?
171 *
172 * @param input バイトé?åˆ?
173 *
174 * @return ?‘6é?数アスキーæ–?—å?
175 */
176 public static String byte2hexa( final byte[] input ) {
177 String rtn = null;
178 if( input != null ) {
179 int len = input.length ;
180 char[] ch = new char[len*2];
181 for( int i=0; i<len; i++ ) {
182 int high = ((input[i] & 0xf0) >> 4);
183 int low = (input[i] & 0x0f);
184 ch[i*2] = hexadecimal[high];
185 ch[i*2+1] = hexadecimal[low];
186 }
187 rtn = new String(ch);
188 }
189 return rtn;
190 }
191
192 /**
193 * ?‘6é?数アスキーæ–?—å?をバイトé?列に変換しますã?
194 *
195 * ?’文字ã?0??,a?žï½??アスキーæ–?—å?をã?バイトé?列に変換されますã?
196 *
197 * よって、å?力Stringの???’å?のlengthを持ったバイトé?列を作æ?しますã?
198 *
199 * @param input ?‘6é?数アスキーæ–?—å?
200 *
201 * @return バイトé?åˆ?
202 */
203 public static byte[] hexa2byte( final String input ) {
204 byte[] rtn = null;
205 if( input != null ) {
206 int len = input.length() ;
207 rtn = new byte[len/2];
208 for( int i=0; i<len/2; i++ ) {
209 char ch = input.charAt( i*2 );
210 int high = ( ch < 'a' ) ? ch-'0' : ch-'a'+10 ;
211 ch = input.charAt( i*2+1 );
212 int low = ( ch < 'a' ) ? ch-'0' : ch-'a'+10 ;
213 rtn[i] = (byte)(high << 4 | low);
214 }
215 }
216 return rtn;
217 }
218
219 /**
220 * MessageDigestにより、MD5 でハッシュしたæ–?—に変換しますã?
221 *
222 * MD5でã€?¼‘6Byteのバイトに変換されますが、ここではã€?¼‘6é?数でæ–?—å?に変換してã�?�¾すã?
223 *
224 * 変換方法ã?、各バイトã?上ä½?下位を?‘6é?æ–?—å?に変換後ã?連結してã�?�¾すã?
225 * これは、Tomcat等ã? digest 認証(MD5使用æ™?と同じ変換方式ですã?
226 * 連結後ã?æ–?—å?長はã€?¼“2バイãƒ?固å®?になりますã?
227 *
228 * @og.rev 5.2.2.0 (2010/11/01) util.StringUtil から移å‹?
229 *
230 * @param input 変換前ã?æ–?—å?
231 *
232 * @return MD5でハッシュしたæ–?—å?。32バイãƒ?固å®?
233 */
234 public static String getMD5( final String input ) {
235 String rtn = null;
236 if( input != null ) {
237 try {
238 MessageDigest md5 = MessageDigest.getInstance( "MD5" );
239 // md5.update( input.getBytes() );
240 md5.update( input.getBytes( DEFAULT_CHARSET ) ); // 5.5.2.6 (2012/05/25) findbugs対å¿?
241 byte[] out = md5.digest();
242 rtn = byte2hexa( out );
243 }
244 catch( NoSuchAlgorithmException ex ) {
245 String errMsg = "MessageDigestで失敗しましたã€?" + input + "]"
246 + ex.getMessage() ;
247 throw new RuntimeException( errMsg,ex );
248 }
249 }
250 return rtn;
251 }
252
253 /**
254 * MessageDigestにより、MD5 でハッシュしたæ–?—に変換しますã?
255 *
256 * MD5でã€?¼‘6Byteのバイトに変換されますが、ここではã€?¼‘6é?数でæ–?—å?に変換してã�?�¾すã?
257 *
258 * 変換方法ã?、各バイトã?上ä½?下位を?‘6é?æ–?—å?に変換後ã?連結してã�?�¾すã?
259 * これは、Tomcat等ã? digest 認証(MD5使用æ™?と同じ変換方式ですã?
260 * 連結後ã?æ–?—å?長はã€?¼“2バイãƒ?固å®?になりますã?
261 *
262 * @og.rev 5.7.2.1 (2014/01/17) Exceptionをまとめますã?
263 *
264 * @param input 変換前ã?File
265 *
266 * @return MD5でハッシュしたæ–?—å?。32バイãƒ?固å®?
267 */
268 public static String getMD5( final File input ) {
269 String rtn = null;
270 if( input != null ) {
271 FileInputStream fis = null;
272 FileChannel fc = null;
273 try {
274 MessageDigest md5 = MessageDigest.getInstance( "MD5" );
275 fis = new FileInputStream( input );
276 fc =fis.getChannel();
277 ByteBuffer bb = fc.map( FileChannel.MapMode.READ_ONLY , 0L , fc.size() );
278 md5.update( bb );
279 byte[] out = md5.digest();
280 rtn = byte2hexa( out );
281 }
282 catch( NoSuchAlgorithmException ex ) {
283 String errMsg = "MessageDigestで MD5 インスタンスの作æ?に失敗しましたã€?" + input + "]"
284 + ex.getMessage() ;
285 throw new RuntimeException( errMsg,ex );
286 }
287 catch( IOException ex ) {
288 String errMsg = "ファイルの読み取りを失敗しましたã€?" + input + "]"
289 + ex.getMessage() ;
290 throw new RuntimeException( errMsg,ex );
291 }
292 finally {
293 Closer.ioClose( fc );
294 Closer.ioClose( fis );
295 }
296 }
297 return rtn;
298 }
299
300 /**
301 * 暗号化ã?ãƒ?‚¹トを行う為のメインメソãƒ?ƒ‰
302 *
303 * java HybsCryptography KEY TEXT で起動しますã?
304 * KEY : 秘å¯?�µ(8 の倍数 (32 以ä¸?448 以ä¸?æ–??
305 * TEXT : 変換するæ–?—å?
306 *
307 * @og.rev 5.2.2.0 (2010/11/01) 循環参ç?の解æ¶?LogWriter 削除)
308 *
309 * @param args 引数配å?
310 * @throws Exception なんらかã?エラーが発生したå?合ã?
311 */
312 public static void main( final String[] args ) throws Exception {
313 if( args.length != 2 ) {
314 // LogWriter.log( "java HybsCryptography KEY TEXT" );
315 // LogWriter.log( " KEY : 秘å¯?�µ(8 の倍数 (32 以ä¸?448 以ä¸?æ–??" );
316 // LogWriter.log( " TEXT : 変換するæ–?—å?" );
317 System.out.println( "java HybsCryptography KEY TEXT" );
318 System.out.println( " KEY : 秘å¯?�µ(8 の倍数 (32 以ä¸?448 以ä¸?æ–??" );
319 System.out.println( " TEXT : 変換するæ–?—å?" );
320 return;
321 }
322
323 HybsCryptography cript = new HybsCryptography( args[0] );
324
325 System.out.println( "IN TEXT : " + args[1] );
326
327 String hexa = cript.encrypt( args[1] );
328 System.out.println( "HEXA TEXT : " + hexa );
329
330 String data = cript.decrypt( hexa );
331 System.out.println( "OUT DATA : " + data );
332 }
333 }