java数据安全 系列文章

1、【java数据安全】数据安全之加密解密(base64、MD、SHA、DES、AES、IDEA、PBE、DH、RSA、EIGamal)、数字签名(DSA、ECDSA)和数字证书介绍、应用示例详细介绍
2、【java数据安全】base64与报文摘要MD(md5、sha、mac)简单介绍及应用场景、示例
3、【java数据安全】对称加密的5种(DES/3DES、AES、IDEA、PBE)常见算法的使用示例
4、【java数据安全】非对称加密算法(DH、RSA、EIGamal/DSA)的介绍、应用场景和示例
5、【java数据安全】数字签名的三种算法(RSA、DSA和ECDSA)使用示例
6、【java数据安全】数字信封介绍及实现流程
7、【java数据安全】国家商用密码介绍及对称加密、非对称加密使用示例(一)
8、【java数据安全】国家商用密码介绍及数字签名、密钥交换、密钥编码格式使用示例(二)


文章目录

  • java数据安全 系列文章
  • 一、基本概念介绍
    • 1、保密性
    • 2、完整性
    • 3、可用性
    • 4、可靠性
    • 5、抗否认性
    • 6、可控性
    • 7、可审查性
    • 8、认证(鉴别)
    • 9、访问控制
    • 10、OSI参考模型
    • 11、8类安全机制
    • 12、加密算法分类
    • 13、java与密码
    • 14、Kerckhoffs principle(科克霍夫原则)
  • 二、加密算法简单介绍及应用场景、示例
    • 1、base64
      • 1)、定义
      • 2)、应用场景
      • 3)、示例
    • 2、消息摘要(Message Digest)
      • 1)、MD
      • 2)、SHA
      • 3)、MAC
    • 3、对称加密
      • 1)、定义
      • 2)、DES
      • 3)、AES
      • 4)、IDEA
      • 5)、PBE
    • 4、非对称加密
      • 1)、定义
      • 2)、DH
      • 3)、RSA
      • 4)、EIGamal/DSA
  • 三、数字签名算法介绍、应用场景和示例
    • 1、介绍
    • 2、RSA签名
      • 1)、介绍
      • 2)、示例
    • 2、DSA签名
      • 1)、介绍
      • 2)、示例
    • 3、ECDSA签名
      • 1)、介绍
      • 2)、示例
  • 四、数字证书
    • 1、介绍
    • 2、证书签发过程
    • 3、示例

本文简单的介绍了数据安全的概念、加密解密常见的算法、数字签名介绍、数字证书的介绍及相关示例。
本文是该系列的第一篇,入门介绍。
本文部分图片来源互联网。

一、基本概念介绍

1、保密性

保密性是确保数据仅能被合法用户访问,即数据不能被未授权的第三方使用。一般通过对称加密来完成保密性,同时也能防窃听,对称加密当前安全性较高的算法有AES和PBE算法。

2、完整性

确保数据只能由授权方或以授权的方式进行修改,即数据在传输过程中不能被未授权方修改。一般通过两方面进行控制,即网络传输过程通过https;另一方面是针对传输的数据进行签名,首选需要使用第三方CA授权的数字证书,次选则是和业务相关的数字签名。数字签名使用算法首选使用ECDSA算法,次选RSA256/512。如果涉及国密的情况,则根据需要选择需要即可,国密算法没有那么多,都是有固定的用途的。SM2和ECDSA对应,都是椭圆曲线,SM2和RSA都是非对称加密。

3、可用性

确保所有的数据仅在适当的时候可以由授权方访问。针对接口做到高可用,一般是通过服务端的高可用技术实现,比如通过keepalived+LVS中间件来控制心跳,一旦一台服务器出现故障则实时进行切换。

4、可靠性

确保系统能在规定的条件下、规定的时间内、完成规定功能时具有稳定的概率。在确保系统正常运行的同时,提高服务对外提供服务的能力,比如说服务的正确性、规定时间内停机时长等要求。

5、抗否认性

也称抗抵赖性,确保发送方与接收方在执行各自操作后,对所做的操作不可否认。抗抵赖性一般通过数字签名来实现,发送方通过私钥签名,接收方通过公钥验证,通过则表示是发送方的数据。为保证私钥的泄漏,则建议使用一次性私钥,即每次私钥使用一次,用完即毁且不留存任何日志及传输。数字签名使用非对称针对报文摘要进行加密,一般推荐算法是ECDSA。针对PC端的抗抵赖性,一般可以通过数字信封来保证其抗抵赖性,即针对传递的消息进行签名获得其公钥,使用随机数作为密钥对传递消息进行加密,然后利用公钥对随机数密钥进行对称加密,最后将密文、公钥等信息传递给接收方,接收方的操作则是反过来的。为了实际应用的更加安全,在生成密钥的时候,可以把设备号或mac作为密钥生成因子,保证一定程度上的公钥的安全性。

6、可控性

对信息及信息系统实施安全监控。通过接口平台的监控功能实现接口的监控,出现异常情况时则做到一定的容错及及时报警。

7、可审查性

通过审计、监控、抗抵赖性等安全机制,确保数据访问者的行为有证可查,当网络出现安全异常时,提供调查的依据和手段。一般通过日志、数字签名等等方式来保证数据的有据可查以及抗抵赖性。

8、认证(鉴别)

确保数据访问者和信息服务者的身份真实有效。一般通过数字签名来保证信息的认证和鉴别。数字签名不再赘述。

9、访问控制

确保数据不被非授权方或以未授权的方式使用。确保接口的访问都是通过授权访问的,比如需要登录后才能访问,ip白名单等控制方式。

10、OSI参考模型



在OSI安全体系结构中通过数据加密确保数据的保密性,在TCP/IP安全体系结构中以加密算法为基础构建SSL/TSL协议。

11、8类安全机制

八类安全机制包括加密机制、数字签名机制、访问控制机制、数据完整性机制、认证机制、业务流填充机制、路由控制机制和公证机制。

  • 加密机制,加密机制对应数据保密性服务。加密是提高数据安全性的最简单方法,通过对数据进行加密,有效提高了数据的保密性,能防止数据在传输过程中被窃取,常用的加密算法有对称加密和非对称加密。典型的对称加密算法有DES、ASE等,非对称加密算法有RSA等。
  • 数字签名机制,数字签名机制对应的是认证(鉴别)服务,数字签名是有效的鉴别方法,利用数字签名技术可以实施用户身份认证和消息认证,他具有借鉴收发双方纠纷的能力,是认证服务最核心的技术。在数字签名技术的基础上,为了鉴别软件的有效性,又产生了代码签名技术。常用的签名算法有RSA、DSA、SM2等算法。
  • 访问控制机制,访问控制机制对应访问控制服务,通过预先设定的规则对用户所访问的数据进行限制。通常,首先是通过用户的用户名和口令进行验证,其次是通过用户的角色、用户组等规则进行验证,最后是用户才能访问的限制资源。一般的应用常使用基于用户角色的访问控制方式,如RBAC。
  • 数据完整性机制,数据完整性机制对应数据完整性服务,数据完整性的作用是为了避免数据在传输过程中受到干扰,同时防止数据在传输过程中被篡改,以提高数据传输完整性。通常可以用单向加密算法对数据进行加密,生成唯一的验证码,用以校验数据的完整性。常用的加密算法有MD5和SHA算法。
  • 认证机制,认证机制对应认证(鉴别)服务,认证的目的在于验证接收方所接收到的数据是否来源于所期望的发送方,通常使用数字签名来认证。常用的算法有RSA和DSA等。
  • 业务流填充机制,或传输流填充机制,对应数据保密性服务,业务流填充机制通过在数据传输过程中传送随机数的方式混淆真实的数据,加大数据破解难度,提高数据的保密性。
  • 路由控制机制,对应访问控制服务,路由控制机制为数据发送方选择安全网络通信路径,避免发送方使用不安全路径发送数据,提高数据的安全性。
  • 公证机制,对应抗否认性服务,公证机制的左右在于解决收发双方的纠纷问题,确保两方利益不受到损害。比如双方签订的合同,需要到第三方公证机构进行公证。

12、加密算法分类

加密算法大致上分为单向加密算法、对称加密算法和非对称加密算法。

  • 单向加密算法,是数据完整性验证的常用算法,包括MD5、SHA算法等
  • 对称加密算法,是数据存储加密的常用算法,加密与解密的密钥相同,包括DES、ASE等
  • 非对称加密算法,是数据传输加密的常用算法,加密和解密的密钥不同,包括RSA等。用公钥加密用私钥解密或用私钥加密用公钥解密。
    对称加密也可用在数据传输上,但非对称加密在密钥管理上更有优势,相对对称加密,非对称加密在安全级别上等级更高,但时间效率上不如对称加密。

13、java与密码

java对密码支持比较充分,可从以下三个方面来说

  • java api支持常用的加密算法,MessageDigest类可以构建MD5、SHA;Mac类可以构建HMAC;Cipher类可以构建DES、AES、Blowfish等对称加密算法和RSA、DSA、DH等非对称加密;Signature类可以用于数字签名和验证;Certificate类可以操作数字证书等。同时还有其他开源类库支持,比如bc等,在接下来的系列文中均有详细的示例。
  • jps容器支持,比如tomcat可以简单的配置https,一般常见的web容器都会支持https
  • java工具支持,可以通过jdk自带的工具keytool完成密钥管理、证书管理;通过jarsigner可以完成代码签名

14、Kerckhoffs principle(科克霍夫原则)

Kerckhoffs principle:数据的安全基于密钥而不是算法的保密,即数据的安全取决于对密钥的保密,对算法公开。该原则也是现代密码学设计的基本原则。
密码算法的公开有助于提高算法的安全性,避免算法自身的漏洞。

二、加密算法简单介绍及应用场景、示例

1、base64

1)、定义

内容传送编码是一种以任意8位字节列组合的描述形式,这种形式不容易被人直接识别。经过base64编码后的数据会比原来数据长约1/3,经过base64编码后的字符串的字符数是以4为单位的整数倍。实现base64的算法推荐使用apache的common codec类库。

2)、应用场景

电子邮件传输、网络数据传输、密钥存储、数字证书存储

3)、示例

import java.util.Base64;/*** @author alan 2018年11月15日* jdk*/
public class Base64Coder {/*** 字符编码*/public final static String ENCODING = "UTF-8";/*** Base64编码* * @param data* @return* @throws Exception*/public static String encode(String data) throws Exception {Base64.Encoder encoder = Base64.getEncoder();byte[] b = data.getBytes(ENCODING);return encoder.encodeToString(b);}/*** Base64解码* * @param data* @return* @throws Exception*/public static String decode(String data) throws Exception {Base64.Decoder decoder = Base64.getDecoder();byte[] b = decoder.decode(data);return new String(b, ENCODING);}
}

2、消息摘要(Message Digest)

消息摘要算法包含三大系列,即MD 、SHA 和MC,常用于验证数据的完整性,是数字签名的核心算法。
任何消息经过散列函数处理后都会获得唯一的散列值(hashcode),该过程称为消息摘要,其散列值成为数字指纹,其算法即是消息摘要算法。
消息摘要算法又称为散列算法,其核心在于散列函数的单向性,即通过散列函数可获得对应的散列值,但不可通过该散列值获得其原始信息。

  • MD,message digest,消息摘要算法,包括MD2、MD4、MD5
  • SHA,secure hash algorithm,安全散列算法,包括SHA-224、SHA-256、SHA-384、SHA-512
  • MAC,message authentication code,消息认证码算法,综合了MD和SHA算法,包括HmacMD5、HmacSHA1、HmacSHA256、HmacSHA384、HmacSHA512

1)、MD

  • 定义
    MD5是由MD2、MD3、MD4改进而来,是典型的消息摘要算法。MD5算法对输入任意长度的消息进行运行,产生一个128位的消息摘要。如果将这个128位的信息摘要信息换算成十六进制,则可以得到一个32位的字符串(32位的数字字母混合码)。
  • 应用场景
    MD5之后的推荐替代应该是SHA,已经不适合安全性要求较高的场景。
  • 代码示例
import java.security.MessageDigest;/*** @author alan 2018年11月15日 jdk*/
public class MDCoder {public static byte[] encodeMD2(byte[] data) throws Exception {// 初始化MessageDigestMessageDigest md = MessageDigest.getInstance("MD2");// 执行消息摘要return md.digest(data);}public static byte[] encodeMD5(byte[] data) throws Exception {// 初始化MessageDigestMessageDigest md = MessageDigest.getInstance("MD5");// 执行消息摘要return md.digest(data);}
}

2)、SHA

  • 定义
    SHA算法是基于MD4算法的,已经成为消息摘要的首选,与MD不同的是其摘要更长,安全性更高。
    SHA算法有SHA-1、SHA-224、SHA-256、SHA-384、SHA-512,除了SHA-1外,其他都是根据信息摘要的长度命名的。SHA-224是为了符合3DES的需要而定义的。
  • 应用场景
    需要报文摘要功能,且安全要求比较高的应用场景,目前很多数字签名都是使用SHA的算法。
  • 示例
    SHA-224是由BouncyCastleProvider实现,jdk本身没有实现。
import java.security.MessageDigest;/*** @author alan 2018年11月15日*/
public class SHACoder {/*** SHA-1加密*/public static byte[] encodeSHA(byte[] data) throws Exception {// 初始化MessageDigestMessageDigest md = MessageDigest.getInstance("SHA");// 执行消息摘要return md.digest(data);}/*** SHA-256加密*/public static byte[] encodeSHA256(byte[] data) throws Exception {// 初始化MessageDigestMessageDigest md = MessageDigest.getInstance("SHA-256");// 执行消息摘要return md.digest(data);}/*** SHA-384加密*/public static byte[] encodeSHA384(byte[] data) throws Exception {// 初始化MessageDigestMessageDigest md = MessageDigest.getInstance("SHA-384");// 执行消息摘要return md.digest(data);}/*** SHA-512加密*/public static byte[] encodeSHA512(byte[] data) throws Exception {// 初始化MessageDigestMessageDigest md = MessageDigest.getInstance("SHA-512");// 执行消息摘要return md.digest(data);}
}

3)、MAC

  • 定义
    MAC是含有密钥散列函数算法,包含了MD和SHA的特性,并在此基础上加入了密钥,通常也会把MAC成为HMAC(keyed-Hash Message Authentication Code)。MAC算法集合了MD和SHA两大系列消息摘要算法,MD系列有HmacMD2、HmacMD4、HmacMD5,SHA系列有HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512。
    经MAC算法得到的摘要值可以使用十六进制编码表示,其摘要值长度与参与实现的算法摘要值长度相同,比如HmacSHA1算法得到的摘要长度就是SHA1算法得到摘要长度,都是160位二进制数,换算成十六进制编码为40位。

  • 应用场景
    在MD和SHA均不满足使用场景要求的时候,MAC是一个有效的补充。

  • 示例

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;/*** @author alan 2018年11月15日*/
public class MACCoder {/*** 初始化HmacMD5密钥* * @return* @throws Exception*/public static byte[] initHmacMD5Key() throws Exception {// 初始化KeyGeneratorKeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");// 产生秘密密钥SecretKey secretKey = keyGenerator.generateKey();// 获得密钥return secretKey.getEncoded();}/*** HmacMD5加密* * @param data*            待加密数据* @param key*            密钥* @return byte[] 消息摘要* * @throws Exception*/public static byte[] encodeHmacMD5(byte[] data, byte[] key) throws Exception {// 还原密钥SecretKey secretKey = new SecretKeySpec(key, "HmacMD5");// 实例化Mac "SslMacMD5"Mac mac = Mac.getInstance("SslMacMD5");// secretKey.getAlgorithm());// 初始化Macmac.init(secretKey);// 执行消息摘要return mac.doFinal(data);}/*** 初始化HmacSHA1密钥* * @return* @throws Exception*/public static byte[] initHmacSHAKey() throws Exception {// 初始化KeyGeneratorKeyGenerator keyGenerator = KeyGenerator.getInstance("HMacTiger");// 产生秘密密钥SecretKey secretKey = keyGenerator.generateKey();// 获得密钥return secretKey.getEncoded();}/*** HmacSHA1加密* * @param data*            待加密数据* @param key*            密钥* @return byte[] 消息摘要* * @throws Exception*/public static byte[] encodeHmacSHA(byte[] data, byte[] key) throws Exception {// 还原密钥SecretKey secretKey = new SecretKeySpec(key, "HMacTiger");// 实例化Mac SslMacMD5Mac mac = Mac.getInstance("SslMacMD5");// secretKey.getAlgorithm());// 初始化Macmac.init(secretKey);// 执行消息摘要return mac.doFinal(data);}// // 根据所安装的 JCE 仲裁策略文件,返回指定转换的最大密钥长度。// public final static int getMaxAllowedKeyLength(String transformation)/*** 初始化HmacSHA256密钥* * @return* @throws Exception*/public static byte[] initHmacSHA256Key() throws Exception {// 初始化KeyGeneratorKeyGenerator keyGenerator = KeyGenerator.getInstance("HmacSHA256");// 产生秘密密钥SecretKey secretKey = keyGenerator.generateKey();// 获得密钥return secretKey.getEncoded();}/*** HmacSHA256加密* * @param data*            待加密数据* @param key*            密钥* @return byte[] 消息摘要* * @throws Exception*/public static byte[] encodeHmacSHA256(byte[] data, byte[] key) throws Exception {// 还原密钥SecretKey secretKey = new SecretKeySpec(key, "HmacSHA256");// 实例化MacMac mac = Mac.getInstance(secretKey.getAlgorithm());// 初始化Macmac.init(secretKey);// 执行消息摘要return mac.doFinal(data);}/*** 初始化HmacSHA384密钥* * @return* @throws Exception*/public static byte[] initHmacSHA384Key() throws Exception {// 初始化KeyGeneratorKeyGenerator keyGenerator = KeyGenerator.getInstance("HmacSHA384");// 产生秘密密钥SecretKey secretKey = keyGenerator.generateKey();// 获得密钥return secretKey.getEncoded();}/*** HmacSHA384加密* * @param data*            待加密数据* @param key*            密钥* @return byte[] 消息摘要* * @throws Exception*/public static byte[] encodeHmacSHA384(byte[] data, byte[] key) throws Exception {// 还原密钥SecretKey secretKey = new SecretKeySpec(key, "HmacSHA384");// 实例化MacMac mac = Mac.getInstance(secretKey.getAlgorithm());// 初始化Macmac.init(secretKey);// 执行消息摘要return mac.doFinal(data);}/*** 初始化HmacSHA512密钥* * @return* @throws Exception*/public static byte[] initHmacSHA512Key() throws Exception {// 初始化KeyGeneratorKeyGenerator keyGenerator = KeyGenerator.getInstance("HmacSHA512");// 产生秘密密钥SecretKey secretKey = keyGenerator.generateKey();// 获得密钥return secretKey.getEncoded();}/*** HmacSHA512加密* * @param data*            待加密数据* @param key*            密钥* @return byte[] 消息摘要* * @throws Exception*/public static byte[] encodeHmacSHA512(byte[] data, byte[] key) throws Exception {// 还原密钥SecretKey secretKey = new SecretKeySpec(key, "HmacSHA512");// 实例化MacMac mac = Mac.getInstance(secretKey.getAlgorithm());// 初始化Macmac.init(secretKey);// 执行消息摘要return mac.doFinal(data);}
}

3、对称加密

1)、定义

对称加密就是加密与解密拥有相同的密钥,根据加密方式可分为密码和分组密码。分组密码工作模式可分为ECB、CBC、CFB、OFB和CTR等,密钥长度决定了加密算法的安全性。常见的加密算法有DES或3DES、AES和RC系列算法,除此之外,还有Blowfish、Twofish、Serpent、IDEA和PBE等。

2)、DES

DES(Data Encryption Standard)数据加密标准,其衍生算法有DESede(3DES),由于安全性的原因AES逐步替代DES。

  • 示例
import java.security.Key;
import java.security.SecureRandom;import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;/*** @author alan 2018年11月16日*/
public class DESCoder {/*** 密钥算法 <br>* Java 6 只支持56bit密钥 <br>* Bouncy Castle 支持64bit密钥*/public static final String KEY_ALGORITHM = "DES";/*** 加密/解密算法 / 工作模式 / 填充方式*/public static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5PADDING";/*** 转换密钥* * @param key*            二进制密钥* @return Key 密钥* @throws Exception*/private static Key toKey(byte[] key) throws Exception {// 实例化DES密钥材料DESKeySpec dks = new DESKeySpec(key);// 实例化秘密密钥工厂SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);// 生成秘密密钥SecretKey secretKey = keyFactory.generateSecret(dks);return secretKey;}/*** 解密* * @param data*            待解密数据* @param key*            密钥* @return byte[] 解密数据* @throws Exception*/public static byte[] decrypt(byte[] data, byte[] key) throws Exception {// 还原密钥Key k = toKey(key);// 实例化Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);// 初始化,设置为解密模式cipher.init(Cipher.DECRYPT_MODE, k);// 执行操作return cipher.doFinal(data);}/*** 加密* * @param data*            待加密数据* @param key*            密钥* @return byte[] 加密数据* @throws Exception*/public static byte[] encrypt(byte[] data, byte[] key) throws Exception {// 还原密钥Key k = toKey(key);// 实例化Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);// 初始化,设置为加密模式cipher.init(Cipher.ENCRYPT_MODE, k);// 执行操作return cipher.doFinal(data);}/*** 生成密钥 <br>* Java 6 只支持56bit密钥 <br>* Bouncy Castle 支持64bit密钥 <br>* * @return byte[] 二进制密钥* @throws Exception*/public static byte[] initKey() throws Exception {/** 实例化密钥生成器* * 若要使用64bit密钥注意替换 将下述代码中的KeyGenerator.getInstance(CIPHER_ALGORITHM);* 替换为KeyGenerator.getInstance(CIPHER_ALGORITHM, "BC");*/KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);/** 初始化密钥生成器 若要使用64bit密钥注意替换 将下述代码kg.init(56); 替换为kg.init(64);*/kg.init(56, new SecureRandom());// 生成秘密密钥SecretKey secretKey = kg.generateKey();// 获得密钥的二进制编码形式return secretKey.getEncoded();}
}

3)、AES

AES(Advanced Encryption Standard)高级数据加密标准,作为DES算法的替代。AES算法具有密钥建立时间短、灵敏性好、内存需求低等优点,应用比较广泛。

  • 示例
import java.security.Key;import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;/*** @author alan 2018年11月16日*/
public class AESCoder {public static final String KEY_ALGORITHM = "AES";/*** 加密/解密算法 / 工作模式 / 填充方式 Java 6支持PKCS5Padding填充方式 Bouncy* Castle支持PKCS7Padding填充方式*/public static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";/*** 转换密钥* * @param key*            二进制密钥* @return Key 密钥* @throws Exception*/private static Key toKey(byte[] key) throws Exception {// 实例化AES密钥材料SecretKey secretKey = new SecretKeySpec(key, KEY_ALGORITHM);return secretKey;}/*** 解密* * @param data*            待解密数据* @param key*            密钥* @return byte[] 解密数据* @throws Exception*/public static byte[] decrypt(byte[] data, byte[] key) throws Exception {// 还原密钥Key k = toKey(key);/** 实例化 使用PKCS7Padding填充方式,按如下方式实现 Cipher.getInstance(CIPHER_ALGORITHM, "BC");*/Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);// 初始化,设置为解密模式cipher.init(Cipher.DECRYPT_MODE, k);// 执行操作return cipher.doFinal(data);}/*** 加密* * @param data*            待加密数据* @param key*            密钥* @return byte[] 加密数据* @throws Exception*/public static byte[] encrypt(byte[] data, byte[] key) throws Exception {// 还原密钥Key k = toKey(key);/** 实例化 使用PKCS7Padding填充方式,按如下方式实现 Cipher.getInstance(CIPHER_ALGORITHM, "BC");*/Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);// 初始化,设置为加密模式cipher.init(Cipher.ENCRYPT_MODE, k);// 执行操作return cipher.doFinal(data);}/*** 生成密钥 <br>* * @return byte[] 二进制密钥* @throws Exception*/public static byte[] initKey() throws Exception {// 实例化KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);/** AES 要求密钥长度为 128位、192位或 256位*/kg.init(256);// 生成秘密密钥SecretKey secretKey = kg.generateKey();// 获得密钥的二进制编码形式return secretKey.getEncoded();}
}

4)、IDEA

IDEA(International Data Encryption Algorithm)国际数据加密算法是一种对称分组密码,其密钥长度为128位,数据块大小为64位,目前常用的场景是邮件加密算法。

  • 示例
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.bouncycastle.jce.provider.BouncyCastleProvider;/*** * @author alan 2018年11月16日*/
public abstract class IDEACoder {public static final String KEY_ALGORITHM = "IDEA";//加密/解密算法 / 工作模式 / 填充方式public static final String CIPHER_ALGORITHM = "IDEA/ECB/PKCS5Padding";/*** 转换密钥* * @param key*            二进制密钥* @return Key 密钥* @throws Exception*/private static Key toKey(byte[] key) throws Exception {// 生成秘密密钥SecretKey secretKey = new SecretKeySpec(key, KEY_ALGORITHM);return secretKey;}/*** 解密* * @param data*            待解密数据* @param key*            密钥* @return byte[] 解密数据* @throws Exception*/public static byte[] decrypt(byte[] data, byte[] key) throws Exception {// 加入BouncyCastleProvider支持Security.addProvider(new BouncyCastleProvider());// 还原密钥Key k = toKey(key);// 实例化Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);// 初始化,设置为解密模式cipher.init(Cipher.DECRYPT_MODE, k);// 执行操作return cipher.doFinal(data);}/*** 加密* * @param data*            待加密数据* @param key*            密钥* @return byte[] 加密数据* @throws Exception*/public static byte[] encrypt(byte[] data, byte[] key) throws Exception {// 加入BouncyCastleProvider支持Security.addProvider(new BouncyCastleProvider());// 还原密钥Key k = toKey(key);// 实例化Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);// 初始化,设置为加密模式cipher.init(Cipher.ENCRYPT_MODE, k);// 执行操作return cipher.doFinal(data);}/*** 生成密钥 * * @return byte[] 二进制密钥* @throws Exception*/public static byte[] initKey() throws Exception {// 加入BouncyCastleProvider支持Security.addProvider(new BouncyCastleProvider());// 实例化KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);// 初始化kg.init(128);// 生成秘密密钥SecretKey secretKey = kg.generateKey();// 获得密钥的二进制编码形式return secretKey.getEncoded();}
}

5)、PBE

PBE(Password Based Encryption)基于密码加密算法是一种基于密码的加密算法,其特点是密码(password)由用户自己保管,采用随机数(加盐)杂凑多重加密等方法保证数据的安全性。PBE没有密钥,其密码(password)代替了密钥,为了增加密码的安全性,采用了加盐的处理方式。PBE是对称加密算法的综合性算法,常见的算法有PBEWithMD5AndDES,该算法是使用了MD5和DES构建PBE算法。

  • 示例
import java.security.Key;
import java.security.SecureRandom;import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;/*** @author alan* 2018年11月16日*/
public class PBECoder {/*** Java 6 支持以下任意一种算法* * <pre>* PBEWithMD5AndDES * PBEWithMD5AndTripleDES * PBEWithSHA1AndDESede* PBEWithSHA1AndRC2_40* </pre>*/public static final String ALGORITHM = "PBEWithMD5AndTripleDES";/*** 盐初始化<br>* 盐长度必须为8字节* * @return byte[] 盐* @throws Exception*/public static byte[] initSalt() throws Exception {SecureRandom random = new SecureRandom();return random.generateSeed(8);}/*** 转换密钥* * @param password*            密码* @return Key 密钥* @throws Exception*/private static Key toKey(String password) throws Exception {// 密钥材料转换PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());// 实例化SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);// 生成密钥SecretKey secretKey = keyFactory.generateSecret(keySpec);return secretKey;}/*** 加密* * @param data*            数据* @param password*            密码* @param salt*            盐* @return byte[] 加密数据* @throws Exception*/public static byte[] encrypt(byte[] data, String password, byte[] salt)throws Exception {// 转换密钥Key key = toKey(password);// 实例化PBE参数材料PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);// 实例化Cipher cipher = Cipher.getInstance(ALGORITHM);// 初始化cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);// 执行操作return cipher.doFinal(data);}/*** 解密* * @param data*            数据* @param password*            密码* @param salt*            盐* @return byte[] 解密数据* @throws Exception*/public static byte[] decrypt(byte[] data, String password, byte[] salt)throws Exception {// 转换密钥Key key = toKey(password);// 实例化PBE参数材料PBEParameterSpec paramSpec = new PBEParameterSpec(salt, 100);// 实例化Cipher cipher = Cipher.getInstance(ALGORITHM);// 初始化cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);// 执行操作return cipher.doFinal(data);}
}

4、非对称加密

1)、定义

非对称加密算法是加密和解密使用不同的密钥。公钥和私钥成对出现,公钥加密私钥解密,或者私钥加密公钥解密。由于其时间效率上不高,一般应用在安全性要求较高的场合。
常用的对称加密算法有两类,即基于因子分解难题的RSA和基于离散对数难题的DSA。RSA是应用最广泛的非对称加密算法,也是第一个既能用于数据加密也能用于数字签名的算法。DSA是由EIGamal算法演变而来的,用于数字签名。

2)、DH

DH(Diffie-Hellman)密钥交换算法主要是为了解决密钥交换而发展出来的。DH算法是一个密钥协商算法,仅能用于密钥分配,不能用于加密或解密。DH算法的安全性基于有限域上的离散对数难题,基于这种安全性,通过DH算法进行密钥分配,使得消息的收发双方可以安全地交换一个秘密密钥,再通过这个密钥对数据进行加密和解密处理。

  • 示例
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.SecretKeySpec;/*** @author alan 2018年11月16日*/
public class DHCoder {/*** 非对称加密密钥算法*/public static final String KEY_ALGORITHM = "DH";/*** 本地密钥算法,即对称加密密钥算法,可选DES、DESede和AES算法*/public static final String SECRET_KEY_ALGORITHM = "AES";/*** 默认密钥长度* * DH算法默认密钥长度为1024 密钥长度必须是64的倍数,其范围在512到1024位之间。*/private static final int KEY_SIZE = 512;/*** 公钥*/private static final String PUBLIC_KEY = "DHPublicKey";/*** 私钥*/private static final String PRIVATE_KEY = "DHPrivateKey";/*** 初始化甲方密钥* * @return Map 甲方密钥Map* @throws Exception*/public static Map<String, Object> initKey() throws Exception {// 实例化密钥对生成器KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);// 初始化密钥对生成器keyPairGenerator.initialize(KEY_SIZE);// 生成密钥对KeyPair keyPair = keyPairGenerator.generateKeyPair();// 甲方公钥DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();// 甲方私钥DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();// 将密钥对存储在Map中Map<String, Object> keyMap = new HashMap<String, Object>(2);keyMap.put(PUBLIC_KEY, publicKey);keyMap.put(PRIVATE_KEY, privateKey);return keyMap;}/*** 初始化乙方密钥* * @param key*            甲方公钥* @return Map 乙方密钥Map* @throws Exception*/public static Map<String, Object> initKey(byte[] key) throws Exception {// 解析甲方公钥// 转换公钥材料X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);// 实例化密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);// 产生公钥PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);// 由甲方公钥构建乙方密钥DHParameterSpec dhParamSpec = ((DHPublicKey) pubKey).getParams();// 实例化密钥对生成器KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(keyFactory.getAlgorithm());// 初始化密钥对生成器keyPairGenerator.initialize(dhParamSpec);// 产生密钥对KeyPair keyPair = keyPairGenerator.genKeyPair();// 乙方公钥DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();// 乙方私钥DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();// 将密钥对存储在Map中Map<String, Object> keyMap = new HashMap<String, Object>(2);keyMap.put(PUBLIC_KEY, publicKey);keyMap.put(PRIVATE_KEY, privateKey);return keyMap;}/*** 加密* * @param data*            待加密数据* @param key*            密钥* @return byte[] 加密数据* @throws Exception*/public static byte[] encrypt(byte[] data, byte[] key) throws Exception {// 生成本地密钥SecretKey secretKey = new SecretKeySpec(key, SECRET_KEY_ALGORITHM);// 数据加密Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE, secretKey);return cipher.doFinal(data);}/*** 解密<br>* * @param data*            待解密数据* @param key*            密钥* @return byte[] 解密数据* @throws Exception*/public static byte[] decrypt(byte[] data, byte[] key) throws Exception {// 生成本地密钥SecretKey secretKey = new SecretKeySpec(key, SECRET_KEY_ALGORITHM);// 数据解密Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE, secretKey);return cipher.doFinal(data);}/*** 构建密钥* * @param publicKey*            公钥* @param privateKey*            私钥* @return byte[] 本地密钥* @throws Exception*/public static byte[] getSecretKey(byte[] publicKey, byte[] privateKey) throws Exception {// 实例化密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);// 初始化公钥// 密钥材料转换X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);// 产生公钥PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);// 初始化私钥// 密钥材料转换PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);// 产生私钥PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);// 实例化KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory.getAlgorithm());// 初始化keyAgree.init(priKey);keyAgree.doPhase(pubKey, true);// 生成本地密钥SecretKey secretKey = keyAgree.generateSecret(SECRET_KEY_ALGORITHM);return secretKey.getEncoded();}/*** 取得私钥* * @param keyMap*            密钥Map* @return byte[] 私钥* @throws Exception*/public static byte[] getPrivateKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PRIVATE_KEY);return key.getEncoded();}/*** 取得公钥* * @param keyMap*            密钥Map* @return byte[] 公钥* @throws Exception*/public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PUBLIC_KEY);return key.getEncoded();}
}

3)、RSA

RSA是三个创建者的姓名缩写,是唯一被广泛接受并实现的通用公开加密算法,目前已经成为非对称加密的国际标准,也可以用于数据加密,也可以用于数据签名。RSA算法公钥长度远小于私钥长度,并遵循“公钥加密私钥解密”和“私钥加密公钥解密”两项加密解密原则。

  • 示例
import java.security.Key;
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 java.util.HashMap;
import java.util.Map;import javax.crypto.Cipher;/*** @author alan 2018年11月20日*/
public class RSACoder {/*** 非对称加密密钥算法*/public static final String KEY_ALGORITHM = "RSA";/*** 公钥*/private static final String PUBLIC_KEY = "RSAPublicKey";/*** 私钥*/private static final String PRIVATE_KEY = "RSAPrivateKey";/*** RSA密钥长度 默认1024位, 密钥长度必须是64的倍数, 范围在512至65536位之间。*/private static final int KEY_SIZE = 512;/*** 私钥解密* * @param data*            待解密数据* @param key*            私钥* @return byte[] 解密数据* @throws Exception*/public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception {// 取得私钥PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);// 生成私钥PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);// 对数据解密Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE, privateKey);return cipher.doFinal(data);}/*** 公钥解密* * @param data*            待解密数据* @param key*            公钥* @return byte[] 解密数据* @throws Exception*/public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception {// 取得公钥X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);// 生成公钥PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);// 对数据解密Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE, publicKey);return cipher.doFinal(data);}/*** 公钥加密* * @param data*            待加密数据* @param key*            公钥* @return byte[] 加密数据* @throws Exception*/public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {// 取得公钥X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);// 对数据加密Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE, publicKey);return cipher.doFinal(data);}/*** 私钥加密* * @param data*            待加密数据* @param key*            私钥* @return byte[] 加密数据* @throws Exception*/public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception {// 取得私钥PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);// 生成私钥PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);// 对数据加密Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE, privateKey);return cipher.doFinal(data);}/*** 取得私钥* * @param keyMap*            密钥Map* @return byte[] 私钥* @throws Exception*/public static byte[] getPrivateKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PRIVATE_KEY);return key.getEncoded();}/*** 取得公钥* * @param keyMap*            密钥Map* @return byte[] 公钥* @throws Exception*/public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PUBLIC_KEY);return key.getEncoded();}/*** 初始化密钥* * @return Map 密钥Map* @throws Exception*/public static Map<String, Object> initKey() throws Exception {// 实例化密钥对生成器KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);// 初始化密钥对生成器keyPairGen.initialize(KEY_SIZE);// 生成密钥对KeyPair keyPair = keyPairGen.generateKeyPair();// 公钥RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();// 私钥RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();// 封装密钥Map<String, Object> keyMap = new HashMap<String, Object>(2);keyMap.put(PUBLIC_KEY, publicKey);keyMap.put(PRIVATE_KEY, privateKey);return keyMap;}
}

4)、EIGamal/DSA

基于离散对数问题的算法有EIGamal和ECC,是常用的非对称加密算法,DSA(Digital Signature Algorithm)是EIGamal的一个变形。遵循“公钥加密,私钥解密”的加密解密方式。与RSA相比比较接近,但只实现了“公钥加密,私钥解密”部分。EIGamal算法的公私钥长度基本一致。
ECC(Elliptical Curve Cryptography)椭圆曲线加密算法是以椭圆曲线理论为基础实现的,通过椭圆曲线方程式的性质产生密钥,而不是采用传统的方法利用大质数的积来产生。在创建密钥时更快、更小。

  • 示例
import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.Key;
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 java.util.HashMap;
import java.util.Map;import javax.crypto.Cipher;
import javax.crypto.spec.DHParameterSpec;import org.bouncycastle.jce.provider.BouncyCastleProvider;/*** @author alan* 2018年11月20日*/
public class ElGamalCoder {/*** 非对称加密密钥算法*/public static final String KEY_ALGORITHM = "ElGamal";/*** 密钥长度* * ElGamal算法默认密钥长度为1024 密钥长度范围在160位至16384位不等。*/private static final int KEY_SIZE = 256;/*** 公钥*/private static final String PUBLIC_KEY = "ElGamalPublicKey";/*** 私钥*/private static final String PRIVATE_KEY = "ElGamalPrivateKey";/*** 用私钥解密* * @param data*            待解密数据* @param key*            私钥* @return byte[] 解密数据* @throws Exception*/public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception {// 加入BouncyCastleProvider支持Security.addProvider(new BouncyCastleProvider());// 私钥材料转换PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);// 实例化密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);// 生成私钥Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);// 对数据解密Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE, privateKey);return cipher.doFinal(data);}/*** 用公钥加密* * @param data*            待加密数据* @param key*            公钥* @return byte[] 加密数据* @throws Exception*/public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {// 加入BouncyCastleProvider支持Security.addProvider(new BouncyCastleProvider());// 公钥材料转换X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);// 实例化密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);// 生成公钥Key publicKey = keyFactory.generatePublic(x509KeySpec);// 对数据加密Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE, publicKey);return cipher.doFinal(data);}/*** 生成密钥* * @return Map 密钥Map* @throws Exception*/public static Map<String, Object> initKey() throws Exception {// 加入BouncyCastleProvider支持Security.addProvider(new BouncyCastleProvider());// 实例化算法参数生成器AlgorithmParameterGenerator apg = AlgorithmParameterGenerator.getInstance(KEY_ALGORITHM);// 初始化算法参数生成器apg.init(KEY_SIZE);// 生成算法参数AlgorithmParameters params = apg.generateParameters();// 构建参数材料DHParameterSpec elParams = (DHParameterSpec) params.getParameterSpec(DHParameterSpec.class);// 实例化密钥对儿生成器KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_ALGORITHM);// 初始化密钥对儿生成器kpg.initialize(elParams, new SecureRandom());// 生成密钥对儿KeyPair keys = kpg.genKeyPair();// 取得密钥PublicKey publicKey = keys.getPublic();PrivateKey privateKey = keys.getPrivate();// 封装密钥Map<String, Object> map = new HashMap<String, Object>(2);map.put(PUBLIC_KEY, publicKey);map.put(PRIVATE_KEY, privateKey);return map;}/*** 取得私钥* * @param keyMap*            密钥Map* @return byte[] 私钥* @throws Exception*/public static byte[] getPrivateKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PRIVATE_KEY);return key.getEncoded();}/*** 取得公钥* * @param keyMap* @return* @throws Exception*/public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PUBLIC_KEY);return key.getEncoded();}
}

三、数字签名算法介绍、应用场景和示例

1、介绍

数字签名算法是一种带有密钥的消息摘要算法,使用的是非对称加密算法与消息摘要算法的结合。
数字签名算法要求能够验证数据的完整性、数据的来源以及防抵赖。消息摘要算法是验证数据完整性的最佳算法;防抵赖靠签名来确保,也是基于消息摘要的。
数字签名算法包含签名和验证两个重要步骤,遵循“私钥签名,公钥验证”的签名验证方式。签名时需要私钥和待签名的数据;验证时需要公钥、签名值和待签名数据,其核心就是消息摘要信息,签名值与消息摘要值一样,通常以十六进制字符串来表示。简单来说先对原始数据做摘要处理,然后使用私钥对摘要值签名;验证时使用公钥验证消息的摘要值。
数字签名常用算法有RSA、DSA、ECDSA,其中RSA是基于整数因子分解问题,DSA和ECDSA则是基于离散对数问题。RSA是目前数字签名应用最广泛的算法。

2、RSA签名

1)、介绍

RSA数字签名算法与加密算法一致,统称RSA。RSA数字签名算法分为MD和SHA两个系列,MD系列主要包含MD2withRSA和MD5withRSA;SHA系列包含SHA1withRSA、SHA224withRSA、SHA256withRSA、SHA384withRSA、SHA512withRSA。

2)、示例

import java.security.Key;
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 java.util.HashMap;
import java.util.Map;/*** @author alan 2018年11月20日*/
public class RSACoder {/*** 数字签名 密钥算法*/public static final String KEY_ALGORITHM = "RSA";/*** 数字签名 签名/验证算法*/public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";/*** 公钥*/private static final String PUBLIC_KEY = "RSAPublicKey";/*** 私钥*/private static final String PRIVATE_KEY = "RSAPrivateKey";/*** RSA密钥长度 默认1024位, 密钥长度必须是64的倍数, 范围在512至65536位之间。*/private static final int KEY_SIZE = 512;/*** 签名* * @param data*            待签名数据* @param privateKey*            私钥* @return byte[] 数字签名* @throws Exception*/public static byte[] sign(byte[] data, byte[] privateKey) throws Exception {// 转换私钥材料PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);// 实例化密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);// 取私钥匙对象PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);// 实例化SignatureSignature signature = Signature.getInstance(SIGNATURE_ALGORITHM);// 初始化Signaturesignature.initSign(priKey);// 更新signature.update(data);// 签名return signature.sign();}/*** 校验* * @param data*            待校验数据* @param publicKey*            公钥* @param sign*            数字签名* * @return boolean 校验成功返回true 失败返回false* @throws Exception* */public static boolean verify(byte[] data, byte[] publicKey, byte[] sign) throws Exception {// 转换公钥材料X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);// 实例化密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);// 生成公钥PublicKey pubKey = keyFactory.generatePublic(keySpec);// 实例化SignatureSignature signature = Signature.getInstance(SIGNATURE_ALGORITHM);// 初始化Signaturesignature.initVerify(pubKey);// 更新signature.update(data);// 验证return signature.verify(sign);}/*** 取得私钥* * @param keyMap* @return* @throws Exception*/public static byte[] getPrivateKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PRIVATE_KEY);return key.getEncoded();}/*** 取得公钥* * @param keyMap* @return* @throws Exception*/public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PUBLIC_KEY);return key.getEncoded();}/*** 初始化密钥* * @return Map 密钥对儿 Map* @throws Exception*/public static Map<String, Object> initKey() throws Exception {// 实例化密钥对儿生成器KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);// 初始化密钥对儿生成器keyPairGen.initialize(KEY_SIZE);// 生成密钥对儿KeyPair keyPair = keyPairGen.generateKeyPair();// 公钥RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();// 私钥RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();// 封装密钥Map<String, Object> keyMap = new HashMap<String, Object>(2);keyMap.put(PUBLIC_KEY, publicKey);keyMap.put(PRIVATE_KEY, privateKey);return keyMap;}
}

2、DSA签名

1)、介绍

DSA本质上是EIGamal数字签名算法,与RSA算法是数字证书中两种常见的算法,与RSA不同的是DSA仅仅包含数字签名算法,使用DSA算法的数字证书无法进行加密通信,而RSA算法即可加密也可签名。
DSA算法签名长度与密钥长度无关。

2)、示例

import java.security.Key;
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.Signature;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;/*** @author alan 2018年11月20日*/
public class DSACoder {/*** 数字签名密钥算法*/public static final String ALGORITHM = "DSA";/*** 数字签名 签名/验证算法*/public static final String SIGNATURE_ALGORITHM = "SHA1withDSA";/*** 公钥*/private static final String PUBLIC_KEY = "DSAPublicKey";/*** 私钥*/private static final String PRIVATE_KEY = "DSAPrivateKey";/*** DSA密钥长度 默认1024位, 密钥长度必须是64的倍数, 范围在512至1024位之间(含)*/private static final int KEY_SIZE = 1024;/*** 签名* * @param data*            待签名数据* @param privateKey*            私钥* @return byte[] 数字签名* @throws Exception*/public static byte[] sign(byte[] data, byte[] privateKey) throws Exception {// 还原私钥// 转换私钥材料PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);// 实例化密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);// 生成私钥对象PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);// 实例化SignatureSignature signature = Signature.getInstance(SIGNATURE_ALGORITHM);// 初始化Signaturesignature.initSign(priKey);// 更新signature.update(data);// 签名return signature.sign();}/*** 校验* * @param data*            待校验数据* @param publicKey*            公钥* @param sign*            数字签名* * @return boolean 校验成功返回true 失败返回false* @throws Exception* */public static boolean verify(byte[] data, byte[] publicKey, byte[] sign) throws Exception {// 还原公钥// 转换公钥材料X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);// 实例化密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);// 取公钥匙对象PublicKey pubKey = keyFactory.generatePublic(keySpec);// 实例话SignatureSignature signature = Signature.getInstance(SIGNATURE_ALGORITHM);// 初始化Signaturesignature.initVerify(pubKey);// 更新signature.update(data);// 验证return signature.verify(sign);}/*** 生成密钥* * @return 密钥对象* @throws Exception*/public static Map<String, Object> initKey() throws Exception {// 初始化密钥对儿生成器KeyPairGenerator keygen = KeyPairGenerator.getInstance(ALGORITHM);// 实例化密钥对儿生成器keygen.initialize(KEY_SIZE, new SecureRandom());// 实例化密钥对儿KeyPair keys = keygen.genKeyPair();DSAPublicKey publicKey = (DSAPublicKey) keys.getPublic();DSAPrivateKey privateKey = (DSAPrivateKey) keys.getPrivate();// 封装密钥Map<String, Object> map = new HashMap<String, Object>(2);map.put(PUBLIC_KEY, publicKey);map.put(PRIVATE_KEY, privateKey);return map;}/*** 取得私钥* * @param keyMap*            密钥Map* @return byte[] 私钥* @throws Exception*/public static byte[] getPrivateKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PRIVATE_KEY);return key.getEncoded();}/*** 取得公钥* * @param keyMap*            密钥Map* @return byte[] 公钥* @throws Exception*/public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PUBLIC_KEY);return key.getEncoded();}
}

3、ECDSA签名

1)、介绍

ECDSA相对于传统的签名算法,速度更快、强度更高、签名更短优点,其用途越来越广泛。

2)、示例

import java.math.BigInteger;
import java.security.Key;
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.Signature;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;import org.bouncycastle.jce.provider.BouncyCastleProvider;/*** @author alan 2018年11月20日*/
public class ECDSACoder {/*** 数字签名 密钥算法*/private static final String KEY_ALGORITHM = "ECDSA";/*** 数字签名 签名/验证算法* * Bouncy Castle支持以下7种算法 NONEwithECDSA RIPEMD160withECDSA SHA1withECDSA* SHA224withECDSA SHA256withECDSA SHA384withECDSA SHA512withECDSA*/private static final String SIGNATURE_ALGORITHM = "SHA512withECDSA";/*** 公钥*/private static final String PUBLIC_KEY = "ECDSAPublicKey";/*** 私钥*/private static final String PRIVATE_KEY = "ECDSAPrivateKey";/*** 初始化密钥* * @return Map 密钥Map* @throws Exception*/public static Map<String, Object> initKey() throws Exception {// 加入BouncyCastleProvider支持Security.addProvider(new BouncyCastleProvider());BigInteger p = new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839");ECFieldFp ecFieldFp = new ECFieldFp(p);BigInteger a = new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16);BigInteger b = new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16);EllipticCurve ellipticCurve = new EllipticCurve(ecFieldFp, a, b);BigInteger x = new BigInteger("110282003749548856476348533541186204577905061504881242240149511594420911");BigInteger y = new BigInteger("869078407435509378747351873793058868500210384946040694651368759217025454");ECPoint g = new ECPoint(x, y);BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307");ECParameterSpec ecParameterSpec = new ECParameterSpec(ellipticCurve, g, n, 1);// 实例化密钥对儿生成器KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_ALGORITHM);// 初始化密钥对儿生成器kpg.initialize(ecParameterSpec, new SecureRandom());// 生成密钥对儿KeyPair keypair = kpg.generateKeyPair();ECPublicKey publicKey = (ECPublicKey) keypair.getPublic();ECPrivateKey privateKey = (ECPrivateKey) keypair.getPrivate();// 封装密钥Map<String, Object> map = new HashMap<String, Object>(2);map.put(PUBLIC_KEY, publicKey);map.put(PRIVATE_KEY, privateKey);return map;}/*** 取得私钥* * @param keyMap*            密钥Map* @return byte[] 私钥* @throws Exception*/public static byte[] getPrivateKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PRIVATE_KEY);return key.getEncoded();}/*** 取得公钥* * @param keyMap*            密钥Map* @return byte[] 公钥* @throws Exception*/public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception {Key key = (Key) keyMap.get(PUBLIC_KEY);return key.getEncoded();}/*** 签名* * @param data*            待签名数据* @param privateKey*            私钥* @return byte[] 数字签名* @throws Exception*/public static byte[] sign(byte[] data, byte[] privateKey) throws Exception {// 加入BouncyCastleProvider支持Security.addProvider(new BouncyCastleProvider());// 转换私钥材料PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);// 实例化密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);// 取私钥匙对象PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);// 实例化SignatureSignature signature = Signature.getInstance(SIGNATURE_ALGORITHM);// 初始化Signaturesignature.initSign(priKey);// 更新signature.update(data);// 签名return signature.sign();}/*** 校验* * @param data*            待校验数据* @param publicKey*            公钥* @param sign*            数字签名* @return boolean 校验成功返回true 失败返回false* @throws Exception* */public static boolean verify(byte[] data, byte[] publicKey, byte[] sign) throws Exception {// 加入BouncyCastleProvider支持Security.addProvider(new BouncyCastleProvider());// 转换公钥材料X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);// 实例化密钥工厂KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);// 生成公钥PublicKey pubKey = keyFactory.generatePublic(keySpec);// 实例化SignatureSignature signature = Signature.getInstance(SIGNATURE_ALGORITHM);// 初始化Signaturesignature.initVerify(pubKey);// 更新signature.update(data);// 验证return signature.verify(sign);}
}

四、数字证书

1、介绍

数字证书有加密解密的必要信息,包含签名算法,可用于网络数据加密解密交互、标识网络用户身份,也是加密算法与公钥的载体。
目前数字证书中最常用的非对称加密算法是RSA,与之配套的签名算法是SHA1withRSA
数字证书(Digital Certificate)也称为电子证书,用于标识网络中的用户身份,一般有数字证书颁发认证机构(Certificate Authority CA)签发,VeriSign、VeoTrust和Thawte是三大CA机构。
通过CA机构颁发的数字证书,可以对网络上传输的数据进行加密、解密、签名和验证操作,确保数据的机密性、完整性和防抵赖,同时数字证书包含的用户信息可以明确的标识用户身份,可以保证交易者的真实身份。
数字证书采用了公钥基础设施(public key infrastructure pki),使用相应的加密算法确保网络应用的安全,主要体现在如下几个方面。

  • 使用非对称加密算法对数据进行加密解密,确保数据的机密性
  • 使用数字签名算法对数据进行签名和验证,确保数据的完整性与防抵赖
  • 使用消息摘要算法对数字证书本身做摘要,确保数字证书的完整性

数字证书编码格式有多种,主要包含CER和DER。
数字证书需要符合PKI制定的ITU-T X509国际标准。

2、证书签发过程


其文字描述如下:
1、数字证书申请者生成密钥对
2、数字证书申请者将算法、公钥和证书申请者身份信息发送至CA
3、CA核实用户身份
4、CA颁发数字证书给申请者

3、示例

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;import javax.crypto.Cipher;/*** @author alan 2018年11月21日*/
public class CertificateCoder {/*** 类型证书X509*/public static final String CERT_TYPE = "X.509";/*** 由KeyStore获得私钥* * @param keyStorePath 密钥库路径* @param alias        别名* @param password     密码* @return PrivateKey 私钥* @throws Exception*/private static PrivateKey getPrivateKeyByKeyStore(String keyStorePath, String alias, String password) throws Exception {// 获得密钥库KeyStore ks = getKeyStore(keyStorePath, password);// 获得私钥return (PrivateKey) ks.getKey(alias, password.toCharArray());}/*** 由Certificate获得公钥* * @param certificatePath 证书路径* @return PublicKey 公钥* @throws Exception*/private static PublicKey getPublicKeyByCertificate(String certificatePath) throws Exception {// 获得证书Certificate certificate = getCertificate(certificatePath);// 获得公钥return certificate.getPublicKey();}/*** 获得Certificate* * @param certificatePath 证书路径* @return Certificate 证书* @throws Exception*/private static Certificate getCertificate(String certificatePath) throws Exception {// 实例化证书工厂CertificateFactory certificateFactory = CertificateFactory.getInstance(CERT_TYPE);// 取得证书文件流FileInputStream in = new FileInputStream(certificatePath);// 生成证书Certificate certificate = certificateFactory.generateCertificate(in);// 关闭证书文件流in.close();return certificate;}/*** 获得Certificate* * @param keyStorePath 密钥库路径* @param alias        别名* @param password     密码* @return Certificate 证书* @throws Exception*/private static Certificate getCertificate(String keyStorePath, String alias, String password) throws Exception {// 获得密钥库KeyStore ks = getKeyStore(keyStorePath, password);// 获得证书return ks.getCertificate(alias);}/*** 获得KeyStore* * @param keyStorePath 密钥库路径* @param password     密码* @return KeyStore 密钥库* @throws Exception*/private static KeyStore getKeyStore(String keyStorePath, String password) throws Exception {// 实例化密钥库KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());// 获得密钥库文件流FileInputStream is = new FileInputStream(keyStorePath);// 加载密钥库ks.load(is, password.toCharArray());// 关闭密钥库文件流is.close();return ks;}/*** 私钥加密* * @param data         待加密数据* @param keyStorePath 密钥库路径* @param alias        别名* @param password     密码* @return byte[] 加密数据* @throws Exception*/public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath, String alias, String password) throws Exception {// 取得私钥PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorePath, alias, password);// 对数据加密Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE, privateKey);return cipher.doFinal(data);}/*** 私钥解密* * @param data         待解密数据* @param keyStorePath 密钥库路径* @param alias        别名* @param password     密码* @return byte[] 解密数据* @throws Exception*/public static byte[] decryptByPrivateKey(byte[] data, String keyStorePath, String alias, String password) throws Exception {// 取得私钥PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorePath, alias, password);// 对数据加密Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE, privateKey);return cipher.doFinal(data);}/*** 公钥加密* * @param data            待加密数据* @param certificatePath 证书路径* @return byte[] 加密数据* @throws Exception*/public static byte[] encryptByPublicKey(byte[] data, String certificatePath) throws Exception {// 取得公钥PublicKey publicKey = getPublicKeyByCertificate(certificatePath);// 对数据加密Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE, publicKey);return cipher.doFinal(data);}/*** 公钥解密* * @param data            待解密数据* @param certificatePath 证书路径* @return byte[] 解密数据* @throws Exception*/public static byte[] decryptByPublicKey(byte[] data, String certificatePath) throws Exception {// 取得公钥PublicKey publicKey = getPublicKeyByCertificate(certificatePath);// 对数据加密Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE, publicKey);return cipher.doFinal(data);}/*** 签名* * @param keyStorePath 密钥库路径* @param alias        别名* @param password     密码* @return byte[] 签名* @throws Exception*/public static byte[] sign(byte[] sign, String keyStorePath, String alias, String password) throws Exception {// 获得证书X509Certificate x509Certificate = (X509Certificate) getCertificate(keyStorePath, alias, password);// 构建签名,由证书指定签名算法Signature signature = Signature.getInstance(x509Certificate.getSigAlgName());// 获取私钥PrivateKey privateKey = getPrivateKeyByKeyStore(keyStorePath, alias, password);// 初始化签名,由私钥构建signature.initSign(privateKey);signature.update(sign);return signature.sign();}/*** 验证签名* * @param data            数据* @param sign            签名* @param certificatePath 证书路径* @return boolean 验证通过为真* @throws Exception*/public static boolean verify(byte[] data, byte[] sign, String certificatePath) throws Exception {// 获得证书X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);// 由证书构建签名Signature signature = Signature.getInstance(x509Certificate.getSigAlgName());// 由证书初始化签名,实际上是使用了证书中的公钥signature.initVerify(x509Certificate);signature.update(data);return signature.verify(sign);}}

以上,简单的介绍了数据安全的概念、加密解密常见的算法、数字签名介绍、数字证书的介绍及相关示例,接下来会有针对每个具体应用详细介绍。

1、【java数据安全】数据安全之加密解密(base64、MD、SHA、DES、AES、IDEA、PBE、DH、RSA、EIGamal)、数字签名(DSA、ECDSA)和数字证书介绍、应用示例详细介绍相关推荐

  1. 3、【java数据安全】对称加密的5种(DES/3DES、AES、IDEA、PBE)常见算法的使用示例

    java数据安全 系列文章 1.[java数据安全]数据安全之加密解密(base64.MD.SHA.DES.AES.IDEA.PBE.DH.RSA.EIGamal).数字签名(DSA.ECDSA)和数 ...

  2. java之php、Android、JAVA、C# 3DES加密解密

    异常如下 1.javax.crypto.BadPaddingException: Given final block not properly padded 1)要确认下是否加密和解密都是使用相同的填 ...

  3. java和c 的rsa加密算法_RSA算法签名技术Java与C++统一(加密解密结果一样)

    RSA算法签名技术Java与C++统一 (加密解密结果一样) 源代码下载地址:http://www.doczj.com/doc/64f44a94a0116c175f0e484d.html/produc ...

  4. python 加密解密 rc4_python实现rc4加密解密,base64输出

    这里将告诉您python实现rc4加密解密,base64输出,具体实现方法:from Crypto.Cipher import ARC4 as rc4cipher import base64 def ...

  5. AES加密解密SHA1、SHA加密MD5加密

    AES加密解密 SHA1.SHA加密 MD5加密 二话不说马上附上代码: package com.luo.util; import java.io.UnsupportedEncodingExcepti ...

  6. java中完成md5加密解密_java实现md5加密解密 notNET中加密和解密的实现方法

    java实现md5加密解密 notNET中加密和解密的实现方法 亦或是旅途风光 7-14 1918℃ 22 [ ee21.cn - ASP.NET ] .NET将原来独立的API和SDK合并到一个框架 ...

  7. java 字符串 加密_如何用JAVA实现字符串简单加密解密?

    展开全部 java加密字符串可以使用des加密算法62616964757a686964616fe4b893e5b19e31333363376462,实例如下: package test; import ...

  8. delphi7aes加密解密与java互转_Java 加密/解密Excel

    概述 设置excel文件保护时,通常可选择对整个工作簿进行加密保护,打开文件时需要输入密码:或者对指定工作表进行加密,即设置表格内容只读,无法对工作表进行编辑.另外,也可以对工作表特定区域设置保护,即 ...

  9. java des加密解密_Java实现的DES加密解密工具类实例

    本文实例讲述了Java实现的DES加密解密工具类.分享给大家供大家参考,具体如下: 一个工具类,很常用,不做深入研究了,那来可直接用 DesUtil.java package lsy; import ...

最新文章

  1. Caffe源码中各种依赖库的作用及简单使用
  2. 清华 NLP 团队推荐:必读的77篇机器阅读理解论文
  3. java resume过时方法_学点开发|关于Java多线程用法解析
  4. 下列哪个适合做链栈_很多朋友在问:多层实木生态板和颗粒板哪个更适合做衣柜呢?...
  5. IOS pushViewController如何去隐藏tabbar
  6. python 多线程并发怎么还是顺序执行_python thread 并发且顺序运行示例
  7. 谷歌浏览器检查更新时出错:无法启动更新检查(错误代码为 3: 0x80080005 -- system level)
  8. 收藏 | 从头训练深度监督目标检测
  9. git 添加用户名和邮箱_Git实用教程(二) | Git简介及安装详解
  10. java中异常的定义_java中异常的理解
  11. android camera 废弃,在Ubuntu系统基于ROS使用废旧Android手机摄像头搭建监控设备
  12. sql语句中having的用法
  13. 单机如何修改服务器,修改dnf单机服务器地址
  14. 人行发布2018年度银行科技发展获奖名单
  15. 符号-$,美元符号$在不同语言代码中的解释与应用
  16. 施努卡:机器视觉公司排名(机器人视觉系统)
  17. Obsidian看板指北
  18. h5 和 微信小程序添加emoji表情处理
  19. 从补天白帽大会看网络世界那些“挖洞”的人
  20. 笔试面试经历----上海爱立信

热门文章

  1. ISO9001体系认证办理需要多长时间
  2. Stripe支付流程简要描述
  3. php文本框的属性,在PHP中,为文本框设置“name”属性的方法是() 答案:为不同文本框表单元素分别设置不同的“name”属性值...
  4. 朴素贝叶斯算法的推导与实践
  5. 以前的越南人为什么用汉字来写家谱?放弃汉语造成了什么影响?
  6. Docker下搭建Redis分片集群
  7. 关于毕业论文的致谢,我真想这么写……
  8. 免费的 Auto CAD DWG文件查看软件 U盘携带好方便 9.5 MB
  9. linux下搭建FastDFS文件服务器
  10. 深入理解Java虚拟机——虚拟机堆转储快照分析工具(jhat)