密码的常用术语:
1. 密码体制: 由明文空间, 密文空间, 密钥空间, 加密算法和解密算法 5 部分组成.
2. 密码协议: 也称为安全协议, 是指以密码学为基础的消息交换的通信协议, 目的是在网络环境中提供安全的服务.
3. 柯克霍夫原则: 数据的安全基于密钥而不是算法的保密. 即系统的安全取决于密钥, 对密钥保密, 对算法公开.-- 现代密码学设计的基本原则.
密码的分类:
按照时间可以分为古典密码和现代密码.
按照加密算法是否公开可以分为受限制的算法和基于密钥的算法(之所以把算法公开主要是防止加密算法的发明人利用它做一些不为人知的事).
按照密码体制的不同可以分为对称密码, 非对称密码.
按照明文的处理方法, 可以分为:
分组密码: 加密时将明文分成固定长度的组, 用同一密钥和算法对每一块加密, 输出也是固定长度的密文. 多用于网络加密.
流密码: 也称为序列密码. 加密时每次加密一位或者一个字节明文.
散列函数(又称为 hash 函数), 可以用来验证数据的完整性. 它的特点是: 长度不受限制, hash 值容易计算, 散列的运算是不可逆的.
与散列函数相关的算法有: 消息摘要算法(MD5 等), 安全散列算法(SHA), 消息认证码算法(Mac).
数字签名: 主要针对以数字的形式存储的消息进行的处理.
OSI 与 TCP/IP 安全体系
业务流填充机制: 在数据传输的过程中填入一些额外的信息混淆真实的数据.
Java 安全组成, 包, 及第三方拓展
打开 jdk 安装目录下的 jre\lib\security\java.security 文件:
我们要使用第三地方的加解密的提供者可以在上面增加 provider 和它的引用. 参看文档的上面一部分我们可以使用调用方法的形式, 参见文档:
JDK 本身提供了 3 个包:
java.security: 消息摘要
javax.crypto: 安全消息摘要, 消息认证 (鉴别) 码
java.NET.ssl: 安全套接字(常用的类: HttpsURLConnection,SSLContext)
第三方 java 扩展:
Bouncy Castle: 支持两种方案:1配置;2调用
Commons Codec:Apache,Base64, 二进制, 十六进制, 字符集编码; URL 编码 / 解码
Base64 加密
base64 算法是基于 64 个字符的一种替换算法. base64 加密的产生式电子邮件的 "历史问题"-- 邮件只能传输 ASCII 码. base64 加密的应用场景: email, 密钥, 证书文件. 该算法可以由 3 种方式实现: JDK,Bouncy Castle,Commons Codec.
实现如下:
- package base64;
- import java.io.IOException;
- import org.apache.commons.codec.binary.Base64;
- import sun.misc.BASE64Decoder;
- import sun.misc.BASE64Encoder;
- /**
- * 该类是 Base64 算法的实现
- */
- public class JavaBase64 {
- private static String src = "面向对象编程, object-oriented!@#*5"; // 需要加密的原始字符串
- public static void main(String[] args) throws IOException {
- System.out.println("原始字符串:\t\t\t" + src);
- System.out.println();
- jdkBase64();
- System.out.println();
- commonsCodecBase64();
- System.out.println();
- bouncyCastleBase64();
- }
- /** JDK 实现 Base64 编码 */
- public static void jdkBase64() throws IOException{
- // 如果这里没有出现 sun 的 base64 可以从 Build Path 中删除然后添加
- BASE64Encoder encoder = new BASE64Encoder();
- String encode = encoder.encode(src.getBytes());// 编码
- BASE64Decoder decoder = new BASE64Decoder();
- String decode = new String(decoder.decodeBuffer(encode));// 解码
- System.out.println("JDK 实现的 base64 编码:\t\t" + encode);
- System.out.println("JDK 实现的 base64 解码:\t\t" + decode);
- }
- /** Commons Codec 实现 base64 编码 */
- public static void commonsCodecBase64() {
- byte[] encode = Base64.encodeBase64(src.getBytes());
- byte[] decode = Base64.decodeBase64(encode);
- System.out.println("Commons Codec 实现 base64 编码:\t" + new String(encode));
- System.out.println("Commons Codec 实现 base64 解码:\t" + new String(decode));
- }
- /**Bouncy Castle 实现 base64 编码 */
- public static void bouncyCastleBase64() {
- byte[] encode = org.bouncycastle.util.encoders.Base64.encode(src.getBytes());
- byte[] decode = org.bouncycastle.util.encoders.Base64.decode(encode);
- System.out.println("Bouncy Castle 实现 base64 编码:\t"+new String(encode));
- System.out.println("Bouncy Castle 实现 base64 解码:\t"+new String(decode));
- }
- }
运行结果(base64 比较经典的就是一等号结尾):
消息摘要算法加密
消息摘要算法主要分为 3 类: MD(Message Digest),SHA(Secure Hash Algorithm),Mac(Message Authentication Code), 以上 3 类算法的主要作用是验证数据的完整性 -- 是数字签名的核心算法.
消息摘要算法 --MD
MD 算法家族有 3 类 MD2,MD4,MD5,MD 家族生成的都是 128 位的信息摘要.
算法 | 摘要长度 | 实现方 |
MD2 | 128 | JDK |
MD4 | 128 | Bouncy Castle |
MD5 | 128 | JDK |
信息摘要算法由于使用的是一种单向函数, 所以理论上是不可破解的(山东大学的王晓云教授已经破解了 MD5 和 SHA, 所以消息摘要是可以伪造的, 只不过难度比较大). 所有 MD 算法进行摘要的结果都是 128 为位(32 位 16 进制的数字, 因为 1 位 16 进制数代表 4 位二进制数).
以下是 Java 中实现的各种 MD 加密:
- package md;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import java.security.Security;
- import org.apache.commons.codec.binary.Hex;
- import org.apache.commons.codec.digest.DigestUtils;
- import org.bouncycastle.crypto.Digest;
- import org.bouncycastle.crypto.digests.MD2Digest;
- import org.bouncycastle.crypto.digests.MD5Digest;
- import org.bouncycastle.jce.provider.BouncyCastleProvider;
- public class JavaMD {
- private static String src = "object-oriented"; // 需要加密的原始字符串
- public static void main(String[] args) throws NoSuchAlgorithmException {
- System.out.println("原始字符串:" + src + "\n");
- jdkMD5();
- bouncyCastleMD5();
- commonsCodecMD5();
- System.out.println();
- jdkMD2();
- bouncyCastleMD2();
- commonsCodecMD2();
- System.out.println();
- bouncyCastleMD4();
- }
- /** jdk 实现 MD5 加密 */
- public static void jdkMD5() throws NoSuchAlgorithmException {
- MessageDigest md = MessageDigest.getInstance("MD5");
- byte[] md5Bytes = md.digest(src.getBytes());
- System.out.println("JDK MD5:" + Hex.encodeHexString(md5Bytes));// 利用第三方包将 byte 数组转化为 16 进制字符串
- }
- /** jdk 实现 MD2 加密 */
- public static void jdkMD2() throws NoSuchAlgorithmException {
- MessageDigest md = MessageDigest.getInstance("md2");
- byte[] md5Bytes = md.digest(src.getBytes());
- System.out.println("JDK MD2:" + Hex.encodeHexString(md5Bytes));
- }
- /** Bouncy Castle 实现 MD4 加密 */
- public static void bouncyCastleMD4() throws NoSuchAlgorithmException{
- /* 通过这种方式给 JDK 动态添加一个 provider, 就可以通过这种方式获得 JDK 本身不支持的 MD4 了 */
- Security.addProvider(new BouncyCastleProvider());
- MessageDigest md = MessageDigest.getInstance("md4");
- byte[] md4Bytes = md.digest(src.getBytes());
- System.out.println("bc MD4:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md4Bytes));
- }
- /** Bouncy Castle 实现 MD5 加密 */
- public static void bouncyCastleMD5(){
- Digest digest = new MD5Digest();
- digest.update(src.getBytes(), 0, src.getBytes().length);
- byte[]md5Bytes = new byte[digest.getDigestSize()];
- digest.doFinal(md5Bytes, 0);
- System.out.println("bc MD5:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md5Bytes));
- }
- /** Bouncy Castle 实现 MD2 加密 */
- public static void bouncyCastleMD2(){
- Digest digest = new MD2Digest();
- digest.update(src.getBytes(), 0, src.getBytes().length);
- byte[]md2Bytes = new byte[digest.getDigestSize()];
- digest.doFinal(md2Bytes, 0);
- System.out.println("bc MD2:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md2Bytes));
- }
- /** Commons Codec 实现 MD5 加密 */
- public static void commonsCodecMD5() {
- System.out.println("cc MD5:\t" + DigestUtils.md5Hex(src.getBytes()));
- }
- /** Commons Codec 实现 MD2 加密 */
- public static void commonsCodecMD2() {
- System.out.println("cc MD2:\t" + DigestUtils.md2Hex(src.getBytes()));
- }
- }
以上程序的运行结果:
JDK 本身提供了 MD2 和 MD5 的实现, apache 的 Commons Codec 在 JDK 的基础上进行了改良, 使用 Commons Codec 提供接口进行 MD2 和 MD5 加密将会简单很多. JDK 本省并没有提供 MD4 算法的实现, 但是我们可以通过动态添加 provider 的方式让 jdk 支持 MD4, 见以下代码:
- /* 通过这种方式给 JDK 动态添加一个 provider, 就可以通过这种方式获得 JDK 本身不支持的 MD4 了 */
- Security.addProvider(new BouncyCastleProvider());
- MessageDigest md = MessageDigest.getInstance("md4");
- byte[] md4Bytes = md.digest(src.getBytes());
- System.out.println("bc MD4:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md4Bytes));
Bouncy Castle 提供了 MD2,MD4 和 MD5 的实现, 对消息摘要算法的支持比较完善, 但是 API 还是没有 Apache 的 Commons Codec 友善. 因此, 如果我们要进行 MD2 和 MD4 实现, 最好选用 Commons Codec.
MD 算法的应用
注册时:
应用程序服务器将用户提交的密码进行 MD5 即: 数据库中存放的用户名是明文, 而密码是密文 (16 进制字符串) 摘要算法, 得到 32 位的 16 进制字符串 (密文). 把用户名(明文) 和密码 (密文) 进行信息持久化存储到数据库中, 返回注册结果.
登录时:
应用程序服务器同样对密码进行 MD5 摘要, 然后将用户提交的用户名和密码的摘要信息和数据库中存储的信息进行比对, 返回登录结果.
消息摘要算法 --SHA
安全散列算法, 固定长度的摘要信息. 被认为是 MD5 的继承者. 是一个系列, 包括 SHA-1,SHA-2(SHA-224,SHA-256,SHA-384,SHA-512), 也就是除了 SHA-1, 其他的 4 种都被称为是 SHA-2. 每种算法的摘要长度和实现方如下:
SHA 算法的实现和 MD 算法的实现大同小异, 也是 JDK 提供了默认的几种实现, apache 的 Commons Codec 在 JDK 的基础上进行了优化, 使其更好用, 而 Bouncy Castle 是 JDK 的拓展, 提供了 JDK 和 Commons Codec 没有的 SHA-224 的实现.
- package sha;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import org.apache.commons.codec.binary.Hex;
- import org.apache.commons.codec.digest.DigestUtils;
- import org.bouncycastle.crypto.Digest;
- import org.bouncycastle.crypto.digests.SHA1Digest;
- import org.bouncycastle.crypto.digests.SHA224Digest;
- import org.bouncycastle.crypto.digests.SHA256Digest;
- public class JavaSHA {
- private static String src = "object-oriente"; // 需要加密的原始字符串
- public static void main(String[] args) throws NoSuchAlgorithmException {
- System.out.println("原始字符串:" + src);
- jdkSHA1();
- bouncyCastleSHA1();
- commonsCodecSAH1();
- System.out.println();
- bouncyCastleSHA224();
- System.out.println();
- jdkSHA256();
- bouncyCastleSHA256();
- }
- /** JDK 实现 sha-1 */
- public static void jdkSHA1() throws NoSuchAlgorithmException {
- MessageDigest md = MessageDigest.getInstance("sha");// sha1 算法传入参数为 sha
- byte[] sha1Bytes = md.digest(src.getBytes());
- System.out.println("JDK SHA-1:\t" + Hex.encodeHexString(sha1Bytes));
- }
- /** JDK 实现 sha-256 */
- public static void jdkSHA256() throws NoSuchAlgorithmException{
- MessageDigest md = MessageDigest.getInstance("sha-256");
- md.update(src.getBytes());
- System.out.println("JDK SHA-256:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md.digest()));
- }
- /** Bouncy Castle 实现 sha-1 */
- public static void bouncyCastleSHA1(){
- Digest digest = new SHA1Digest();
- digest.update(src.getBytes(), 0, src.getBytes().length);
- byte[]sha1Bytes = new byte[digest.getDigestSize()];
- digest.doFinal(sha1Bytes, 0);
- System.out.println("bc SHA-1:\t" + org.bouncycastle.util.encoders.Hex.toHexString(sha1Bytes));
- }
- /** Bouncy Castle 实现 sha-224 */
- public static void bouncyCastleSHA224(){
- Digest digest = new SHA224Digest();
- digest.update(src.getBytes(), 0, src.getBytes().length);
- byte[]sha224Bytes = new byte[digest.getDigestSize()];
- digest.doFinal(sha224Bytes, 0);
- System.out.println("bc SHA-224:\t" + org.bouncycastle.util.encoders.Hex.toHexString(sha224Bytes));
- }
- /** Bouncy Castle 实现 sha-256 */
- public static void bouncyCastleSHA256() {
- Digest digest = new SHA256Digest();
- digest.update(src.getBytes(), 0, src.getBytes().length);
- byte[] sha256Bytes = new byte[digest.getDigestSize()];
- digest.doFinal(sha256Bytes, 0);
- System.out.println("bc SHA-256:\t" + org.bouncycastle.util.encoders.Hex.toHexString(sha256Bytes));
- }
- /** Commons Codec 实现 sha-1 */
- public static void commonsCodecSAH1(){
- System.out.println("cc SHA-1:\t" + DigestUtils.sha1Hex(src.getBytes()));
- /* 采用下面的方式更加方便 */
- // System.out.println("cc SHA-1:\t" + DigestUtils.sha1Hex(src));
- }
- }
运行结果:
SHA 算法的应用
在浏览器的证书管理器中证书: Web 证书一般采用 SHA 算法.
消息摘要算法是为了防止消息在传输过程中的篡改.
我们在很多网站上都可以用 QQ 账号一键登录, 通常腾讯会给每一个接入方一个 key, 可能会约定一个消息传送的格式(例如: http://**?msg=12Hsad74mj&×tamp=1309488734), 其中 msg = 摘要信息 + key + 时间戳.
消息摘要算法 --Mac
Mac(Message Authentication Code), 兼容了 MD 和 SHA 的特性, 并且在它们的基础上加入了密钥. 因此 Mac 也称为 HMAC(keyed-Hash Message Authentication Code)含有密钥的散列函数算法.
MD 系列: HmacMD2,HmacMD4,HmacMD5
SHA 系列: HmacSHA1,HmacSHA224,HmacSHA256,HmacSHA384,HmacSHA512
例如: 常用的 Linux 客户端 SecurityCRT.Mac 的算法的提供者如下:
Commons Codec 中并没有提供 Hmac 算法的实现.
下面的程序以 JDK 本身和 Bouncy Castle 实现了 HmacMD5, 如果需要实现其他的加密只需要改变相关的参数即可:
- package hmac;
- import java.security.InvalidKeyException;
- import java.security.NoSuchAlgorithmException;
- import javax.crypto.KeyGenerator;
- import javax.crypto.Mac;
- import javax.crypto.SecretKey;
- import javax.crypto.spec.SecretKeySpec;
- import org.apache.commons.codec.DecoderException;
- import org.apache.commons.codec.binary.Hex;
- import org.bouncycastle.crypto.digests.MD5Digest;
- import org.bouncycastle.crypto.macs.HMac;
- import org.bouncycastle.crypto.params.KeyParameter;
- public class JavaHmac {
- private static String src = "object-oriente"; // 需要加密的原始字符串
- public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException, DecoderException {
- System.out.println("原始字符串:" + src + "\n");
- jdkHmacMD5();
- bouncyCastleHmacMD5();
- }
- public static void jdkHmacMD5() throws NoSuchAlgorithmException, InvalidKeyException, DecoderException{
- //1. 得到密钥
- KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");
- SecretKey secretKey = keyGenerator.generateKey();// 生成密钥
- // byte[] key = secretKey.getEncoded();// 获得密钥
- byte[] key = Hex.decodeHex("aabbccddee".toCharArray());
- //2. 还原密钥
- SecretKey restoreSecretKey = new SecretKeySpec(key, "hmacMD5");
- //3. 信息摘要
- Mac Mac = Mac.getInstance(restoreSecretKey.getAlgorithm());// 实例化 Mac
- Mac.init(restoreSecretKey);// 初始化 Mac
- byte[] hmacMD5Bytes = Mac.doFinal(src.getBytes());// 执行摘要
- System.out.println("jdkHmacMD5:\t" + Hex.encodeHexString(hmacMD5Bytes));
- }
- public static void bouncyCastleHmacMD5() {
- HMac hmac = new HMac(new MD5Digest());
- // 生成密钥的时候以 aabbccddee 为基准
- hmac.init(new KeyParameter(org.bouncycastle.util.encoders.Hex.decode("aabbccddee")));
- hmac.update(src.getBytes(), 0, src.getBytes().length);
- // 执行摘要
- byte[]hmacMDdBytes = new byte[hmac.getMacSize()];
- hmac.doFinal(hmacMDdBytes, 0);
- System.out.println("bcHmacMD5:\t"+org.bouncycastle.util.encoders.Hex.toHexString(hmacMDdBytes));
- }
- }
运行结果:
HMAC 算法的应用:
对称加密算法
加密密钥和解密密钥相同, 加密运算和解密运算互为逆运算. 是一种初等的加密算法. 主要的算法有 DES(3DES),AES,PBE,IDEA.
DES
数据加密标准(Data Encryption Standard),IBM 提交的算法.
- package des;
- import java.security.Security;
- import javax.crypto.Cipher;
- import javax.crypto.KeyGenerator;
- import javax.crypto.SecretKey;
- import javax.crypto.SecretKeyFactory;
- import javax.crypto.spec.DESKeySpec;
- import org.apache.commons.codec.binary.Hex;
- import org.bouncycastle.jce.provider.BouncyCastleProvider;
- public class JavaDES {
- private static String src = "面向对象编程, object-oriented!@#*5"; // 需要加密的原始字符串
- public static void main(String[] args) throws Exception {
- System.out.println("原始字符串:\n" + src);
- jdkDES();
- bouncyCastleDES();
- }
- /** jdk 实现 DES 加密 */
- public static void jdkDES() throws Exception{
- //1. 生成 key
- KeyGenerator keyGenerator = KeyGenerator.getInstance("des");// 密钥生成器
- keyGenerator.init(56);// 指定密钥长度为 56 位
- SecretKey secretKey = keyGenerator.generateKey();// 用密钥生成器生成密钥
- byte[] byteKeys = secretKey.getEncoded();// 得到密钥的 byte 数组
- //2.key 转换
- DESKeySpec desKeySpec = new DESKeySpec(byteKeys);
- SecretKeyFactory factory = SecretKeyFactory.getInstance("des");// 秘密密钥工厂
- SecretKey convertSecretKey = factory.generateSecret(desKeySpec);
- //3. 加密
- Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");// 见上图的工作模式和填充模式
- cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);// 加密模式
- byte[]result = cipher.doFinal(src.getBytes());
- System.out.println("jdk DES 加密:\n" + Hex.encodeHexString(result));
- //4. 解密
- cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);// 解密模式
- result = cipher.doFinal(result);
- System.out.println("jdk DES 解密:\n" + new String(result));
- }
- /** Bouncy Castle 实现 DES 加密 */
- public static void bouncyCastleDES() throws Exception{
- Security.addProvider(new BouncyCastleProvider());// 增加 provider
- //1. 生成 key
- KeyGenerator keyGenerator = KeyGenerator.getInstance("des","BC");// 密钥生成器, 指定为 bouncyCastle 默认是 sun 的 JCE
- keyGenerator.init(56);// 指定 key 长度为 56 位
- keyGenerator.getProvider();
- SecretKey secretKey = keyGenerator.generateKey();// 用密钥生成器生成密钥
- byte[] byteKeys = secretKey.getEncoded();// 得到密钥的 byte 数组
- //2.key 转换
- DESKeySpec desKeySpec = new DESKeySpec(byteKeys);
- SecretKeyFactory factory = SecretKeyFactory.getInstance("des");// 密钥工厂
- SecretKey convertSecretKey = factory.generateSecret(desKeySpec);
- //3. 加密
- Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
- cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);// 加密模式
- byte[]result = cipher.doFinal(src.getBytes());
- System.out.println("bc DES 加密:\n" + Hex.encodeHexString(result));
- //4. 解密
- cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);// 解密模式
- result = cipher.doFinal(result);
- System.out.println("bc DES 解密:\n" + new String(result));
- }
- }
运行结果:
在使用 bc 进行 DES 加解密的时候除了需要使用 Security.addProvider()方法增加一个 BouncyCastle, 还需要指定密钥生成器的提供者为 BC, 如上面的代码的 57 行, 否则会默认使用 sun 的 JCE. 应用场景:
3 重 DES
3DES 的好处是密钥长度增加. 迭代次数增加.
实现的方式通常由 JDK 和 BC 两种, 实现的方式和 DES 的实现方式大同小异:
- package des;
- import java.security.SecureRandom;
- import java.security.Security;
- import javax.crypto.Cipher;
- import javax.crypto.KeyGenerator;
- import javax.crypto.SecretKey;
- import javax.crypto.SecretKeyFactory;
- import javax.crypto.spec.DESedeKeySpec;
- import org.apache.commons.codec.binary.Hex;
- import org.bouncycastle.jce.provider.BouncyCastleProvider;
- public class Java3DES {
- private static String src = "面向对象编程, object-oriented!@#*5"; // 需要加密的原始字符串
- public static void main(String[] args) throws Exception {
- System.out.println("原始字符串:" + src + "\n");
- jdk3DES();
- bouncyCastle3DES();
- }
- /** jdk 实现 3DES */
- public static void jdk3DES() throws Exception{
- //1. 生成 key
- KeyGenerator keyGenerator = KeyGenerator.getInstance("desede");// 密钥生成器
- // keyGenerator.init(new SecureRandom()); // 可以用它生成一个默认长度的 key
- keyGenerator.init(168);// 指定密钥长度为 112 位
- SecretKey secretKey = keyGenerator.generateKey();// 用密钥生成器生成密钥
- byte[] byteKeys = secretKey.getEncoded();// 得到密钥的 byte 数组
- //2.key 转换
- DESedeKeySpec deSedeKeySpec = new DESedeKeySpec(byteKeys);
- SecretKeyFactory factory = SecretKeyFactory.getInstance("desede");// 秘密密钥工厂
- SecretKey convertSecretKey = factory.generateSecret(deSedeKeySpec);
- //3. 加密
- Cipher cipher = Cipher.getInstance("desede/ECB/PKCS5Padding");
- cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);// 加密模式
- byte[]result = cipher.doFinal(src.getBytes());
- System.out.println("jdk DES3 加密:\n" + Hex.encodeHexString(result));
- //4. 解密
- cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);// 解密模式
- result = cipher.doFinal(result);
- System.out.println("jdk DES3 解密:\n" + new String(result) + "\n");
- }
- /** bc 实现 3DES */
- public static void bouncyCastle3DES() throws Exception{
- Security.addProvider(new BouncyCastleProvider());
- //1. 生成 key
- KeyGenerator keyGenerator = KeyGenerator.getInstance("desede","BC");// 密钥生成器[指定 provider]
- keyGenerator.init(new SecureRandom());// 指定密钥的长度为默认
- SecretKey secretKey = keyGenerator.generateKey();// 用密钥生成器生成密钥
- byte[] byteKeys = secretKey.getEncoded();// 得到密钥的 byte 数组
- //2.key 转换
- DESedeKeySpec deSedeKeySpec = new DESedeKeySpec(byteKeys);
- SecretKeyFactory factory = SecretKeyFactory.getInstance("desede");// 秘密密钥工厂
- SecretKey convertSecretKey = factory.generateSecret(deSedeKeySpec);
- //3. 加密
- Cipher cipher = Cipher.getInstance("desede/ECB/PKCS5Padding");
- cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);// 加密模式
- byte[]result = cipher.doFinal(src.getBytes());
- System.out.println("bc DES3 加密:\n" + Hex.encodeHexString(result));
- //4. 解密
- cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);// 解密模式
- result = cipher.doFinal(result);
- System.out.println("bc DES3 解密:\n" + new String(result) + "\n");
- }
- }
运行结果:
AES
AES 产生的原因是 3 重 DES 的效率比较低而 DES 的安全性较低. AES 是目前使用最多的对称加密算法, AES 还有一个优势是至今尚未被破解. AES 通常用于移动通信系统的加密以及基于 SSH 协议的软件 (SSH Client,SecurityCRT) 的加密. 密钥长度以及实现方如下:
无政策限制权限文件是指: 因为某些国家的进口管制限制, java 发布的运行环境包中的一些加解密有一定的限制(因为美国政府的一些原因). 一般的 JDK 的 jre 的 security 包中的 local_policy.jar 和 US_export_policy.jar 都是没有内容的, 所以只能使用 128 位加密. 下面是 JDK 和 BC 实现的 AES 加密(步骤和 DES 类似):
- package aes;
- import java.security.Key;
- import java.security.Security;
- import javax.crypto.Cipher;
- import javax.crypto.KeyGenerator;
- import javax.crypto.SecretKey;
- import javax.crypto.spec.SecretKeySpec;
- import org.apache.commons.codec.binary.Base64;
- import org.bouncycastle.jce.provider.BouncyCastleProvider;
- public class JavaAES {
- private static String src = "面向对象编程, object-oriented!@#*5"; // 需要加密的原始字符串
- public static void main(String[] args) throws Exception {
- System.out.println("初始字符串:" + src + "\n");
- jdkAES();
- bouncyCastleAES();
- }
- public static void jdkAES() throws Exception{
- //1. 生成 key
- KeyGenerator keyGenerator = KeyGenerator.getInstance("aes");
- keyGenerator.init(128);// 初始化 key 的长度, 只能是 128,
- SecretKey secretKey = keyGenerator.generateKey();// 生成 key
- byte[] keyBytes = secretKey.getEncoded();// 得到 key 的字节数组
- //2.key 的转换
- Key key = new SecretKeySpec(keyBytes, "aes");
- //3. 加密
- Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");// 加解密方式 + 工作模式 + 填充方式
- cipher.init(Cipher.ENCRYPT_MODE, key);// 以加密模式初始化
- byte[] result = cipher.doFinal(src.getBytes());
- System.out.println("JDK AES 加密:" + Base64.encodeBase64String(result));
- //4. 解密
- cipher.init(Cipher.DECRYPT_MODE, key);
- result = cipher.doFinal(result);
- System.out.println("JDK AES 解密:" + new String(result));
- }
- public static void bouncyCastleAES() throws Exception{
- Security.addProvider(new BouncyCastleProvider());
- KeyGenerator keyGenerator = KeyGenerator.getInstance("aes", "BC");
- keyGenerator.init(128);// 这里只能指定 128, 不能使用 keyGenerator.init(new SecureRandom())
- SecretKey secretKey = keyGenerator.generateKey();
- byte[] keyBytes = secretKey.getEncoded();
- Key key = new SecretKeySpec(keyBytes, "aes");
- Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5padding");
- cipher.init(Cipher.ENCRYPT_MODE, key);
- byte[] result = cipher.doFinal(src.getBytes());
- System.out.println("bc AES 加密:" + Base64.encodeBase64String(result));
- cipher.init(Cipher.DECRYPT_MODE, key);
- result = cipher.doFinal(result);
- System.out.println("bc AES 解密:" + new String(result));
- }
- }
运行结果:
PBE
PBE 算法结合了消息摘要算法和对称加密算法的优点, 是一种特殊的对称加密算法. Password Based Encryption, 基于口令的加密. 因为口令是比较好记的, 就容易通过穷举, 猜测的方式获得口令 -- 针对这种情况, 我们采用的方式是加盐 (Salt), 通过加入一些额外的内容(通常是随机字符) 去扰乱. 实现的方式有 2 种: JDK 和 BC.
JDK 和 BC 实现的 PBEWithMD5AndDES 的算法如下:
- package pbe;
- import java.security.Key;
- import java.security.SecureRandom;
- import java.security.Security;
- import javax.crypto.Cipher;
- import javax.crypto.SecretKeyFactory;
- import javax.crypto.spec.PBEKeySpec;
- import javax.crypto.spec.PBEParameterSpec;
- import org.apache.commons.codec.binary.Base64;
- import org.bouncycastle.jce.provider.BouncyCastleProvider;
- public class JavaPBE {
- private static String src = "面向对象编程, object-oriented!@#*5"; // 需要加密的原始字符串
- public static void main(String[] args) throws Exception {
- System.out.println("原始字符串:" + src);
- jdkPBE();
- bouncyCastlePBE();
- }
- public static void jdkPBE() throws Exception{
- //1. 初始化盐
- SecureRandom secureRandom = new SecureRandom();// 强加密随机数生成器
- byte[] salt= secureRandom.generateSeed(8);// 产生盐必须是 8 位
- //2. 口令与密钥
- String password = "root";
- PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());// 密钥转换的对象
- SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");// 实例化密钥转换工厂
- Key key = factory.generateSecret(pbeKeySpec);// 由工厂产生 key
- //3. 加密
- PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 100);//PBE 输入参数的材料, 盐, 迭代 100 次
- Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
- cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec);
- byte[] result = cipher.doFinal(src.getBytes());
- System.out.println("jdk PBE 加密:" + Base64.encodeBase64String(result));
- //4. 解密
- cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec);
- result = cipher.doFinal(result);
- System.out.println("jdk PBE 解密:" + new String(result));
- }
- public static void bouncyCastlePBE() throws Exception{
- Security.addProvider(new BouncyCastleProvider());// 添加到 provider
- SecureRandom secureRandom = new SecureRandom();
- byte[] salt = secureRandom.generateSeed(8);
- String password = "admin";
- PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
- SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWithMD5AndDES","BC");// 指定 provider
- Key key = factory.generateSecret(pbeKeySpec);
- PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, 50);
- Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
- cipher.init(Cipher.ENCRYPT_MODE, key,parameterSpec);
- byte[]result = cipher.doFinal(src.getBytes());
- System.out.println("bc PBE 加密:" + Base64.encodeBase64String(result));
- cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec);
- result = cipher.doFinal(result);
- System.out.println("bc PBE 解密:" + new String(result));
- }
- }
运行结果:
应用场景:
非对称加密算法
加密密钥分为公钥和私钥. 可以使用公钥加密私钥解密, 也可以使用私钥加密公钥解密. 非对称加密算法主要有: DH(Diffie-Hellman)密钥交换算法, RSA(基于因子分解),Elgamal(基于离散对数),ECC(Elliptical Curve Cryptography, 椭圆曲线加密).
DH(密钥交换)算法
如何安全地传送密钥是对称加密算法的症结所在. 密钥交换算法是通过构建本地密钥来解决对称加密算法中的密钥传递的问题的.
实现该算法的步骤和所需要的类如下:
1. 初始化发送方密钥
- -KeyPairGenerator
- -KeyPair(密钥载体, 密钥对, 包括公约和私钥)
- -PublicKey
2. 初始化接收方密钥
- -KeyFactory(可以生成公钥和私钥)
- -X509EncodedKeySpec(根据 ASN.1 标准进行密钥编码)
- -DHPublicKey
- -DHParameterSpec
- -KeyPairGenerator
- -PrivateKey
3. 密钥构建
- -KeyAgreement(提供密钥一致性或密钥交换协议的功能)
- -SecretKey(生成一个分组的秘密密钥)
- -KeyFactory
- -X509EncodedKeySpec
- -PublicKey
4. 加解密
-Cipher(JCE 框架的核心)
具体实现:
- package dh;
- import java.security.KeyFactory;
- import java.security.KeyPair;
- import java.security.KeyPairGenerator;
- import java.security.PrivateKey;
- import java.security.PublicKey;
- import java.security.spec.X509EncodedKeySpec;
- import java.util.Objects;
- import javax.crypto.Cipher;
- import javax.crypto.KeyAgreement;
- import javax.crypto.SecretKey;
- import javax.crypto.interfaces.DHPublicKey;
- import javax.crypto.spec.DHParameterSpec;
- import org.apache.commons.codec.binary.Base64;
- public class JavaDH {
- private static String src = "面向对象编程, object-oriented!@#*5"; // 需要加密的原始字符串
- public static void main(String[] args) throws Exception {
- System.out.println("初始字符串:" + src);
- jdkDH();
- }
- /** JDK 实现密钥交换算法 */
- public static void jdkDH() throws Exception{
- //1. 初始化发送方密钥
- KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator.getInstance("dh");
- senderKeyPairGenerator.initialize(512);// 密钥长度 512
- KeyPair senderKeyPair = senderKeyPairGenerator.generateKeyPair();
- byte[] senderPublicKeyEnc = senderKeyPair.getPublic().getEncoded();// 发送方公钥(需要把这个发送给)
- //2. 初始化接收方密钥
- KeyFactory receiverkeyFactory = KeyFactory.getInstance("dh");
- X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(senderPublicKeyEnc);
- PublicKey receiverPublicKey = receiverkeyFactory.generatePublic(x509EncodedKeySpec);
- DHParameterSpec dhParameterSpec = ((DHPublicKey)receiverPublicKey).getParams();
- KeyPairGenerator receiverKeyPairGenerator = KeyPairGenerator.getInstance("dh");
- receiverKeyPairGenerator.initialize(dhParameterSpec);
- KeyPair receiverKeyPair = receiverKeyPairGenerator.generateKeyPair();
- PrivateKey receiverPrivateKey = receiverKeyPair.getPrivate();
- //3. 密钥构建
- KeyAgreement receiverkeyAgreement = KeyAgreement.getInstance("dh");
- receiverkeyAgreement.init(receiverPrivateKey);
- receiverkeyAgreement.doPhase(receiverPublicKey, true);
- SecretKey receiverDesKey = receiverkeyAgreement.generateSecret("des");
- byte[] receiverPublicKeyEnc = receiverKeyPair.getPublic().getEncoded();
- KeyFactory senderKeyFactory = KeyFactory.getInstance("dh");
- x509EncodedKeySpec = new X509EncodedKeySpec(receiverPublicKeyEnc);
- PublicKey senderPublicKey = senderKeyFactory.generatePublic(x509EncodedKeySpec);
- KeyAgreement senderKeyAgreement = KeyAgreement.getInstance("dh");
- senderKeyAgreement.init(senderKeyPair.getPrivate());
- senderKeyAgreement.doPhase(senderPublicKey, true);
- SecretKey senderDesKey = senderKeyAgreement.generateSecret("des");
- if (Objects.equals(senderDesKey,receiverDesKey)) {
- System.out.println("双方密钥相同");
- }
- //4. 加密
- Cipher cipher = Cipher.getInstance("des");
- cipher.init(Cipher.ENCRYPT_MODE, senderDesKey);
- byte[] result = cipher.doFinal(src.getBytes());
- System.out.println("密钥交换算法加密:" + Base64.encodeBase64String(result));
- //5. 解密
- cipher.init(cipher.DECRYPT_MODE, receiverDesKey);
- result = cipher.doFinal(result);
- System.out.println("密钥交换算法解密:" + new String(result));
- }
- }
运行结果:
非对称加密算法 --RSA
RSA 是唯一被广泛接受并实现的通用算法.
在 RSA 算法中公钥的长度远远小于私钥的长度. 以下是其 java 实现:
- package rsa;
- import java.security.KeyFactory;
- import java.security.KeyPair;
- import java.security.KeyPairGenerator;
- import java.security.PrivateKey;
- import java.security.PublicKey;
- import java.security.interfaces.RSAPrivateKey;
- import java.security.interfaces.RSAPublicKey;
- import java.security.spec.PKCS8EncodedKeySpec;
- import java.security.spec.X509EncodedKeySpec;
- import javax.crypto.Cipher;
- import org.apache.commons.codec.binary.Base64;
- public class JavaRSA {
- private static String src = "面向对象编程, object-oriented!@#*5"; // 需要加密的原始字符串
- public static void main(String[] args) throws Exception {
- System.out.println("初始字符串:" + src);
- jdkRSA();
- }
- public static void jdkRSA() throws Exception{
- //1. 初始化密钥
- KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
- keyPairGenerator.initialize(512);// 密钥长度为 64 的整数倍, 最大是 65536
- KeyPair keyPair = keyPairGenerator.generateKeyPair();
- RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
- RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
- System.out.println("RSA 公钥:" + Base64.encodeBase64String(rsaPublicKey.getEncoded()));
- System.out.println("RSA 私钥:" + Base64.encodeBase64String(rsaPrivateKey.getEncoded()));
- //2.1 私钥加密, 公钥解密[加密]
- PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
- KeyFactory keyFactory = KeyFactory.getInstance("RSA");
- PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
- Cipher cipher = Cipher.getInstance("RSA");
- cipher.init(Cipher.ENCRYPT_MODE, privateKey);
- byte[] result = cipher.doFinal(src.getBytes());
- System.out.println("JDK RSA 私钥加密:" + Base64.encodeBase64String(result));
- //2.2 私钥加密, 公钥解密[解密]
- X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
- keyFactory = KeyFactory.getInstance("RSA");
- PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
- cipher.init(Cipher.DECRYPT_MODE, publicKey);
- result = cipher.doFinal(result);
- System.out.println("JDK RSA 公钥解密:" + new String(result));
- //3.1 公钥加密, 私钥解密[加密]
- x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
- keyFactory = KeyFactory.getInstance("RSA");
- publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
- cipher.init(Cipher.ENCRYPT_MODE, publicKey);
- result = cipher.doFinal(src.getBytes());
- System.out.println("JDK RSA 公钥加密:" + Base64.encodeBase64String(result));
- //3.2 公约加密, 私钥解密[解密]
- pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
- keyFactory = KeyFactory.getInstance("RSA");
- privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
- cipher.init(Cipher.DECRYPT_MODE, privateKey);
- result = cipher.doFinal(result);
- System.out.println("JDK RSA 私钥解密:" + new String(result));
- }
- }
RSA 有两种模式公钥加密私钥解密和私钥加密公钥解密两种模式, 其序列图如下:
Elgamal 算法
和 RSA 不同的是它只提供公钥加密, 它依靠 BouncyCastle 实现.
java 实现如下:
- package elgamal;
- import java.security.AlgorithmParameterGenerator;
- import java.security.AlgorithmParameters;
- import java.security.KeyFactory;
- import java.security.KeyPair;
- import java.security.KeyPairGenerator;
- import java.security.PrivateKey;
- import java.security.PublicKey;
- import java.security.SecureRandom;
- import java.security.Security;
- import java.security.spec.PKCS8EncodedKeySpec;
- import java.security.spec.X509EncodedKeySpec;
- import javax.crypto.Cipher;
- import javax.crypto.spec.DHParameterSpec;
- import org.apache.commons.codec.binary.Base64;
- import org.bouncycastle.jce.provider.BouncyCastleProvider;
- /**
- * 非对称加密算法 --ELGamal 算法
- * 对于:"Illegal key size or default parameters" 异常, 是因为美国的出口限制, Sun 通过权限文件 (local_policy.jar,US_export_policy.jar) 做了相应限制.
- * Java 7 无政策限制文件: http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html,
- * 下载后得到 UnlimitedJCEPolicyJDK7.zip, 解压替换 %JAVA_HOME%/jre/lib/security 的两个文件即可
- * @author gaopengfei
- *
- */
- public class JavaELGamal {
- private static String src = "object-oriented!@#*5"; // 需要加密的原始字符串
- public static void main(String[] args) throws Exception {
- System.out.println("初始字符串:" + src);
- bouncyCastleELGamal();
- }
- /**
- * Bouncy Castle 实现 ELGamal, 这种算法和 RSA 算法的区别是只能公钥加密, 私钥解密
- * */
- private static void bouncyCastleELGamal() throws Exception{
- Security.addProvider(new BouncyCastleProvider());// 加入对 Bouncy Castle 的支持
- //1. 初始化发送方密钥
- AlgorithmParameterGenerator algorithmParameterGenerator = AlgorithmParameterGenerator.getInstance("ELGamal");
- algorithmParameterGenerator.init(256);// 初始化参数生成器
- AlgorithmParameters algorithmParameters = algorithmParameterGenerator.generateParameters();// 生成算法参数
- DHParameterSpec dhParameterSpec = (DHParameterSpec)algorithmParameters.getParameterSpec(DHParameterSpec.class);// 构建参数材料
- KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ELGamal");// 实例化密钥对生成器
- // 初始化密钥对生成器
- keyPairGenerator.initialize(dhParameterSpec, new SecureRandom());
- KeyPair keyPair = keyPairGenerator.generateKeyPair();
- // 公钥和私钥
- PublicKey elGamalPublicKey = keyPair.getPublic();
- PrivateKey elGamalPrivateKey = keyPair.getPrivate();
- System.out.println("ELGamal 公钥:" + Base64.encodeBase64String(elGamalPublicKey.getEncoded()));
- System.out.println("ELGamal 私钥:" + Base64.encodeBase64String(elGamalPrivateKey.getEncoded()));
- //2. 加密[公钥加密]
- X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(elGamalPublicKey.getEncoded());
- KeyFactory keyFactory = KeyFactory.getInstance("ELGamal");
- elGamalPublicKey = (PublicKey) keyFactory.generatePublic(x509EncodedKeySpec);
- Cipher cipher = Cipher.getInstance("ELGamal","BC");
- cipher.init(Cipher.ENCRYPT_MODE, elGamalPublicKey);
- byte[] result = cipher.doFinal(src.getBytes());
- System.out.println("ELGamal 公钥加密:" + Base64.encodeBase64String(result));
- //3. 解密[私钥解密]
- PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(elGamalPrivateKey.getEncoded());
- keyFactory = KeyFactory.getInstance("ELGamal");
- elGamalPrivateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
- cipher.init(Cipher.DECRYPT_MODE, elGamalPrivateKey);
- result = cipher.doFinal(result);
- System.out.println("ELGamal 私钥解密:" + new String(result));
- // // 加密[私钥加密]
- // pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(elGamalPrivateKey.getEncoded());
- // keyFactory = KeyFactory.getInstance("ELGamal");
- // elGamalPrivateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
- // cipher.init(Cipher.ENCRYPT_MODE, elGamalPrivateKey);
- // result = cipher.doFinal(src.getBytes());
- // System.out.println("ELGamal 私钥加密:" + Base64.encodeBase64String(result));
- //
- // // 解密[公钥解密]
- // x509EncodedKeySpec = new X509EncodedKeySpec(elGamalPublicKey.getEncoded());
- // keyFactory = KeyFactory.getInstance("ELGamal");
- // elGamalPublicKey = keyFactory.generatePublic(x509EncodedKeySpec);
- // cipher.init(Cipher.DECRYPT_MODE, elGamalPublicKey);
- // result = cipher.doFinal(result);
- // System.out.println("ELGamal 解密:" + new String(result));
- }
- }
数字签名
数字签名是带有密钥 (公钥, 私钥) 的消息摘要算法. 主要作用是验证数据的完整性, 认证数据来源, 抗否认. 在数字签名的实现中我们使用私钥签名, 公钥验证. 常用的数字签名算法包括 RSA,DSA,ECDSA.
RSA
该算法是数字签名的经典算法. 主要包括 MD 和 SHA 两类.
Java 实现 RSA 数字签名如下:
- package rsa2;
- import java.security.KeyFactory;
- import java.security.KeyPair;
- import java.security.KeyPairGenerator;
- import java.security.PrivateKey;
- import java.security.PublicKey;
- import java.security.Signature;
- import java.security.interfaces.RSAPrivateKey;
- import java.security.interfaces.RSAPublicKey;
- import java.security.spec.PKCS8EncodedKeySpec;
- import java.security.spec.X509EncodedKeySpec;
- import org.apache.commons.codec.binary.Hex;
- public class JavaRSA {
- private static String src = "What can I do for you?";
- public static void main(String[] args) throws Exception {
- jdkRSA();
- }
- public static void jdkRSA() throws Exception{
- //1. 初始化密钥
- KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
- keyPairGenerator.initialize(512);
- KeyPair keyPair = keyPairGenerator.generateKeyPair();
- RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
- RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
- //2. 执行数字签名[私钥签名]
- PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
- KeyFactory keyFactory = KeyFactory.getInstance("RSA");
- PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
- Signature signature = Signature.getInstance("MD5WithRSA");
- signature.initSign(privateKey);
- signature.update(src.getBytes());
- byte[] result = signature.sign();
- System.out.println("JDK RSA 签名:" + Hex.encodeHexString(result));
- //3. 验证签名[公钥验证]
- X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
- keyFactory = KeyFactory.getInstance("RSA");
- PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
- signature = Signature.getInstance("MD5WithRSA");
- signature.initVerify(publicKey);
- signature.update(src.getBytes());
- boolean bool = signature.verify(result);
- System.out.println("数字签名是否有效?" + bool);
- }
- }
运行结果:
DSA 算法
DSS(Digital Signature Standard), 数字签名标准, 通过这个标准逐步形成了 DSA(Digital Signature Algorithm), 数字签名算算法. DSA 仅仅包括数字签名, 不能进行加解密. 实现方式如下:
该算法到的实现和 RSA 数字签名的实现大同小异(只是在细节参数方面存在很少的差别). 见如下:
JavaDSA.java
程序运行结果:
ECDSA
微软的 Office,Windows 操作系统的验证就是 ECDSA 算法 -- 椭圆曲线数字签名算法(Elliptic Curve Digital Signature Algorithm), 在 2000 年的时候称为了 ANSI 和 IEEE 的标准. 特点是: 速度快, 签名短, 强度高. 在 JDK1.7update4 之后提供了对 ECDSA 的支持. 该签名的算法也和 RSA 的数字签名算法也是大同小异.
JavaECDSA.java
运行结果:
最后附上一系列 Java 加密的项目地址(包括 Base64, 对称加密, 非对称加密, 消息摘要和数字签名). 本文所需的 jar 文件在项目的 lib 目录中, jdk 无政策访问限制文件在项目的 ext 目录下.
来源: https://www.cnblogs.com/xinglongbing521/p/10627774.html