阅读:4937回复:0
加密算法分享篇
在通过接口下载气象资料类型的文件时,我们通常采用两种方式:
1、资料接口提供产品文件名称,然后通过用户名和密码,进行权限验证后,下载产品文件。 2、对产品文件的下载地址进行加密,防止别人通过下载地址直接获取产品的文件信息及用户名和密码等相关信息。 在CIMISS中,我们下载雷达或卫星等数据文件时,采用的就是第二种方案,通过一串加密后的字符串,我们就可直接进行产品文件的下载。 在网上就能找到许多的加密算法,这里,我对常见的一些加密算法进行了一个简单的总结: 一.Base64 严格来说Base64并不是一种加密/解密算法,而是一种编码方式。Base64不生成密钥,通过Base64编码后的密文就可以直接“翻译”为明文,但是可以通过向明文中添加混淆字符来达到加密的效果。 下面是加密的实现类:---------------------------分割线--------------------------- import java.io.IOException; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; public class Base64Demo { private static String src = "TestBase64"; public static void main(String[] args) { Base64Demo.jdkBase64(); Base64Demo.commonsCodecBase64 (); Base64Demo.bouncyCastleBase64 (); } //使用JDK的base64实现, public static void jdkBase64 (){ BASE64Encoder encoder = new BASE64Encoder(); String encode = encoder.encode(Base64Demo.src.getBytes()); System.out.println("encode: " + encode); BASE64Decoder decoder = new BASE64Decoder(); try { String decode = new String ( decoder.decodeBuffer(encode)); System.out.println("decode: " + decode); } catch (IOException e) { e.printStackTrace(); } } //使用apache的commonsCodec实现 public static void commonsCodecBase64 (){ byte[] encodeBytes = org.apache.commons.codec.binary.Base64.encodeBase64(Base64Demo.src.getBytes()); String encode = new String (encodeBytes); System.out.println("encode: " + encode); byte[] decodeBytes = org.apache.commons.codec.binary.Base64.decodeBase64(encode); String decode = new String(decodeBytes); System.out.println("decode: " + decode); } //使用bouncyCastlede实现 public static void bouncyCastleBase64 () { byte[] encodeBytes = org.bouncycastle.util.encoders.Base64.encode(Base64Demo.src.getBytes()) ; String encode = new String (encodeBytes); System.out.println("encode: " + encode); byte[] decodeBytes = org.bouncycastle.util.encoders.Base64.decode(encode); String decode = new String(decodeBytes); System.out.println("decode: " + decode); } } ---------------------------分割线--------------------------- 二.DES DES是一种基于56位密钥的对称算法,1976年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),随后在国际上广泛流传开来。现在DES已经不是一种安全的加密算法,已被公开破解,现在DES已经被高级加密标准(AES)所代替。 下面是加密的实现类:---------------------------分割线--------------------------- import java.security.InvalidKeyException;import java.security.Key; import java.security.NoSuchAlgorithmException;import java.security.NoSuchProviderException; import java.security.Security;import java.security.spec.InvalidKeySpecException; import javax.crypto.BadPaddingException; import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator;import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey;import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.bouncycastle.util.encoders.Hex; public class DESDemo { private static String src = "TestDES"; public static void jdkDES () { try { //生成密钥Key KeyGenerator keyGenerator = KeyGenerator.getInstance("DES"); keyGenerator.init(56); SecretKey secretKey = keyGenerator.generateKey(); byte[] bytesKey = secretKey.getEncoded(); //KEY转换 DESKeySpec deSedeKeySpec = new DESKeySpec(bytesKey); SecretKeyFactory factory = SecretKeyFactory.getInstance("DES"); Key convertSecretKey = factory.generateSecret(deSedeKeySpec); //加密 Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey); byte[] encodeResult = cipher.doFinal(DESDemo.src.getBytes()); System.out.println("DESEncode :" + Hex.toHexString(encodeResult)); //解密 cipher.init(Cipher.DECRYPT_MODE,convertSecretKey); byte[] DecodeResult = cipher.doFinal(encodeResult); System.out.println("DESDncode :" + new String (DecodeResult)); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeyException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (InvalidKeySpecException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (NoSuchPaddingException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (IllegalBlockSizeException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (BadPaddingException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } public static void bcDES (){ try { //使用BouncyCastle 的DES加密 Security.addProvider(new BouncyCastleProvider()); //生成密钥Key KeyGenerator keyGenerator = KeyGenerator.getInstance("DES","BC"); keyGenerator.init(56); SecretKey secretKey = keyGenerator.generateKey(); byte[] bytesKey = secretKey.getEncoded(); //KEY转换 DESKeySpec deSedeKeySpec = new DESKeySpec(bytesKey); SecretKeyFactory factory = SecretKeyFactory.getInstance("DES"); Key convertSecretKey = factory.generateSecret(deSedeKeySpec); //加密 Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey); byte[] encodeResult = cipher.doFinal(DESDemo.src.getBytes()); System.out.println("DESEncode :" + Hex.toHexString(encodeResult)); //解密 cipher.init(Cipher.DECRYPT_MODE,convertSecretKey); byte[] DecodeResult = cipher.doFinal(encodeResult); System.out.println("DESDncode :" + new String (DecodeResult)); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeyException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (InvalidKeySpecException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (NoSuchPaddingException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (IllegalBlockSizeException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (BadPaddingException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (NoSuchProviderException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } public static void main(String[] args) { DESDemo.jdkDES (); DESDemo.bcDES(); } } ---------------------------分割线--------------------------- 三.3DES 3DES是DES的一种派生算法,主要提升了DES的一些实用所需的安全性。 下面是加密的实现类: ---------------------------分割线--------------------------- import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Security; import java.security.spec.InvalidKeySpecException; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESedeKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.encoders.Hex; public class TripleDESDemo { private static String src = "TestTripleDES"; public static void jdkTripleDES () { try { //生成密钥Key KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede"); keyGenerator.init(168); SecretKey secretKey = keyGenerator.generateKey(); byte[] bytesKey = secretKey.getEncoded(); //KEY转换 DESedeKeySpec deSedeKeySpec = new DESedeKeySpec(bytesKey); SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede"); Key convertSecretKey = factory.generateSecret(deSedeKeySpec); //加密 Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey); byte[] encodeResult = cipher.doFinal(TripleDESDemo.src.getBytes()); System.out.println("TripleDESEncode :" + Hex.toHexString(encodeResult)); //解密 cipher.init(Cipher.DECRYPT_MODE,convertSecretKey); byte[] DecodeResult = cipher.doFinal(encodeResult); System.out.println("TripleDESDncode :" + new String (DecodeResult)); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeyException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (InvalidKeySpecException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (NoSuchPaddingException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (IllegalBlockSizeException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (BadPaddingException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } public static void bcTripleDES () { try { Security.addProvider(new BouncyCastleProvider()); //生成密钥Key KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede","BC"); keyGenerator.getProvider(); keyGenerator.init(168); SecretKey secretKey = keyGenerator.generateKey(); byte[] bytesKey = secretKey.getEncoded(); //KEY转换 DESedeKeySpec deSedeKeySpec = new DESedeKeySpec(bytesKey); SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede"); Key convertSecretKey = factory.generateSecret(deSedeKeySpec); //加密 Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey); byte[] encodeResult = cipher.doFinal(TripleDESDemo.src.getBytes()); System.out.println("TripleDESEncode :" + Hex.toHexString(encodeResult)); //解密 cipher.init(Cipher.DECRYPT_MODE,convertSecretKey); byte[] DecodeResult = cipher.doFinal(encodeResult); System.out.println("TripleDESDncode :" + new String (DecodeResult)); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeyException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (InvalidKeySpecException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (NoSuchPaddingException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (IllegalBlockSizeException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (BadPaddingException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (NoSuchProviderException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } public static void main(String[] args) { jdkTripleDES (); bcTripleDES (); } } ---------------------------分割线--------------------------- 四、MD5加密 下面是加密的实现类: ---------------------------分割线--------------------------- public class MD5Util { public static String getMD5(String str) { try { // 生成一个MD5加密计算摘要 MessageDigest md = MessageDigest.getInstance("MD5"); // 计算md5函数 md.update(str.getBytes()); // digest()最后确定返回md5 hash值,返回值为8为字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符 // BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值 String md5=new BigInteger(1, md.digest()).toString(16); //BigInteger会把0省略掉,需补全至32位 return fillMD5(md5); } catch (Exception e) { throw new RuntimeException("MD5加密错误:"+e.getMessage(),e); } } public static String fillMD5(String md5){ return md5.length()==32?md5:fillMD5("0"+md5); } /** * 加密解密算法 执行一次加密,两次解密 */ public static String convertMD5(String inStr){ char[] a = inStr.toCharArray(); for (int i = 0; i < a.length; i++){ a = (char) (a ^ 't'); } String s = new String(a); return s; } } ---------------------------分割线--------------------------- 对于像对url中的参数进行加密的过程,我不建议使用rsa或者是三重des这样的加密算法,主要原因在于性能和速度会受影响。我建议大家使用对称加密算法如:DES或者是PBE算法。这里,我对我们日常系统中最常用也是当前最流行的对称加密算法进行了一个总结。 五、AES对称加密(特别推荐!!!) 下面是加密的实现类: ---------------------------分割线--------------------------- import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; /** * 加密解密类 * * @author zdj * */ public class SymmetricEncoder { /* * 加密 1.构造密钥生成器 2.根据ecnodeRules规则初始化密钥生成器 3.产生密钥 4.创建和初始化密码器 5.内容加密 6.返回字符串 */ public static String AESEncode(String encodeRules, String content) { try { // 1.构造密钥生成器,指定为AES算法,不区分大小写 KeyGenerator keygen = KeyGenerator.getInstance("AES"); // 2.根据ecnodeRules规则初始化密钥生成器 // 生成一个128位的随机源,根据传入的字节数组 keygen.init(128, new SecureRandom(encodeRules.getBytes())); // 3.产生原始对称密钥 SecretKey original_key = keygen.generateKey(); // 4.获得原始对称密钥的字节数组 byte[] raw = original_key.getEncoded(); // 5.根据字节数组生成AES密钥 SecretKey key = new SecretKeySpec(raw, "AES"); // 6.根据指定算法AES自成密码器 Cipher cipher = Cipher.getInstance("AES"); // 7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEY cipher.init(Cipher.ENCRYPT_MODE, key); // 8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码 byte[] byte_encode = content.getBytes("utf-8"); // 9.根据密码器的初始化方式--加密:将数据加密 byte[] byte_AES = cipher.doFinal(byte_encode); // 10.将加密后的数据转换为字符串 // 这里用Base64Encoder中会找不到包 // 解决办法: // 在项目的Build path中先移除JRE System Library,再添加库JRE System // Library,重新编译后就一切正常了。 String AES_encode = new String(new BASE64Encoder().encode(byte_AES)); // 11.将字符串返回 return AES_encode; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } // 如果有错就返加nulll return null; } /* * 解密 解密过程: 1.同加密1-4步 2.将加密后的字符串反纺成byte[]数组 3.将加密内容解密 */ public static String AESDncode(String encodeRules, String content) { try { // 1.构造密钥生成器,指定为AES算法,不区分大小写 KeyGenerator keygen = KeyGenerator.getInstance("AES"); // 2.根据ecnodeRules规则初始化密钥生成器 // 生成一个128位的随机源,根据传入的字节数组 // SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG"); // secureRandom.setSeed(encodeRules.getBytes()); // keygen.init(128, secureRandom); keygen.init(128, new SecureRandom(encodeRules.getBytes())); // 3.产生原始对称密钥 SecretKey original_key = keygen.generateKey(); // 4.获得原始对称密钥的字节数组 byte[] raw = original_key.getEncoded(); // 5.根据字节数组生成AES密钥 SecretKey key = new SecretKeySpec(raw, "AES"); // 6.根据指定算法AES自成密码器 Cipher cipher = Cipher.getInstance("AES"); // 7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的KEY cipher.init(Cipher.DECRYPT_MODE, key); // 8.将加密并编码后的内容解码成字节数组 byte[] byte_content = new BASE64Decoder().decodeBuffer(content); /* * 解密 */ byte[] byte_decode = cipher.doFinal(byte_content); String AES_decode = new String(byte_decode, "utf-8"); return AES_decode; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } // 如果有错就返加nulll return null; } public static void main(String[] args) { SymmetricEncoder se=new SymmetricEncoder(); String url = "9C3CBD8E:o_se_ur_rada_flow_tdr/J.0003.0001.S001:0020190416000004Z9854J.0003.0001.S001"; String encodeRules = "使用AES对称加密";//加密规则 //加密 String content = se.AESEncode(encodeRules, url);//"NKnBfZZ3a2zWFzpDdjK8SDuNoEFET+THePSTS5PC+/x5FbXT/yADF9coj45tVFiuchqvx1gpoqcz uGE330Lxcy1xXxZHoHH5dEon7hmPe5UTuhjwPoO6pMroozY+bWwg"; System.out.println("根据输入的规则"+encodeRules+"加密后的密文是:"+content); //解密 url = se.AESDncode("使用AES对称加密", content);// 解密后的明文,解密规则需与加密规则想同 System.out.println("解密后:" + url);//"9C3CBD8E:o_se_ur_rada_flow_tdr/J.0003.0001.S001:0020190416000004Z9854J.0003.0001.S001"; } ---------------------------分割线--------------------------- 文末,特别说明,在URL参数中,我们通常会遇到特殊字符及符号,需要特别注意。大家可参考这个链接进行处理:https://www.jeffjade.com/2015/04/16/2015-04-16-deal-url-special-char/ 这里,也特别感谢罗山城同事对AES加密算法的分享! 此次对加密算法的分享到此结束,下一章将对APP消息推送方式进行分享,感兴趣的同事可持续关注,欢迎您的留言及点赞,谢谢~~~~~~ |
|
最新喜欢:罗山城 |