本文转载自微信公众号「潜行前行」,作者cscw。转载本文请联系潜行前行公众号。
前言
和前端进行数据交互时或者和第三方商家对接时,需要对隐私数据进行加密。单向加密,对称加密,非对称加密,其对应的算法也各式各样。java提供了统一的框架来规范(java.security)安全加密这类API。下面将一一介绍
1 加密算法概念及分类
常用的加密算法类型有三种,如下:
2 秘钥生成
对称加密密钥的生成
KeyGenerator用于生成对称秘钥(可逆加密),或者一个密码性秘钥
支持算法:AES、ARCFOUR、DES、DESede、HmacMD5、HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512、RC2
- public static final KeyGenerator getInstance(String algorithm, String provider)
- public static final KeyGenerator getInstance(String algorithm)
- public final void init(int keysize)
- public final void init(int keysize, SecureRandom random)
- public final void init(SecureRandom random)
- public final void init(AlgorithmParameterSpec params, SecureRandom random)
- public final SecretKey generateKey()
示例
- public static void main(String[] args) throws Exception {
- SecretKey secretKey = generatorDesKey();
- System.out.println(secretKey);
- }
- public static SecretKey generatorDesKey() throws NoSuchAlgorithmException {
- KeyGenerator keyGen = KeyGenerator.getInstance("DES");
- SecureRandom random = new SecureRandom();
- random.nextBytes(new byte[128]);
- keyGen.init(56,random);
- SecretKey key = keyGen.generateKey();
- return key;
- }
- ------------输出结果------------------
- com.sun.crypto.provider.DESKey@185c3
非对称加密秘钥的生成
- //KeyPairGenerator.java
- public static KeyPairGenerator getInstance(String algorithm)
- public static KeyPairGenerator getInstance(String algorithm, String provider)
- public void initialize(int keysize, SecureRandom random)
- public void initialize(AlgorithmParameterSpec params, SecureRandom random)
- public final KeyPair genKeyPair()
- //KeyPair.java
- public PublicKey getPublic()
- public PrivateKey getPrivate()
示例
- public static void main(String[] args) throws Exception {
- KeyPair keyPair = generatorRsaKey();
- System.out.println(keyPair);
- }
- public static KeyPair generatorRsaKey() throws Exception {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
- SecureRandom random = new SecureRandom();
- random.nextBytes(new byte[516]);
- keyGen.initialize(516,random);
- KeyPair keyPair = keyGen.genKeyPair();
- System.out.println(keyPair.getPrivate());
- System.out.println(keyPair.getPublic());
- return keyPair;
- }
输出结果
- SunRsaSign RSA private CRT key, 516 bits
- params: null
- modulus: 126519853979546358862851378153247782379894323767375778571361894186790679401365500006956495592162216057219204240578435837612184688685910973224797092901015673
- private exponent: 84346569319697572575234252102165188253262882511583852380907929457860452934243188047935652497010382336410866699832067872276413297543254894848799721123249067
- Sun RSA public key, 516 bits
- params: null
- modulus: 126519853979546358862851378153247782379894323767375778571361894186790679401365500006956495592162216057219204240578435837612184688685910973224797092901015673
- public exponent: 3
- java.security.KeyPair@5010be6
密钥Key和密钥规格KeySpec的相互转化
If the key is stored on a hardware device, its specification may contain information that helps identify the key on the device
KeySpec是一个接口,用来组成加密密钥的密钥内容的(透明)规范。如果密钥存储在硬件设备上,则其规范可以包含有助于标识该设备上的密钥的信息
❞KeySpec具有规范性,所以一般会根据外部参数生成KeySpec,再根据KeySpec生成对应的Key(个人理解,如有高见,请说出你的见解)。SecretKeyFactory、KeyFactory的作用就是转换Key与KeySpec
SecretKeyFactory:用于对称加密的密钥和密钥规格之间的转换,配合KeyGenerator使用
支持算法:AES、ARCFOUR、DES、DESede、PBEWithMD5AndDES、PBEWithHmacSHA256AndAES_128、PBKDF2WithHmacSHA256
- public static final SecretKeyFactory getInstance(String algorithm)
- public static final SecretKeyFactory getInstance(String algorithm, String provider)
- public final SecretKey translateKey(SecretKey key)
- public final SecretKey generateSecret(KeySpec keySpec)
- public final KeySpec getKeySpec(SecretKey key, Class<?> keySpec)
示例
- public static void main(String[] args) throws Exception {
- SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
- byte[] DESKey = "helloWWW".getBytes(StandardCharsets.UTF_8);// 设置密钥
- DESKeySpec keySpec = new DESKeySpec(DESKey);// 设置密钥参数
- SecretKey key = keyFactory.generateSecret(keySpec);// 得到密钥对象
- System.out.println(key);
- }
- ------------输出结果------------------
- com.sun.crypto.provider.DESKey@18e49
KeyFactory:用于非对称加密的密钥和密钥规格之间的转换,配合KeyPairGenerator使用
支持算法:DiffieHellman、DSA、RSA、RSASSA-PSS、EC
- //KeyFactory.java
- public static KeyFactory getInstance(String algorithm)
- public static KeyFactory getInstance(String algorithm, String provider)
- public final PublicKey generatePublic(KeySpec keySpec)
- public final PrivateKey generatePrivate(KeySpec keySpec)
- public final <T extends KeySpec> T getKeySpec(Key key, Class<T> keySpec)
示例
- public static void main(String[] args) throws Exception {
- //生成RSA秘钥对;generatorRsaKey是上面示例提供的函数
- KeyPair keyPair = generatorRsaKey();
- System.out.println(keyPair);
- //PublicKey转KeySpec;KeySpec再转PublicKey
- X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(keyPair.getPublic().getEncoded());
- KeyFactory keyFactory = KeyFactory.getInstance("RSA");
- PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
- System.out.println(pubKey);
- //PrivateKey转KeySpec;KeySpec再转PrivateKey
- PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(keyPair.getPrivate().getEncoded());
- PrivateKey priKey = keyFactory.generatePrivate(priKeySpec);
- System.out.println(priKey);
- }
输出结果
- java.security.KeyPair@78e03bb5
- Sun RSA public key, 1024 bits
- params: null
- modulus: 94134923375030889337699664145116176095803777687781162111756914700229869014912695784710407302811615186395818803402552376808400599961548587586207216709744471870318354813036696801675648731428269930963470277811176883827680414539855481218813862408748594430021606927061565116386180650249935749556615770533203721821
- public exponent: 65537
- SunRsaSign RSA private CRT key, 1024 bits
- params: null
- modulus: 94134923375030889337699664145116176095803777687781162111756914700229869014912695784710407302811615186395818803402552376808400599961548587586207216709744471870318354813036696801675648731428269930963470277811176883827680414539855481218813862408748594430021606927061565116386180650249935749556615770533203721821
- private exponent: 67868152791098303572124282937222322055125020915630253288684471666171190487123683962152169691286583419399765605089805755591451063493647416931630849589322449230367252892862038338916192807582203337302166911147185956153147905653905702289234855039234840869874793012808454810161546053566242403672442319692325665473
3 摘要算法-MessageDigest和javax.crypto.Mac(HMAC)
- MessageDigest digest = MessageDigest.getInstance("MD5");
- System.out.println(new String(digest.digest("hello world!".getBytes())));
- System.out.println(new String(digest.digest("hello world!".getBytes())));
- ------------输出结果------------------
- 0���G?�w
- 0���G?�w
MAC的示例
- public static void main(String[] args) throws Exception {
- // 初始化HmacMD5摘要算法的密钥产生器
- KeyGenerator generator = KeyGenerator.getInstance("HmacMD5");
- // 产生密钥
- SecretKey secretKey = generator.generateKey();
- //SecretKeySpec继承于SecretKey和KeySpec,因此可直接用SecretKeySpec初始化Mac
- //SecretKey secretKey = new SecretKeySpec("password".getBytes(), "HmacMD5");
- Mac mac = Mac.getInstance("HmacMD5");
- mac.init(secretKey);
- //计算摘要
- String data = "hello world";
- byte[] result1 = mac.doFinal(data.getBytes());
- byte[] result2 = mac.doFinal(data.getBytes());
- System.out.println(new String(result1).equals(new String(result2)));
- }
- ------------输出结果------------------
- true
4 签名算法工具-Signature
- public static void main(String[] args) throws Exception {
- KeyPair keyPair = generatorRsaKey();
- Signature signature = Signature.getInstance("MD5withRSA");
- signature.initSign(keyPair.getPrivate());
- //加解密数据
- byte[] data = "hello world".getBytes();
- //数据签名
- signature.update(data);
- byte[] digest = signature.sign();
- //数据解密加验证
- signature.initVerify(keyPair.getPublic());
- signature.update(data);
- System.out.println("验证结果:"+signature.verify(digest));
- }
- ------------输出结果------------------
- 验证结果:true
5 常用加密工具类-Cipher
- public static void main(String[] args) throws Exception {
- KeyPair keyPair = generatorRsaKey();
- Cipher cipher = Cipher.getInstance("RSA");
- // 编码前设定编码方式及密钥
- cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPrivate());
- //加解密数据
- byte[] data = "hello world".getBytes();
- //数据签名
- byte[] enData = cipher.doFinal(data);
- //数据解密
- cipher.init(Cipher.DECRYPT_MODE, keyPair.getPublic());
- byte[] newData = cipher.doFinal(enData);
- System.out.println("验证结果:"+new String(newData));
- }
- ------------输出结果------------------
- 验证结果:hello world
6 Certificate-证书存储
- //certificateStream是证书的输入流
- public static PublicKey getPublicKeyByCer(InputStream certificateStream) throws Exception{
- CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
- Certificate certificate = certificateFactory.generateCertificate(certificateStream);
- return certificate.getPublicKey();
- }
7 KeyStore-密钥证书的实体类
示例
- public static void main(String[] args) throws Exception {
- InputStream certificateStream = null;
- //根据Certificate生成KeyStore
- CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
- KeyStore keyStore = KeyStore.getInstance("PKCS12");
- keyStore.load(null);
- keyStore.setCertificateEntry("certificate", certificateFactory.generateCertificate(certificateStream));
- //加载jks文件,并生成KeyStore
- KeyStore trustKeyStore = KeyStore.getInstance("jks");
- FileInputStream trustKeyStoreFile = new FileInputStream("/root/trustKeyStore.jks");
- trustKeyStore.load(trustKeyStoreFile, "password".toCharArray());
- }
8 java.https加载证书的API
一般的证书加载过程
- public static String postWithSSL(String url, String jsonBody) throws Exception {
- SSLContext sslContext = getSslContext();
- SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
- sslContext, new String[]{"TLSv1.2", "TLSv1.1", "TLSv1"}, null,
- SSLConnectionSocketFactory.getDefaultHostnameVerifier());
- RequestConfig config = RequestConfig.custom()
- .setConnectTimeout(3000)
- .setSocketTimeout(3000)
- .build();
- CloseableHttpClient client = HttpClients.custom()
- .setSSLSocketFactory(sslConnectionSocketFactory)
- .setDefaultRequestConfig(config).build();
- HttpPost httpPost = new HttpPost(url);
- //httpPost.setHeaders(headers);
- httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
- httpPost.setHeader("Accept", "application/json");
- httpPost.setEntity(new StringEntity(jsonBody, StandardCharsets.UTF_8));
- HttpResponse response = client.execute(httpPost);
- HttpEntity responseEntity = response.getEntity();
- String result = EntityUtils.toString(responseEntity, "UTF-8");
- return result;
- }
- //双向加密 SSLContext
- private static SSLContext getSslContext() throws Exception {
- //自身私钥
- KeyStore identityKeyStore = KeyStore.getInstance("jks");
- FileInputStream identityKeyStoreFile = new FileInputStream("/root/myServer.jks");
- identityKeyStore.load(identityKeyStoreFile, "password1".toCharArray());
- //服务端信任证书
- KeyStore trustKeyStore = KeyStore.getInstance("jks");
- FileInputStream trustKeyStoreFile = new FileInputStream("/root/trustKeyStore.jks");
- trustKeyStore.load(trustKeyStoreFile, "password".toCharArray());
- //构建SSLContexts
- return SSLContexts.custom()
- .loadKeyMaterial(identityKeyStore, "password1".toCharArray()) // load identity keystore
- .loadTrustMaterial(trustKeyStore, null) // load trust keystore
- .build();
- }
- //双向加密 SSLContext 方式二
- private static SSLContext getSslContext2() throws Exception{
- //自身私钥
- KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- KeyStore keystore = KeyStore.getInstance("jks");
- keystore.load(new FileInputStream(new File("/root/myServer.jks")), "password".toCharArray());
- keyFactory.init(keystore, "password".toCharArray());
- KeyManager[] keyManagers = keyFactory.getKeyManagers();
- //服务端信任证书
- TrustManagerFactory trustFactory = TrustManagerFactory.getInstance("SunX509");
- KeyStore tsStore = KeyStore.getInstance("jks");
- tsStore.load(new FileInputStream(new File("/root/trustKeyStore.jks")), "password".toCharArray());
- trustFactory.init(tsStore);
- TrustManager[] trustManagers = trustFactory.getTrustManagers();
- //初始化SSLContext
- SSLContext sslContext = SSLContext.getInstance("TLS");
- sslContext.init(keyManagers, trustManagers, null);
- return sslContext;
- }
欢迎指正文中错误
参考文章
简介 本文操作介绍使用Linux操作系统的HECS(云耀云服务器)安装宝塔面板。宝塔...
12月4日,2020中国信息通信大会在四川成都开幕,数字基建赋能信息消费专题会议同...
TOP云 (west.cn)3月25日消息,为解决米友批量续费的高额成本问题,TOP云一直在...
TOP云 1月13日讯,不知是受股市影响还是怎么着,最近 域名 圈似乎达成了广泛的共...
客户简介 帝国金融集团成立于香港,是一家提供全方位投资理财的金融服务平台。帝...
虚拟主机 能装java吗?Java项目可以使用虚拟主机,但要选择专门的 Java主机 。在...
创建专线网关并完成专用通道建设后,即可在控制台配置私有网络的路由表,将需要...
来源 | 阿里巴巴云原生公众号 阿里巴巴开源的混沌工程项目 ChaosBlade 通过 CNCF...
大数据领域发展20年的变与不变 1.1 概述 大数据领域从本世纪初发展到现在,已经...
本文转载自微信公众号「程序员工具集」,作者狐狸。转载本文请联系程序员工具集...