通常在开发过程当中,咱们为了保证敏感数据的安全性,才会对操做传输的数据进行加密,从而提升整个系统的安全性。html
好比,客户端和服务端的数据交互传输,服务端将从数据库查询出来的数据经过加密的方式传递给客户端,客户端也将用户提交的数据加密后提交给服务端,两边都经过对应的解密规则进行解密,这样在数据传输的过程当中,一些别有用心的人试图经过Fiddler这样的工具进行数据抓包而试图得到一些隐私数据将变得极其艰难,这也就达到了咱们对数据安全性提高目的。java
周一的时候,我接到了一个需求,某领导想要经过系统A免密跳转到系统B,由于领导以为再去系统B输入一次用户名、密码、验证码实在是太繁琐了,尤为是在他有大量的审批工做要作的状况下。算法
若是两个系通通一作的CAS单点登陆的前期框架性工做,这件事能够说根本不叫事,可是这个系统A和系统B都是近十年的老系统,确定是没有这样的条件的,因而如何将免密登陆的安全性提升就成了这个需求的重中之重了。数据库
先抛开加密自己,我先说一下我对这个需求的总体考虑:apache
具体步骤是:安全
总体的架构思路大体就是如此,这样就算别有用心的人使用抓包工具对这两次API请求都进行截获,也很难获取到真实的数据信息了。网络
用什么算法?架构
众所周知,加密方式有两个经常使用的大方向,一个是对称加密,一个是非对称加密。框架
对称加密:用相同的密钥对原文进行加密和解密,通讯双方共用一个密钥。ide
- 加密过程:原文 + 密钥 => 密文
- 解密过程:密文 - 密钥 => 原文
非对称加密:有两个密钥,即公钥(Public Key)和私钥(Private Key),对数据进行加密和解密使用不一样的密钥。使用公钥进行加密,使用私钥进行解密。
- 加密过程:原文 + 公钥 => 密文
- 解密过程:密文 - 私钥 => 原文
对称加密的缺点:
对称加密算法的缺点:没法确保密钥被安全传递。若是密钥被截获,则整个加密密文都是不安全的。
对称加密的特色:
采用非对称加密算法即便第三方在网络上截获到密文,但其没法得到接收方的私钥,也就没法对密文进行解密,做为接收方务必保证本身私钥的安全,因此非对称加密技术解决了密钥传输过程的安全性问题。
好了,看到这里,大方向确定定下来了,非对称加密跑不了了,而后咱们看看非对称加密有哪些加密算法呢?
RSA、Elgamal、背包算法、Rabin、Diffie-Hellman、ECC(椭圆曲线加密算法)。 使用最普遍的是RSA算法,Elgamal是另外一种经常使用的非对称加密算法,考虑到成本和学习曲线的问题,我此次选择了ElGamal加密算法,由于两点:
ElGamal算法不是双向加解密的,RSA是双向加解密的。
双向加解密:公钥、私钥均可以进行加密和解密(公钥加密须要私钥解密、私钥加密须要公钥解密)
ElGamal我在线查了半天也没找到解密工具,而RSA我查到了(固然,不肯定其是否可用)......
正所谓树大招风,与其使用RSA这种最多见的非对称加密,我仍是决定选择一些相对没那么热门的加密方式,这样一些常见的在线破解网站也不会提供简单的破解渠道,从而进一步增长数据的安全性,可是冷门,也带来了一些冷门固有的问题,这个后面再说。
当你找到一些ElGamal或者RSA的既有算法的DEMO后,兴高采烈的Run起它的main方法后,你有很大几率会遇到这个问题,一脸懵逼的你不用慌张,这是因为美帝的出口限制致使的加密算法Key长度的限制,具体缘由:
每一个国家,尤为是美国,对涉及密码的软件产品控制很是严格,在美国国内,不少密码算法长度都做了限制,并且某些算法在某些国家没有申请专利,能够"滥"用,而在某些国家却作了明确限制,不许使用,如此前提下,Sun必须按照惯例行事。
套用中国一句老话:上有政策,下有对策。Oracle也单独的放出了关于解决这个问题的无政策限制文件(local_policy.jar和US_export_policy.jar),咱们只要下载对应JDK版本的文件并覆盖到指定路径(%JDK_Home%\jre\lib\security)下便可。
这就是冷门带来的问题了,你并不能直接在JDK中使用ElGamal的算法支持,因此必需要引入两个jar包:
bouncycastle 下载地址:
commons-codec 下载地址:
这两个Jar包一个是对ElGamal算法自己提供支持的,另外一个是对Base64提供支持的,都须要引入到项目中去。
在实际使用ElGamal算法的时候,咱们不太可能只在一端使用公钥和私钥,这就面临着咱们须要在另外一个平台使用公钥加密的算法,常见的公钥加密算法是这样写的:
public static byte[] encryptByPublicKey(byte[] data,byte[] key) throws Exception{
//实例化密钥工厂
KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
//初始化公钥
//密钥材料转换
X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
//产生公钥
PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
//数据加密
Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return cipher.doFinal(data);
}
复制代码
当你在同一个程序中这样写公钥加密算法是没有问题的,由于你在启动main方法的时候,已经作好了initKey的相关工做了,可是你在另外一个平台直接调用该方法则会报出错误:
java.security.NoSuchAlgorithmException: ElGamal KeyFactory not available
复制代码
其实这也是冷门后遗症,由于JDK并无实现ElGamal算法,因此不作初始化就直接用KeyFactory调用对应算法的KeyFactory实例,是确定会报错的,解决方法就是本身作好初始化,走到天下都不怕:
public static byte[] encryptByPublicKey(byte[] data,byte[] key) throws Exception{
//加入对BouncyCastle支持
Security.addProvider(new BouncyCastleProvider());
AlgorithmParameterGenerator apg=AlgorithmParameterGenerator.getInstance(KEY_ALGORITHM);
//初始化参数生成器
apg.init(KEY_SIZE);
// 实例化密钥生成器
KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_ALGORITHM);
//实例化密钥工厂
KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
//初始化公钥
//密钥材料转换
X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
//产生公钥
PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
//数据加密
Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return cipher.doFinal(data);
}
复制代码
这个问题就不是每一个人都会遇到了,因为我是给服务端的同事写方法让他们各自调用本身那端须要的加密方法,因此我考虑了将他们须要的类封装成jar包的想法,因而我就将源码各自分离后,进行了基础的封装,而后经过Build FatJar将数据封装成jar包调用,测试调用的项目也顺利的引入了,一切就绪,运行main方法,而后就报错了.....
java.security.NoSuchAlgorithmException: Cannot find any provider supporting ElGamal
复制代码
不支持Elgaml???明明已经加上了对应的初始化方法了啊,怎会不执行呢?
其实这里,不是不执行初始化的方法,而是所需的第三方jar在jar包内部并无被正常加载致使的,我检查了一下jar的MANIFEST.MF文件发现合并打包时第三方丢失了Export-Package和Include-Resource对于第三方jar包的描述,解决方案能够查看:
而我这个项目因为只须要两个jar包,因此个人解决方案是单独导出个人jar包,而后在新项目中独立引入我导出的jar包和bouncycastle包以及codec包,这样一切均可以正常执行了。
以上就是我使用ElGamal算法时遇到的一些问题,但愿你们在使用的过程当中尽可能避开这些问题,也为本身作个记录。