page contents

java.security框架之签名、加密、摘要及证书教程

本文讲述了Java .security框架之签名、加密、摘要及证书教程!具有很好的参考价值,希望对大家有所帮助。一起跟随六星小编过来看看吧,具体如下:

attachments-2023-07-pM7V6gg664bb2fa031c71.png

本文讲述了Java .security框架之签名、加密、摘要及证书教程!具有很好的参考价值,希望对大家有所帮助。一起跟随六星小编过来看看吧,具体如下:

和前端进行数据交互时或者和第三方商家对接时,需要对隐私数据进行加密。单向加密,对称加密,非对称加密,其对应的算法也各式各样。java提供了统一的框架来规范(java.security)安全加密这类API。下面将一一介绍

加密算法概念及分类

秘钥生成

摘要算法工具-MessageDigest

签名算法工具-Signature

常用加密工具类-Cipher

Certificate-证书的保存

KeyStore-密钥证书的实体类

https证书加载

1 加密算法概念及分类

常用的加密算法类型有三种,如下:


单向加密:也就是不可逆的加密,例如MD5,SHA,HMAC

对称加密:也就是加密方和解密方利用同一个秘钥对数据进行加密和解密,例如DES,PBE等等

非对称加密:非对称加密分为公钥和秘钥,二者是非对称的,例如用私钥加密的内容需要使用公钥来解密,使用公钥加密的内容需要用私钥来解密,DSA,RSA

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用于生成非对称加密算法的密钥对KeyPair,KeyPair会包括一个公钥和私钥

支持算法:DiffieHellman、DSA、RSA、RSASSA-PSS、EC

//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)

单向加密是不可逆的,MD5、SHA、MAC都是属于单向加密算法的一种,也称之为摘要算法

MD5、SHA它们会根据明文用哈希算法计算一个固定长度的摘要(哈希值),然后把明文和摘要发送给接收者,接收者根据同样的算法计算出摘要,对比两个摘要是否一样即可验证明文的正确性,它的应用场景是:防止篡改和校验数据

MD5、SHA等算法是开源的,容易被试探出来。有没有更安全的摘要算法呢?HMAC-带密钥(密码)的hash函数,用一个密钥和一个明文消息作为输入,生成一个消息摘要。密钥一般使用KeyGenerator创建,相当于一个密码值,其被试探出的概率小

MessageDigest支持的算法:MD2、MD5、SHA-1、SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256

javax.crypto.Mac支持的算法:HmacMD5、HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512、PBEWithHmacSHA1

MD5的示例

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

签名算法其实也是加密算法,它加密后的数据具有唯一标识性,就像一个人的签名能代表一个人身份。签名一般是指用非对称加密算法的私钥来加密明文的过程,生成的密文可以被持有公钥的人识别解密,只要你的公钥是准确对应无误的,就能保证你解密的数据是来自持有私钥的一方

如何保证公钥是正确无误,没被篡改的?1:一对一给你,2:获取公钥后通过权威机构认证,相关过程可以看下之前写的一篇文章网络篇:朋友面试之https认证加密过程[1]

支持算法:NONEwithRSA、MD2withRSA、MD5withRSA、SHA512/224withRSA、SHA512/256withRSA、RSASSA-PSS、NONEwithDSA、SHA512withDSA、NONEwithECDSA、SHA512withECDSA、MD5withRSAandMGF1(太多了,选择列举几个)

Signature.API示例,配合KeyPairGenerator使用

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

用于加密/解密数据。支持各种类型的算法:对称加密(例如AES),非对称加密(例如RSA)

支持算法:AES、AESWrap、ARCFOUR、Blowfish、DES、DESede、DESedeWrap、ECIES、RSA(太多了,选择列举几个)

示例

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-证书存储

CertificateFactory:用于创建公钥证书(Certificate)和证书吊销列表(CRL)

Certificate及其子类X509Certificate

CertPath和CertPathBuilder:用于构建证书链(也称为证书路径)

CertPathValidator:用于验证证书链

CRL:证书吊销列表

CertStore:用于存储检索证书和CRL

CertificateFactory和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-密钥证书的实体类

KeyStore用于存储私钥和证书(公钥在证书Certificate里面)

公钥:是一个详细的实体的数字关联,并有意让所有想同这个实体发生信任关系的其他实体知道.公共钥匙用来检验签名;

私钥:是一些数字,私有和公共钥匙存在所有用公共钥匙加密的系统的钥匙对中.公共钥匙用来加密数据,私有钥匙用来计算签名.公钥加密的消息只能用私钥解密,私钥签名的消息只能用公钥检验签名。

示例

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

KeyManagerFactory、TrustManagerFactory => KeyManager、TrustManager => SSLContext => SSLEngine、SSLSocketFactory、SSLSocket

一般的证书加载过程

用Certificate、KeyStore生成创建KeyManagerFactory和TrustManagerFactory

KeyManagerFactory和TrustManagerFactory用来创建KeyManager和TrustManager

而KeyManager和TrustManager用来初始化SSLContext

然后使用SSLContext,创建实际实现SSL/TLS协议的对象(SSLSocketFactory、SSLSocket或者SSLEngine)

SSLSocket和SSLEngine可以直接在通信对象中使用

KeyManager和TrustManager作用:

KeyManager负责向对等端显示使用的凭证(使用的密码标准、加密算法、证书、公钥、签名等)

TrustManager负责验证从对等端收到的凭证,验证凭证有多种方式:其中之一是创建CertPath对象,并让JDK的内置公钥基础结构(PKI)框架处理验证。在内部,CertPath实现可能会创建一个Signature对象,并使用它来验证证书链中的每个签名

示例:生成SSLContext,并使用SSLContext初始化apache-httpClient

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;

}

更多相关技术内容咨询欢迎前往并持续关注六星社区了解详情。

想高效系统的学习Java编程语言,推荐大家关注一个微信公众号:Java圈子。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Java入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2023-03-2AoKIjPQ64014b4ad30a3.jpg

  • 发表于 2023-07-22 09:24
  • 阅读 ( 179 )
  • 分类:Java开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
小柒
小柒

1470 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1470 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章