1 /** 2 * Copyright By Grandsoft Company Limited. 3 * 2014年3月26日 下午4:11:51 4 */ 5 package gboat2.base.bridge.util.security; 6 7 import java.io.File; 8 import java.io.FileInputStream; 9 import java.io.FileNotFoundException; 10 import java.io.IOException; 11 import java.io.InputStream; 12 import java.security.Key; 13 import java.security.KeyPair; 14 import java.security.KeyPairGenerator; 15 import java.security.MessageDigest; 16 import java.security.NoSuchAlgorithmException; 17 18 import javax.crypto.Cipher; 19 import javax.crypto.KeyGenerator; 20 21 import org.apache.commons.io.IOUtils; 22 import org.apache.commons.lang3.StringUtils; 23 24 /** 25 * 对数据进行加密、解密操作的基础工具类 26 * @author <a href="mailto:[email protected]">何明旺</a> 27 * @since 3.0 28 * @date 2014年3月26日 29 */ 30 /** 31 * 32 * @author <a href="mailto:[email protected]">何明旺</a> 33 * @since 3.0 34 * @date 2014年3月27日 35 */ 36 public class Encryptor { 37 38 /** The MD2 message digest algorithm defined in RFC 1319. */ 39 public static final String MD2 = "MD2"; 40 41 /** The MD5 message digest algorithm defined in RFC 1321. */ 42 public static final String MD5 = "MD5"; 43 44 /** Secure Hash Algorithm,安全散列算法 */ 45 public static final String SHA = "SHA"; 46 47 /** The SHA-1 hash algorithm defined in the FIPS PUB 180-2. */ 48 public static final String SHA_1 = "SHA-1"; 49 50 /** The SHA-256 hash algorithm defined in the FIPS PUB 180-2. */ 51 public static final String SHA_256 = "SHA-256"; 52 53 /** The SHA-384 hash algorithm defined in the FIPS PUB 180-2. */ 54 public static final String SHA_384 = "SHA-384"; 55 56 /** The SHA-512 hash algorithm defined in the FIPS PUB 180-2. */ 57 public static final String SHA_512 = "SHA-512"; 58 59 /** 60 * 获取 MessageDigest 实例 61 * @param algorithm 加密算法,请参见本类中的名称为 {@code MD*} 和 {@code SHA*} 的常量 62 * @return 63 */ 64 public static MessageDigest getMessageDigest(String algorithm){ 65 try { 66 return MessageDigest.getInstance(algorithm); 67 } catch (NoSuchAlgorithmException e) { 68 throw new GboatSecurityException("算法 [" + algorithm + "] 不存在,或当前 JDK 不支持该算法。", e); 69 } 70 } 71 72 /** 73 * 74 * @param data 要加密的数据 75 * @param algorithm 加密算法,请参见本类中的名称为 {@code MD*} 和 {@code SHA*} 的常量 76 * @return 密文 77 */ 78 public static byte[] digest(byte[] data, String algorithm){ 79 if(data == null) 80 return null; 81 82 MessageDigest messageDigest = getMessageDigest(algorithm); 83 messageDigest.update(data); 84 return messageDigest.digest(); 85 } 86 87 /** 88 * @param data 要加密的字符串 89 * @param algorithm 加密算法,请参见本类中的名称为 {@code MD*} 和 {@code SHA*} 的常量 90 * @return 密文 91 */ 92 public static byte[] digest(String data, String algorithm){ 93 return (data == null) ? null : digest(data.getBytes(), algorithm); 94 } 95 96 /** 97 * @param file 要加密的文件 98 * @param algorithm 加密算法,请参见本类中的名称为 {@code MD*} 和 {@code SHA*} 的常量 99 * @return 密文 100 */ 101 public static byte[] digest(File file, String algorithm){ 102 if(file == null) 103 return null; 104 105 MessageDigest messageDigest = getMessageDigest(algorithm); 106 InputStream input = null; 107 try { 108 input = new FileInputStream(file); 109 byte[] buffer = new byte[4096]; 110 int length = 0; 111 while ((length = input.read(buffer)) > 0) { 112 messageDigest.update(buffer, 0, length); 113 } 114 } catch (FileNotFoundException e) { 115 throw new GboatSecurityException("文件 [" + file.getAbsolutePath() + "] 不存在。", e); 116 } catch (IOException e) { 117 throw new GboatSecurityException("读取文件 [" + file.getAbsolutePath() + "] 发生错误。", e); 118 } finally { 119 IOUtils.closeQuietly(input); 120 } 121 return messageDigest.digest(); 122 } 123 124 /** 125 * 获取密钥生成器实例 126 * 127 * @param algorithm 加密算法的名称,支持的算法有: 128 * AES、ARCFOUR、Blowfish、DES、DESede、HmacMD5、HmacSHA1、HmacSHA256、HmacSHA384、HmacSHA512、RC2 129 * @return 密钥生成器 130 */ 131 public static KeyGenerator getKeyGenerator(String algorithm) { 132 try { 133 return KeyGenerator.getInstance(algorithm); 134 } catch (NoSuchAlgorithmException e) { 135 throw new GboatSecurityException("获取密钥生成器实例失败:算法 [" + algorithm + "] 不存在,或当前 JDK 不支持该算法。", e); 136 } 137 } 138 139 /** 140 * 根据算法名称和密钥长度生成私钥公钥对 141 * @param algorithm 算法名称,如:RSA、DSA 142 * @param size 密钥长度,如:512、1024 143 * @return 144 */ 145 public static KeyPair getKeyPair(String algorithm, int size) { 146 try { 147 KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm); 148 keyGen.initialize(size); 149 return keyGen.genKeyPair(); 150 } catch (NoSuchAlgorithmException e) { 151 throw new GboatSecurityException("生成私钥公钥对失败:算法 [" + algorithm + "] 不存在,或当前 JDK 不支持该算法。", e); 152 } 153 } 154 155 /** 156 * 取得算法名称 157 * @param transformation 158 * @return 159 */ 160 protected static String getAlgorithmFromTransformation(String transformation) { 161 return StringUtils.substringBefore(transformation, "/"); 162 } 163 164 165 /** 166 * 对数据进行加密 167 * 168 * @param data 要加密的明文数据 169 * @param key 密钥 170 * @param transformation the name of the transformation, format is "Algorithm/Modes/Paddings", e.g., 171 * DES/CBC/PKCS5Padding. See Appendix A in the <a target="_blank" 172 * href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA"> 173 * Java Cryptography Architecture Reference Guide</a> for information about standard transformation names.<br> 174 * <table> 175 * <caption><h3>The following table lists cipher algorithms available in the SunJCE provider</h3></caption> 176 * <thead> 177 * <tr> 178 * <th>Algorithm Name</th> 179 * <th>Modes</th> 180 * <th>Paddings</th> 181 * </tr> 182 * </thead> 183 * <tbody> 184 * <tr> 185 * <td>AES</td> 186 * <td>ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB128, OFB, 187 * OFB8..OFB128</td> 188 * <td>NOPADDING, PKCS5PADDING, ISO10126PADDING</td> 189 * </tr> 190 * <tr> 191 * <td>AESWrap</td> 192 * <td>ECB</td> 193 * <td>NOPADDING</td> 194 * </tr> 195 * <tr> 196 * <td>ARCFOUR</td> 197 * <td>ECB</td> 198 * <td>NOPADDING</td> 199 * </tr> 200 * <tr> 201 * <td>Blowfish, DES, DESede, RC2</td> 202 * <td>ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, 203 * OFB8..OFB64</td> 204 * <td>NOPADDING, PKCS5PADDING, ISO10126PADDING</td> 205 * </tr> 206 * <tr> 207 * <td>DESedeWrap</td> 208 * <td>CBC</td> 209 * <td>NOPADDING</td> 210 * </tr> 211 * <tr> 212 * <td>PBEWithMD5AndDES, PBEWithMD5AndTripleDES, 213 * PBEWithSHA1AndDESede, PBEWithSHA1AndRC2_40</td> 214 * <td>CBC</td> 215 * <td>PKCS5Padding</td> 216 * </tr> 217 * <tr> 218 * <td>RSA</td> 219 * <td>ECB</td> 220 * <td>NOPADDING, PKCS1PADDING, OAEPWITHMD5ANDMGF1PADDING, 221 * OAEPWITHSHA1ANDMGF1PADDING, OAEPWITHSHA-1ANDMGF1PADDING, 222 * OAEPWITHSHA-256ANDMGF1PADDING, OAEPWITHSHA-384ANDMGF1PADDING, 223 * OAEPWITHSHA-512ANDMGF1PADDING <!-- OAEPPadding later --></td> 224 * </tr> 225 * </tbody> 226 * </table> 227 * @return 密文 228 */ 229 public static byte[] encrypt(byte[] data, Key key, String transformation) { 230 try { 231 Cipher cipher = Cipher.getInstance(transformation); 232 cipher.init(Cipher.ENCRYPT_MODE, key); 233 return cipher.doFinal(data); 234 } catch (Exception e) { 235 throw new IllegalArgumentException("对数据进行 [" + transformation + "] 加密失败。", e); 236 } 237 } 238 239 /** 240 * 对数据进行解密 241 * 242 * @param data 要解密的明文数据 243 * @param key 密钥 244 * @param transformation the name of the transformation, format is "Algorithm/Modes/Paddings", e.g., 245 * DES/CBC/PKCS5Padding. See Appendix A in the <a target="_blank" 246 * href="http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html#AppA"> 247 * Java Cryptography Architecture Reference Guide</a> for information about standard transformation names.<br> 248 * <table> 249 * <caption><h3>The following table lists cipher algorithms available in the SunJCE provider</h3></caption> 250 * <thead> 251 * <tr> 252 * <th>Algorithm Name</th> 253 * <th>Modes</th> 254 * <th>Paddings</th> 255 * </tr> 256 * </thead> 257 * <tbody> 258 * <tr> 259 * <td>AES</td> 260 * <td>ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB128, OFB, 261 * OFB8..OFB128</td> 262 * <td>NOPADDING, PKCS5PADDING, ISO10126PADDING</td> 263 * </tr> 264 * <tr> 265 * <td>AESWrap</td> 266 * <td>ECB</td> 267 * <td>NOPADDING</td> 268 * </tr> 269 * <tr> 270 * <td>ARCFOUR</td> 271 * <td>ECB</td> 272 * <td>NOPADDING</td> 273 * </tr> 274 * <tr> 275 * <td>Blowfish, DES, DESede, RC2</td> 276 * <td>ECB, CBC, PCBC, CTR, CTS, CFB, CFB8..CFB64, OFB, 277 * OFB8..OFB64</td> 278 * <td>NOPADDING, PKCS5PADDING, ISO10126PADDING</td> 279 * </tr> 280 * <tr> 281 * <td>DESedeWrap</td> 282 * <td>CBC</td> 283 * <td>NOPADDING</td> 284 * </tr> 285 * <tr> 286 * <td>PBEWithMD5AndDES, PBEWithMD5AndTripleDES, 287 * PBEWithSHA1AndDESede, PBEWithSHA1AndRC2_40</td> 288 * <td>CBC</td> 289 * <td>PKCS5Padding</td> 290 * </tr> 291 * <tr> 292 * <td>RSA</td> 293 * <td>ECB</td> 294 * <td>NOPADDING, PKCS1PADDING, OAEPWITHMD5ANDMGF1PADDING, 295 * OAEPWITHSHA1ANDMGF1PADDING, OAEPWITHSHA-1ANDMGF1PADDING, 296 * OAEPWITHSHA-256ANDMGF1PADDING, OAEPWITHSHA-384ANDMGF1PADDING, 297 * OAEPWITHSHA-512ANDMGF1PADDING <!-- OAEPPadding later --></td> 298 * </tr> 299 * </tbody> 300 * </table> 301 * 302 * @return 密文 303 */ 304 public static byte[] decrypt(byte[] data, Key key, String transformation) { 305 try { 306 Cipher cipher = Cipher.getInstance(transformation); 307 cipher.init(Cipher.DECRYPT_MODE, key); 308 return cipher.doFinal(data); 309 } catch (Exception e) { 310 throw new IllegalArgumentException("对数据进行 [" + transformation + "] 解密失败。", e); 311 } 312 } 313 314 }