java 基础---(加密与安全)

1.hash算法

package main.com.wyz.test;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
//hash算法  java8 API:https://docs.oracle.com/javase/8/docs/api/
public class HashTest {
    public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        //算法名称
        String algorithm[] ={"MD5","SHA-1","SHA-256","SHA-512"};

//        MessageDigest:  https://blog.csdn.net/hudashi/article/details/8394158
//        MessageDigest instance = MessageDigest.getInstance(algorithm[0]);
//        MessageDigest instance = MessageDigest.getInstance(algorithm[1]);
//        MessageDigest instance = MessageDigest.getInstance(algorithm[2]);
        MessageDigest instance = MessageDigest.getInstance(algorithm[3]);


        String msg1="Hello";
        String msg2 ="World";
        instance.update(msg1.getBytes(StandardCharsets.UTF_8));
        instance.update(msg2.getBytes(StandardCharsets.UTF_8));
        byte[] digest = instance.digest();
        System.out.println("算法名:"+instance.getAlgorithm() +"<====>输出的摘要长度:"+instance.getDigestLength()+"字节<====>16进制摘要值:"+new BigInteger(1,digest).toString(16));
//        算法名:MD5<====>输出的摘要长度:16字节<====>16进制摘要值:68e109f0f40ca72a15e05cc22786f8e6
//        算法名:SHA-1<====>输出的摘要长度:20字节<====>16进制摘要值:db8ac1c259eb89d4a131b253bacfca5f319d54f2
//        算法名:SHA-256<====>输出的摘要长度:32字节<====>16进制摘要值:872e4e50ce9990d8b041330c47c9ddd11bec6b503ae9386a99da8584e9bb12c4
//        算法名:SHA-512<====>输出的摘要长度:64字节<====>16进制摘要值:8ae6ae71a75d3fb2e0225deeb004faf95d816a0a58093eb4cb5a3aa0f197050d7a4dc0a2d5c6fbae5fb5b0d536a0a9e6b686369fa57a027687c3630321547596
//        注意:MD5因为输出长度较短,短时间内破解是可能的,目前已经不推荐使用。
    }
}

2.Hmac算法

package main.com.wyz.test;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

//Hmac算法 java8 API:https://docs.oracle.com/javase/8/docs/api/
public class HmacTest {
    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
        //算法名称
        String algorithm[] ={"HmacMD5"};
        //KeyGenerator此类提供(对称加密算法:AES,DES 等等)密钥生成器的功能
        // 参考:https://blog.csdn.net/kzcming/article/details/80095114
        //1.通过名称HmacMD5获取KeyGenerator实例;
        KeyGenerator keyGen = KeyGenerator.getInstance(algorithm[0]);
        //2.通过KeyGenerator创建一个SecretKey实例;
        SecretKey key = keyGen.generateKey();
        //打印随机生成的key
        byte[] skey = key.getEncoded();
        System.out.println("算法名称:"+key.getAlgorithm()+"<====>16进制的秘钥值:"+new BigInteger(1,skey).toString(16));
        //3.通过名称HmacMD5获取Mac实例
        Mac mac = Mac.getInstance(algorithm[0]);
        //4.用SecretKey初始化Mac实例;
        mac.init(key);
        //5.对Mac实例反复调用update(byte[])输入数据
        mac.update("HelloWorld".getBytes(StandardCharsets.UTF_8));
        //6.调用Mac实例的doFinal()获取最终的哈希值。
        byte[] result = mac.doFinal();
        System.out.println("算法名称:"+mac.getAlgorithm()+"<====>输出长度:"+mac.getMacLength()+"字节<====>16进制的秘钥值:"+new BigInteger(1,result).toString(16));
        System.out.println("验证前哈希值:"+Arrays.toString(result));

        //通过Hmac计算的哈希和SecretKey 进行验证
        System.out.println("<====验证=====>");
        SecretKeySpec keySpec = new SecretKeySpec(result, algorithm[0]);
        byte[] skey1 = keySpec.getEncoded();
        System.out.println("算法名称:"+keySpec.getAlgorithm()+"<====>16进制的秘钥值:"+new BigInteger(1,skey1).toString(16));

        Mac mac1 = Mac.getInstance(algorithm[0]);
        mac1.init(keySpec);
        mac1.update("HelloWorld".getBytes(StandardCharsets.UTF_8));
        byte[] bytes = mac1.doFinal();
        System.out.println("算法名称:"+mac1.getAlgorithm()+"<====>输出长度:"+mac1.getMacLength()+"字节<====>16进制的秘钥值:"+new BigInteger(1,bytes).toString(16));
        System.out.println("验证后哈希值:"+Arrays.toString(bytes));
//        算法名称:HmacMD5<====>16进制的秘钥值:396ed8fe32ab6eea619a28440393d7bb13b2ff3a6044ae1ca4a685e24f7a28e5b81d2f11557fd9984ea47d150c307ab90dbc0b6b921d465bd766c9847a431ca9
//        算法名称:HmacMD5<====>输出长度:16字节<====>16进制的秘钥值:6483704bc4d8076158c0f96cc58cbf79
//        验证前哈希值:[100, -125, 112, 75, -60, -40, 7, 97, 88, -64, -7, 108, -59, -116, -65, 121]
//<====验证=====>
//        算法名称:HmacMD5<====>16进制的秘钥值:6483704bc4d8076158c0f96cc58cbf79
//        算法名称:HmacMD5<====>输出长度:16字节<====>16进制的秘钥值:c16caa5c3265f1127a01c9be8848670f
//        验证后哈希值:[-63, 108, -86, 92, 50, 101, -15, 18, 122, 1, -55, -66, -120, 72, 103, 15]
    }
}

3.对称加密算法-ECB模式

package main.com.wyz.test;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Base64;

//对称加密算法 --ECB模式
public class SymmetricalECBTest {
    public static void main(String[] args) throws Exception {
        // 原文:
        String message = "Hello, world!";
        System.out.println("原文:Message: " + message);
        // 128位密钥 = 16 bytes Key:
        byte[] key = "1234567890abcdef".getBytes(StandardCharsets.UTF_8);
        // 加密:
        byte[] data = message.getBytes(StandardCharsets.UTF_8);
        byte[] encrypt = encrypt(key, data);
        System.out.println("加密后:Message: " + Base64.getEncoder().encodeToString(encrypt));

        //解密:
        byte[] decrypt = decrypt(key, encrypt);
        System.out.println("解密后:Message: " + new String(decrypt,StandardCharsets.UTF_8));

//        原文:Message: Hello, world!
//        加密后:Message: 2xiGROlFBhC57b7EGu5c3g==
//        解密后:Message: Hello, world!

    }
    // ECB模式加密
    //Cipher: https://www.cnblogs.com/caizhaokai/p/10944667.html
    public static byte[] encrypt(byte[] key,byte[] input) throws GeneralSecurityException  {
        //1.根据算法名称/工作模式/填充模式获取Cipher实例;
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        //2.根据算法名称初始化一个SecretKey实例,密钥必须是指定长度;
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        //3.使用SerectKey初始化Cipher实例,并设置加密或解密模式;
        cipher.init(Cipher.ENCRYPT_MODE,keySpec);//加密模式
        //4.传入明文,获得密文。
        return cipher.doFinal(input);
    }
    //ECB模式解密
    public static byte[] decrypt(byte[] key,byte[] input)  throws GeneralSecurityException{
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        cipher.init(Cipher.DECRYPT_MODE,keySpec);//解密模式
        //传入密文,获得明文。
        return cipher.doFinal(input);
    }


}

4.对称加密算法-CBC模式

package main.com.wyz.test;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Arrays;
import java.util.Base64;


//对称加密算法 CBC模式:
//ECB模式是最简单的AES加密模式,它只需要一个固定长度的密钥,固定的明文会生成固定的密文,这种一对一的加密方式会导致安全性降低,更好的方式是通过CBC模式,它需要一个随机数作为IV参数,这样对于同一份明文,每次生成的密文都不同
public class SymmetricalCBCTest {
    public static void main(String[] args) throws Exception {
        // 原文:
        String message = "Hello, world!";
        System.out.println("原文:Message: " + message);
        // 128位密钥 = 16 bytes Key:
        byte[] key = "1234567890abcdef".getBytes(StandardCharsets.UTF_8);
        // 加密:
        byte[] data = message.getBytes(StandardCharsets.UTF_8);
        byte[] encrypt = encrypt(key, data);
        System.out.println("加密后:Message: " + Base64.getEncoder().encodeToString(encrypt));

        //解密:
        byte[] decrypt = decrypt(key, encrypt);
        System.out.println("解密后:Message: " + new String(decrypt,StandardCharsets.UTF_8));

        //原文:Message: Hello, world!
        //加密时iv数组:[-100, -73, -103, -13, -22, 112, 105, -24, 82, 40, 110, -87, 12, 120, -38, 8]加密后的密文:9cQ1XTxgPinj/uYpBLBB4A==
        //合并后的iv和密文:nLeZ8+pwaehSKG6pDHjaCPXENV08YD4p4/7mKQSwQeA=
        //加密后:Message: nLeZ8+pwaehSKG6pDHjaCPXENV08YD4p4/7mKQSwQeA=
        //解密时iv:[-100, -73, -103, -13, -22, 112, 105, -24, 82, 40, 110, -87, 12, 120, -38, 8]
        //解密后的明文:Hello, world!
        //解密后:Message: Hello, world!

    }
    //CBC模式加密
    public static byte[] encrypt(byte[] key,byte[] input) throws
            GeneralSecurityException{
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        //CBC模式需要生成一个16 bytes的initialization vector:
        SecureRandom secureRandom = SecureRandom.getInstanceStrong();
        byte[] iv = secureRandom.generateSeed(16);
        System.out.printf("加密时iv数组:"+ Arrays.toString(iv));
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivSpec);
        byte[] data = cipher.doFinal(input);
        System.out.println("加密后的密文:"+Base64.getEncoder().encodeToString(data));
        //IV不需要保密,把IV和密文一起返回
        return join(iv,data);

    }
    //CBC模式解密
    public static byte[] decrypt(byte[] key,byte[] input) throws GeneralSecurityException{
        //把input分割成IV 和密文
        byte[] iv = new byte[16];
        byte[] data = new byte[input.length - 16];
        System.arraycopy(input,0,iv,0,16);
        System.arraycopy(input,16,data,0,data.length);
        System.out.println("解密时iv:"+Arrays.toString(iv));
        //解密
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        IvParameterSpec ivPesc = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE,keySpec,ivPesc);
        byte[] result = cipher.doFinal(data);
        System.out.println("解密后的明文:"+new String(result));
        return result;
    }
    //合并
    public static byte[] join(byte[] bs1,byte[] bs2){
        byte[] r = new byte[bs1.length + bs2.length];
        System.arraycopy(bs1,0,r,0,bs1.length);
        System.arraycopy(bs2,0,r,bs1.length,bs2.length);
        System.out.println("合并后的iv和密文:"+Base64.getEncoder().encodeToString(r));
        return r;
    }
}

5.对称加密算法-口令加密算法(PBE)

package main.com.wyz.test;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;

//口令加密算法
public class SymmetricalEPBETest {
    public static void main(String[] args) throws Exception {
        // 把BouncyCastle作为Provider添加到java.security:
        Security.addProvider(new BouncyCastleProvider()); todo 待引入BouncyCastle 的jar
        // 原文:
        String message = "Hello, world!";
        // 加密口令:
        String password = "hello12345";
        // 16 bytes随机Salt:
        byte[] salt = SecureRandom.getInstanceStrong().generateSeed(16);
        System.out.printf("salt: %032x\n", new BigInteger(1, salt));
        // 加密:
        byte[] data = message.getBytes("UTF-8");
        byte[] encrypted = encrypt(password, salt, data);
        System.out.println("encrypted: " + Base64.getEncoder().encodeToString(encrypted));
        // 解密:
        byte[] decrypted = decrypt(password, salt, encrypted);
        System.out.println("decrypted: " + new String(decrypted, "UTF-8"));
    }

    // 加密:
    public static byte[] encrypt(String password, byte[] salt, byte[] input) throws GeneralSecurityException {
        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
        SecretKeyFactory skeyFactory = SecretKeyFactory.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        SecretKey skey = skeyFactory.generateSecret(keySpec);
        PBEParameterSpec pbeps = new PBEParameterSpec(salt, 1000);
        Cipher cipher = Cipher.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        cipher.init(Cipher.ENCRYPT_MODE, skey, pbeps);
        return cipher.doFinal(input);
    }

    // 解密:
    public static byte[] decrypt(String password, byte[] salt, byte[] input) throws GeneralSecurityException {
        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
        SecretKeyFactory skeyFactory = SecretKeyFactory.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        SecretKey skey = skeyFactory.generateSecret(keySpec);
        PBEParameterSpec pbeps = new PBEParameterSpec(salt, 1000);
        Cipher cipher = Cipher.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        cipher.init(Cipher.DECRYPT_MODE, skey, pbeps);
        return cipher.doFinal(input);
    }
}

6.秘钥交换算法(DH算法)

package main.com.wyz.test;

import javax.crypto.KeyAgreement;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;

//密钥交换算法-DH算法没有解决中间人攻击(即甲乙双方并不能确保与自己通信的是否真的是对方)。
//DH算法解决了密钥在双方不直接传递密钥的情况下完成密钥交换,这个神奇的交换原理完全由数学理论支持。
public class DHTest {

    public static void main(String[] args) {
        //ZhangSan 和 LiSi
        Person zhangSan = new Person("ZhangSan");
        Person liSi = new Person("LiSi");
        // 各自生成KeyPair:
        zhangSan.generateKeyPair();
        liSi.generateKeyPair();
        // 双方交换各自的PublicKey:
        // zhangSan根据liSi的PublicKey生成自己的本地密钥:
        zhangSan.generateSecretKey(liSi.publicKey.getEncoded());
        // liSi根据zhangSan的PublicKey生成自己的本地密钥:
        liSi.generateSecretKey(zhangSan.publicKey.getEncoded());

        // 检查双方的本地密钥是否相同:
        System.out.println("==========检查双方的本地密钥===========");
        System.out.println("==========zhangSan:密钥===========");
        zhangSan.printKeys();
        System.out.println("==========liSi:密钥===========");
        liSi.printKeys();
        // 双方的SecretKey相同,后续通信将使用SecretKey作为密钥进行AES加解密...

//
//==========检查双方的本地密钥===========
//==========zhangSan:密钥===========
//Name: ZhangSan
//Private key: 3081d202010030819706092a864886f70d010301308189024100fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e170240678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4020201800433023100f0c6828e3547e61ce01174362fbf13045c20d70bf22069d664a9e6d844761737dabab6ab2fe1c047c049c4c196c97ad3
//Public key: 3081df30819706092a864886f70d010301308189024100fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e170240678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4020201800343000240755894bc5dc580252514d1a2aa1d59e40f310f4ee45a469aa4195fad07d8e44a61b1de52fb1fcdd86130dfc1af2ce7548ad2a1d1a30dc517d7e295d9a5e0d2e5
//Secret key: d6b903a0d4d497f95e26136b3413c181bd607ed3e316ddaf6932649b19aa0ac28968b81ec45be98346022af16c345c25b859115d26042b3138b100cc135c8024
//==========liSi:密钥===========
//Name: LiSi
//Private key: 3081d202010030819706092a864886f70d010301308189024100fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e170240678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4020201800433023100c59b19a7150617d2212f694a4018a1b8c201a14b791f342b34fb38c6f06e703a356023bd4e4814eb97adaf59e203a5df
//Public key: 3081df30819706092a864886f70d010301308189024100fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e170240678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4020201800343000240519092640b3d5a8564f7d0edf86a1a01fdc6c0a12e764ed8a8b9b85c87146f1577b4e95fd901a397e282f061fb6e0a33861b0f18f81bc6132636b866790805c2
//Secret key: d6b903a0d4d497f95e26136b3413c181bd607ed3e316ddaf6932649b19aa0ac28968b81ec45be98346022af16c345c25b859115d26042b3138b100cc135c8024
    }

    static class Person{
        public final  String name;
        public PublicKey publicKey;
        private PrivateKey privateKey;
        private byte[] secretKey;
        public Person(String name){
            this.name = name;
        }
        
        //生成本地keyPair
        public  void  generateKeyPair(){
            try {
                KeyPairGenerator kpGen = KeyPairGenerator.getInstance("DH");
                kpGen.initialize(512);
                KeyPair kp = kpGen.generateKeyPair();
                this.privateKey = kp.getPrivate();
                this.publicKey = kp.getPublic();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }

        }
        //利用传入的公钥 生成秘钥
        public void generateSecretKey(byte[] receivedPubKeyBytes){
            try {
                //从byte[]恢复PublicKey:
                X509EncodedKeySpec keySpec = new X509EncodedKeySpec(receivedPubKeyBytes);
                KeyFactory kf = KeyFactory.getInstance("DH");
                PublicKey receivedPublicKey = kf.generatePublic(keySpec);
                //生成本地秘钥
                KeyAgreement keyAgreement = KeyAgreement.getInstance("DH");
                keyAgreement.init(this.privateKey);//自己的PrivaKey
                keyAgreement.doPhase(receivedPublicKey,true);//对方的PublicKey
                //生成SecretKey
                this.secretKey = keyAgreement.generateSecret();
            } catch (GeneralSecurityException  e) {
                e.printStackTrace();
            }
        }

        public void  printKeys(){
            System.out.printf("Name: %s\n", this.name);
            System.out.printf("Private key: %x\n", new BigInteger(1, this.privateKey.getEncoded()));
            System.out.printf("Public key: %x\n", new BigInteger(1, this.publicKey.getEncoded()));
            System.out.printf("Secret key: %x\n", new BigInteger(1, this.secretKey));
        }
    }
}

7.非对称加密算法(RSA算法)

package main.com.wyz.test;

import javax.crypto.Cipher;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class RSATest {
    public static void main(String[] args) throws Exception{
        byte[] plain = "Hello,encrypt use RSA".getBytes(StandardCharsets.UTF_8);
        //创建公钥/私钥对
        Person zhangsan = new Person("zhangsan");
        //用zhangsan的公钥加密:
        byte[] pk = zhangsan.getPublicKey();
        System.out.println(String.format("public key: %x", new BigInteger(1, pk)));
        byte[] encrypt = zhangsan.encrypt(plain);
        System.out.println(String.format("encrypted: %x", new BigInteger(1, encrypt)));
        //用zhangsan的私密解密
        byte[] sk = zhangsan.getPrivateKey();
        System.out.println(String.format("private key: %x", new BigInteger(1, sk)));
        byte[] decrypt = zhangsan.decrypt(encrypt);
        System.out.println(new String(decrypt, StandardCharsets.UTF_8));

//        public key: 30819f300d06092a864886f70d010101050003818d0030818902818100a01ddd40901cbb072db865576aeb2bd58f834222ced94acb126dd7c2d94aad698d4a799d2151e1148d72eda5372bc53abf8c75c0decaca586359ebc3b8527ec770c6ac3dfee34a2df4c963b7261c6ba0237acef1202ebdcda08a83b5d2f1f553657907f6362a88789fecbb3f400c03d98ce8b23c275d8d6696f3971f8becb7ef0203010001
//        encrypted: 4d324a47047b8e1644846f60d4cfff3170a47a67b7a4a19d596a2f36d79b568da4001ff604d92968e4a115115b41bbdd1d1645095ab54b1587cb89ed5c5a06bc70c143c1ccb7a02bfcc2526b22ba368d54ebdb99fb512f8b148b424bc76bd598339ae626a3ef0d372b0378c66c9578f5e549f857bc565effb7f44a168a2b326c
//        private key: 30820277020100300d06092a864886f70d0101010500048202613082025d02010002818100a01ddd40901cbb072db865576aeb2bd58f834222ced94acb126dd7c2d94aad698d4a799d2151e1148d72eda5372bc53abf8c75c0decaca586359ebc3b8527ec770c6ac3dfee34a2df4c963b7261c6ba0237acef1202ebdcda08a83b5d2f1f553657907f6362a88789fecbb3f400c03d98ce8b23c275d8d6696f3971f8becb7ef0203010001028181008772bc0831e11c16268726b39caef495e4a19500fd1ab43ab58c56496ea7cdaacceb839578ea5b0d97daf14e222dd4daadcf948d63eb08e15caa64d75cc5ec98538ba8e1fb0464adac2397f5c5cb4eda54a3aee2cfb8dac2f71e05ed60cee357de25fa5e221e462ee15113ef9128b3a025220c6dc095ad30f9695c83634ba101024100d76acd488fd6921d87c72dca9e6ffd84c1daa00518b002b26f489558412c6e8527fe2fb0ed0bed4057cd5b15451c20cd7121333f3d41378e627f5f923147cdc7024100be480364ae7c0f61fcc6ca74ed08c2bfd369a4700ff004579e73394d8188eca842120a90a94196812b16567b85a60e98bd20713f333cda815d0a89f1fb57649902400e4ee0bdbe18117276af4b22572db718174c2f2ec77a0163dab266810b2b29581cd4ec54031ab4b27e627c774834db14ea3bbb4cab03e6edc52b12ad022af3c702404f2b9f5dd0cb858afba5aaaf23c0b567230b9d8392de06b07e18eb0ab88ec408ee149b98bd13b10f656211f1ab160094c47c2f2260ab3d2efe0b5881fa55ce61024100a1a16f2c413af4061e55558a8d490a54f6fa4301209b5659855a8805b802a84a9ac90bc2ac261e4f39a1943d86e4d89c9242571dfd9d90f1a87811bb4f9c702e
//        Hello,encrypt use RSA
    }
    
    static class Person{
        String name;
        //私钥
        PrivateKey sk;
        //公钥
        PublicKey pk;
        public  Person(String name) throws GeneralSecurityException {
            this.name = name;
            //生成公钥/私钥对
            KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
            kpGen.initialize(1024);
            KeyPair kp = kpGen.generateKeyPair();
            this.sk = kp.getPrivate();
            this.pk = kp.getPublic();
        }

        //把私钥导出为字节
        public  byte[] getPrivateKey(){
            return this.sk.getEncoded();
        }
        //把公钥导出为字节
        public byte[] getPublicKey(){
            return this.pk.getEncoded();
        }
        //用公钥加密
        public byte[] encrypt(byte[] message) throws GeneralSecurityException{
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE,this.pk);
            return cipher.doFinal(message);
        }
        //用私钥解密
        public  byte[] decrypt(byte[] input) throws GeneralSecurityException{
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE,this.sk);
            return cipher.doFinal(input);
        }
    }
    //恢复公钥
    public PublicKey recoverPublicKey( byte[] pkData) throws GeneralSecurityException{
        KeyFactory kf = KeyFactory.getInstance("RSA");
        //恢复公钥
        X509EncodedKeySpec pkSpec= new X509EncodedKeySpec(pkData);
        PublicKey publicKey = kf.generatePublic(pkSpec);
        return publicKey;
    }

    //恢复私钥
    public PrivateKey recoverPrivateKey( byte[] skData) throws GeneralSecurityException{
        KeyFactory kf = KeyFactory.getInstance("RSA");
        //恢复公钥
        PKCS8EncodedKeySpec skSpec = new PKCS8EncodedKeySpec(skData);
        PrivateKey privateKey = kf.generatePrivate(skSpec);
        return privateKey;
    }
}

7.数字签名(RSA/DSA/ECDSA)

package main.com.wyz.test;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;

public class DSATest {
    public static void main(String[] args) throws GeneralSecurityException{
        //生成RSA公钥/私钥
        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
        kpGen.initialize(1024);
        KeyPair kp = kpGen.generateKeyPair();
        PrivateKey sk = kp.getPrivate();
        PublicKey pk = kp.getPublic();

        //待签名的消息
        byte[] message = "Hello, I am Bob!".getBytes(StandardCharsets.UTF_8);
        //用私钥签名
        Signature s = Signature.getInstance("SHA1withRSA");
        s.initSign(sk);
        s.update(message);
        byte[] sign = s.sign();
        System.out.println(String.format("signature: %x", new BigInteger(1, sign)));

        //用公钥验证
        Signature v = Signature.getInstance("SHA1withRSA");
        v.initVerify(pk);
        v.update(message);
        boolean valid = v.verify(sign);
        System.out.println("valid? " + valid);

//        signature: 7ffa96db287f9b11983c7b19e46159d37ed63c4455fbd9599b19271a49f3a4707c508da63c836842c25fdbf72e3f615c734d4c64ed9b3b8212988e302c89a4b68f7e42664e64b84e85c2c225bc09ca3833e22dc16020401bffa7bdb3754fa07c486127b12d02ef30f9061be1d5c173d544b6d94d132b8bba6b0b0b34109353f5
//        valid? true
    }

}

9.数字证书 (CA)

package main.com.wyz.test;


import javax.crypto.Cipher;
import java.io.InputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.X509Certificate;
//注意:数字证书存储的是公钥,以及相关的证书链和算法信息。私钥必须严格保密,如果数字证书对应的私钥泄漏,就会造成严重的安全威胁。
public class CATest {
    public static void main(String[] args) throws Exception {
        String password ="123456";//keyStore文件证书密码
        String alias ="mycert";//keyStore证书文件的别名
        //需要发送的信息
        byte[] message = "Hello,use X.509 cert!".getBytes(StandardCharsets.UTF_8);
        //读取keyStore文件
        KeyStore ks = loadKeyStore("/my.keystore", password);
        //读取私钥
        PrivateKey privateKey =(PrivateKey) ks.getKey("mycert", password.toCharArray());

        //读取证书
        X509Certificate certificate = (X509Certificate)ks.getCertificate(alias);
        //加密消息
        byte[] encrypt = encrypt(certificate, message);
        System.out.println(String.format("encrypted: %x", new BigInteger(1, encrypt)));

        //解密信息
        byte[] decrypt = decrypt(privateKey, encrypt);
        System.out.println("decrypted: " + new String(decrypt, StandardCharsets.UTF_8));

        //签名
        byte[] sign = sign(privateKey, certificate, message);
        System.out.println(String.format("signature: %x", new BigInteger(1, sign)));

        //验证签名
        boolean verify = verify(certificate, message, sign);
        System.out.println("verify: " + verify);
    }
    //读取(加载)KeyStore文件
    static KeyStore loadKeyStore(String keyStoreFile, String password){
        try (InputStream input = CATest.class.getResourceAsStream(keyStoreFile)) {
            if(input == null){
                throw new RuntimeException("file not found in classpath:"+keyStoreFile);
            }
            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
            ks.load(input,password.toCharArray());
            return ks;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    // 用公钥加密信息
    static byte[] encrypt(X509Certificate certificate,byte[] message) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance(certificate.getPublicKey().getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE,certificate.getPublicKey());
        return cipher.doFinal(message);
    }
    //用私钥解密信息
    static byte[] decrypt(PrivateKey privateKey,byte[] data) throws GeneralSecurityException{
        Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE,privateKey);
        return cipher.doFinal(data);
    }
    //用私钥和公钥进行信息签名
    static byte[] sign(PrivateKey privateKey,X509Certificate certificate,byte[] message) throws GeneralSecurityException {
        Signature signature = Signature.getInstance(certificate.getSigAlgName());
        signature.initSign(privateKey);
        signature.update(message);
        return signature.sign();
    }
    //用公钥进行签名验证
    static boolean verify(X509Certificate certificate,byte[] message,byte[] sig) throws GeneralSecurityException{
        Signature signature = Signature.getInstance(certificate.getSigAlgName());
        signature.initVerify(certificate);
        signature.update(message);
        boolean verify = signature.verify(sig);
        return verify;

    }
}

参考:https://www.liaoxuefeng.com/wiki/1252599548343744/1255943717668160

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值