1.基础知识

暗码学:主要是研讨 编制暗码破译暗码 的学科

暗码学的主要意图:简略的直接说便是,研讨如何躲藏信息并且把信息传递出去的一个学科。

1.1暗码学的前史

1.1.1古典暗码学

古代就开始运用暗码,意图:便是期望维护信息。

中心原理:替换法,移位法

①替换法:

便是运用固定的信息,将原文替换成密文。

例如:bee,将b替换成w,e替换成p,单词就变成了wpp。

替换法的加密办法: 单表替换多表替换

  • 单表替换:原文和密文运用的是同一张表
    例如:abcde ——> swtrp

  • 多表替换:表明有多张表,原文和密文进行对比
    表单1:abcde-swtrp、表单2:abcde-chfhk、表单3:abcde-jftou
    原文:bee
    密钥:312
    密文:fpk

②移位法:

移位法是依照字母,在字母表上面的方位,进行移动

凯撒加密

1.1.2近代暗码学

1.1.3现代暗码学

  • 散列函数

MD5,SHA-1,SHA-256,SHA-512

  • 对称加密

    • 加密办法和解密办法,运用的是同一把密钥

DES加密和解密,AES加密和解密

对称加密的中心原理:流加密,块加密

toString()和new String()中心原理和差异

加密形式:ECB CBC

填充形式:NoPadding和PKCS5padding

  • 非对称加密

    • 有两把密钥,运用公钥加密,有必要运用私钥解密,或许,私钥加密,有必要运用公钥解密

非对称加密的特色

RSA算法和ECC算法

数字摘要

base64中心加密原则,和base64原理

数字签名和数字证书

keytool工具的运用

1.2 ASCII编码

JAVA代码例子

maven依赖

首先导入一下commons-io的maven依赖

<dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.11.0</version>
</dependency>

JavaDemo

charDemo

package com.red.javacodeaudit.encode;
public class AsciiDemo {
    public static void main(String[] args) {
        char a = 'A';
        int b = a;
        //打印出来A字母的ascii编码的巨细
        System.out.println(b);
    }
}

能够看到便是A->65,这儿直接对charint类型进行转化。

Java加密算法

StringDemo

public class AsciiDemo {
    public static void main(String[] args) {
        String str = "rebeyond";
        char[] chars = str.toCharArray();
        for (char aChar : chars) {
            int i = aChar;
            System.out.println(i);
        }
    }
}

其实平常咱们根本不会总是用到char来界说字符,更多的都是用到String来界说字符串,这儿利用了toCharArray办法来回来一个char[]数组,然后转化成ascii方式

Java加密算法

凯撒加密

CaesarDemo

public static void main(String[] args) {
        String input = "Hello World";
        int key = 3;
        char[] chars = input.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (char aChar : chars) {
            int b = aChar;
            b = b + key;
            char newchar = (char) b;
            sb.append(newchar);
        }
        System.out.println(sb.toString());
}

咱们知道凯撒加密便是简略的移位法,然后这儿key设置成3,强调一个知识点便是StringBuilder这个类,咱们将char数组想要转化成String类型的字符串的时分是需求这个类的append办法来完成的。这儿便是加密之后的数据Khoor#Zruog

Java加密算法

凯撒解密

知道这儿需求传入一个密文,和一个解密的key,参数便是这两个,然后回来的是一个String类型的明文

private static String decryptCaesar(String newStr, int key) {
        char[] chars = newStr.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (char aChar : chars) {
            int i = aChar;
            i -= key;
            char newChar = (char) i;
            sb.append(newChar);
        }
        return sb.toString();
}

完好Demo代码

package com.red.javacodeaudit.encode;
public class CaesarDemo {
    public static void main(String[] args) {
        String input = "Hello World";
        int key = 3;
        String newStr = encryptCaesar(input, key);
        System.out.println("密文===>"+newStr);
        String str = decryptCaesar(newStr,key);
        System.out.println("明文===>"+str);
    }
    private static String decryptCaesar(String newStr, int key) {
        char[] chars = newStr.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (char aChar : chars) {
            int i = aChar;
            i -= key;
            char newChar = (char) i;
            sb.append(newChar);
        }
        return sb.toString();
    }
    private static String encryptCaesar(String input, int key) {
        char[] chars = input.toCharArray();
        StringBuilder sb = new StringBuilder();
        for (char aChar : chars) {
            int b = aChar;
            b = b + key;
            char newchar = (char) b;
//            System.out.print(newchar);
            sb.append(newchar);
        }
        return sb.toString();
    }
}

Java加密算法

1.3 频率分析法

意图:在不知道密钥的情况下,也想破解秘文

我认为这儿我应该自己写出来这个工具类,来完善一下自己的java开发水平

原理 :字母e,呈现的频率是最高的,第二高的是t,然后便是a

这儿代码我就放到github上了这儿就不详细演示了,知道怎么做就好.

Github链接,第一次写这种项目,写的十分的乱

1.4 byte和bit的关系

byte:便是所谓的 字节 ,数据存储的根本单位,比如移动硬盘1T,单位事byte

bit: 比特 ,又名做 ,一位要么是0要么是1。数据传输的单位,比如家里的宽带是100MB,下载速度并没有到达100MB,一般都是12-13MB,那是由于需求100/8的速度来看。

1byte = 8bit

代码示例

public static void main(String[] args) {
        String str = "a";
        byte[] bytes = str.getBytes();
        for (byte aByte : bytes) {
            int c = aByte;
            System.out.println(c);
        }
}

这儿输出的成果便是97,对应aascii编码。

之后我看检查一下97的bit方式,Integer类下有一个toBinaryString()办法,能够将字节转化成比特,然后回来一个字符串

String s = Integer.toBinaryString(c);得到成果1100001.

Java加密算法

1.5 中文英文对应的字节

这儿代码先写出来,然后显现一下的字节编码

package com.red.javacodeaudit.encode.ByteBit;
public class bytebit {
    public static void main(String[] args) {
        String str1 = "a";
        String str2 = "红";
        ByteToBit(str2);
    }
    public static void ByteToBit(String str){
        byte[] bytes = str.getBytes();
        for (byte aByte : bytes) {
            System.out.println(aByte);
            String s = Integer.toBinaryString(aByte);
            System.out.println(s);
        }
    }
}

能够看到这儿是一个中文汉字是3个字节,由于这儿是UTF-8编码,假如是UTF-8一个中文对应的是三个字节

Java加密算法

这儿修正一下代码byte[] bytes = str.getBytes("GBK");设置成GBK编码之后,就会变成两个字节,假如是GBK一个中文对应的是两个字节
Java加密算法

假如是英文,就没有编码的概念了,悉数对应的是一个字节

2.对称加密

  • 选用单密钥体系的加密办法,同一个密钥能够一起加密和解密,也成单密钥加密。

  • 常见加密算法

    • DES

    • AES

  • 特色

    • 加密速度快,能够加密大文件

    • 密文可逆,一旦密钥文件泄露,就会导致数据露出

    • 加密后编码表找不到对应字符,呈现乱码

    • 一般结合Base64运用

2.1 DES

2.1.1 Cipher加密目标

根据java官方API的描绘:该类供给加密和解密的加密暗码的功用。 它构成了Java加密扩展(JCE)结构的中心。

为了创立一个Cipher目标,应用程序调用Cipher的getInstance办法,并将所恳求的转化的名称传递给它。 可选地,能够指定供给者的名称。

转化是描绘要在给定输入上履行的操作(或操作集)的字符串,以发生一些输出。 转化总是包含加密算法的名称(例如, DES),并且能够跟从有反馈形式和填充计划。

转化方式如下:

  • “ 算法/形式/填充”或

  • “ 算法”

(在后一种情况下,运用形式和填充计划的供给者特定的默许值)。 例如,以下是有效的转化:

Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");

咱们新建一个Cipher的时分需求调用getInstance函数,里边的参数是“算法/形式/填充”或许只是是“算法”。

2.1.2 DES代码示例

加密一段数据,首先需求原文和密钥

public class DesDemo {
    public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException {
        String data = "小红爱JAVA";
        String key = "12345678";
        String transformation = "DES";//这儿是加密算法
      	String algoritm = "DES";//这儿是加密规矩,跟加密算法是有差异的,可是这儿先了解成是一个东西
        Cipher cipher = Cipher.getInstance(transformation);
    }
}

这儿就得到了一个完好的cipher目标,之后需求对目标进行init,其间有两个参数

  • 行为形式—>ENCRYPT_MODE便是加密,由于cipher目标能够加密也能够解密,所以需求声明这个目标是用来加密的仍是解密的

    Java加密算法

  • 加密规矩—>SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algoritm)这儿便是new一个加密规矩。

    String data = “小红爱JAVA”; String key = “12345678”; String transformation = “DES”; String algoritm = “DES”; Cipher cipher = Cipher.getInstance(transformation); SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algoritm);//new一个加密规矩 cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec);

这儿的init用到的便是这个结构办法

Java加密算法

咱们能够看到SecretKeySpec是完成了SecretKey接口,SecretKey接口继承的Key类,所以本质上仍是一个Key.
Java加密算法

现在有了一个加密的cipher目标之后,就要履行加密办法了便是doFinal(),需求传入原文的byte[]数组,也会回来一个byte[]数组。
Java加密算法
加密后的代码是这个样子

public class DesDemo {
    public static void main(String[] args) throws Exception {
        String data = "小红爱JAVA";
        String key = "12345678";
        String transformation = "DES";
        String algoritm = "DES";
        Cipher cipher = Cipher.getInstance(transformation);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algoritm);
        cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec);
        byte[] bytes = cipher.doFinal(data.getBytes());
        System.out.println(new String(bytes));
    }
}

履行成果是乱码,由于ascii中找不到对应的字节编码

Java加密算法

之后运用base64继续编码一下

public static void main(String[] args) throws Exception {
        String data = "小红爱JAVA";
        String key = "12345678";
        String transformation = "DES";
        String algoritm = "DES";
        Cipher cipher = Cipher.getInstance(transformation);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algoritm);
        cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec);
        byte[] bytes = cipher.doFinal(data.getBytes());
        byte[] encode = Base64.encodeBase64(bytes);
        System.out.println(new String(encode));
}

Java加密算法

留意这儿有一个坑是,运用DES加密的时分密钥key有必要是8位数,其他位数会报错

加密解密完好代码

package com.red.javacodeaudit.encode.DesAes;
import com.sun.org.apache.xml.internal.security.utils.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
public class DesDemo {
    public static void main(String[] args) throws Exception {
        String data = "小红爱JAVA";
        String key = "12345678";
        String transformation = "DES";
        String algoritm = "DES";
      	String encryptData = encryptDes(data,key,transformation,algoritm);
        System.out.println("加密后的数据:"+encryptData);
        String finaldata = decryptDes(encryptData,key,transformation,algoritm);
        System.out.println("解密后的数据:"+finaldata);
    }
    /**
     *
     * @param encryptData 密文
     * @param key
     * @param transformation
     * @param algoritm
     */
    private static String decryptDes(String encryptData, String key, String transformation, String algoritm) throws Exception{
        Cipher cipher = Cipher.getInstance(transformation);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algoritm);
        cipher.init(Cipher.DECRYPT_MODE,secretKeySpec);
        byte[] bytes = cipher.doFinal(Base64.decode(encryptData));
        return new String(bytes);
    }
    /**
     * 用DES算法加密文本
     * @param data
     * @param key
     * @param transformation
     * @param algoritm
     * @return
     * @throws Exception
     * @throws NoSuchAlgorithmException
     */
    private static String encryptDes(String data, String key, String transformation, String algoritm) throws Exception, NoSuchAlgorithmException {
        Cipher cipher = Cipher.getInstance(transformation);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algoritm);
        cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec);
        byte[] bytes = cipher.doFinal(data.getBytes());
        String encode = Base64.encode(bytes);
        return encode;
    }
}

Java加密算法

2.2 Base64

base64不是加密算法,是可读性算法。意图不是维护咱们的数据,意图是为了 可读性

Base64 由64个字符组成,大写A-Z,小写a-z,数字0-9,两个符号 + 和 / 。其实还有=是填充字符

Base64 编码原理:Base64是3个字节为一组,一个字节是8位,一共便是24位,base64把三个字节,转化为4组,每组6位,一个字节,应该是8位,缺少2位,在高位进行补0,这样做的优点便是,base64取后边6位,前面的两位都是0,不进行核算,能够把base64控制在0-63之间。

Java加密算法

在base64中,需求设置一共是3个字节,为一组,假如在输出的时分,不够三个字节,就需求运用=进行补齐

public class Base64Demo {
    public static void main(String[] args) {
        //这儿就一个字符,就需求填充两个等号
        System.out.println(Base64.encode("1".getBytes()));
        System.out.println(Base64.encode("12".getBytes()));
        System.out.println(Base64.encode("123".getBytes()));
        System.out.println(Base64.encode("嘿嘿".getBytes()));
    }
}

Java加密算法

2.3 toString()和new String()

首先看一下代码示例

public class Base64Demo {
    public static void main(String[] args) throws Exception{
        String str = "SmF2YUNvZGVBdWRpdA==";
        System.out.println("new String===>"+new String(Base64.decode(str.getBytes())));
        System.out.println("toString=====>"+Base64.decode(str.getBytes()).toString());
    }
}

成果如下,能够看到new String得到的成果是正确的,那么为什么会是new String得到正确的成果呢

Java加密算法

其实在调用toString的时分会调用的是ObjecttoString办法,调用的是hashcode()办法,得到的是一个哈希值
Java加密算法

new String办法:是根据参数,参数是一个字节数组,运用JVM虚拟机默许编码格式,会把这个字节数组进行decode,找到对应的字符,假如虚拟机的编码格式,假如是ISO-8859-1,会去找ascii里边的编码进行参照,找到对应的字符。

new String():一般在进行转码的时分,需求运用

toString():做目标打印的时分,或许想得到地址的时分,就运用toString().

2.4 AES

这儿跟DES没有差异,便是将代码里的变量改成AES就能够,可是key留意要改成16位的,不然会报错。

2.5 加密形式

2.5.1 ECB(电子暗码本)

ECB:把一段文本进行分拆加密,运用同一个key,别离进行加密,然后组合到一起

  • 优点:能够并行处理数据

  • 缺陷:相同的原文生成相同的密文,不能很好的维护数据

  • 一起加密,原文是一样的,加密出来的密文也是一样的

2.5.2 CBC(暗码块链接)

每个明文块先与前一个密文块进行异或后,再进行加密。在这种办法中,每个密文块都依赖于它前面的一切明文块。这儿存在一个IV向量来加密原文

  • 优点:安全系数很高,相同的原文发生的密文是不同的

  • 缺陷:串行处理数据,加密速度很慢

    Java加密算法

2.6 填充形式

当需求依照块处理的数据,数据长度不符合块处理需求时,依照一定的办法填充溢块长的规矩

2.6.1 NoPadding

  • 不填充

  • 在DES算法中,要求原文长度有必要是8byte的整数倍

  • 在AES算法中,要求原文长度有必要是16byte的整数倍

2.6.2 PKCS5Padding

数据块的巨细为8位,不够就补齐

TIPS:

  • 假如没有设置加密形式和填充形式就默许运用ECB/PKCS5Padding形式

代码示例

这儿看到单纯的运用DES加密的成果是OaaGdLrz6BRTP49DWl2Q6w==

Java加密算法

更换到DES/ECB/PKCS5Padding加密形式和填充形式的时分,密文仍是没有变化,阐明默许便是这个加密形式和填充形式
Java加密算法
现在来看CBC加密形式,只是更换加密形式的话会发生过错,由于咱们知道CBC加密是需求一个IV向量的。
Java加密算法
new IvParameterSpec(key.getBytes());得到一个iv,参数便是key的字节数组,然后在cipher.init的时分参加iv,相同解密的办法里也需求一个iv

IvParameterSpec iv = new IvParameterSpec(key.getBytes());
cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec,iv);
private static String encryptDes(String data, String key, String transformation, String algoritm) throws Exception, NoSuchAlgorithmException {
        Cipher cipher = Cipher.getInstance(transformation);
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), algoritm);
        IvParameterSpec iv = new IvParameterSpec(key.getBytes());
        cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec,iv);
        byte[] bytes = cipher.doFinal(data.getBytes());
        String encode = Base64.encode(bytes);
        return encode;
}

能够看到就不会报错了

Java加密算法

3.音讯摘要

  • 音讯摘要又称数字摘要

  • 它是一个唯一对应一个音讯或文本的固定长度的值,由一个单向的Hash加密函数对音讯进行作用而发生

  • 运用数字摘要生成的值是不行篡改的, 为了确保文件或许值的安全性

音讯摘要算法是不行逆的,常见的算法有

- MD5
- SHA1
- SHA256
- SHA512

运用的是MessageDigest,运用getInstace()办法传入参数algorithm表明加密类型

MessageDigest digest = MessageDigest.getInstance("SHA");

Java加密算法

得到一个digest目标之后就能调用其digest办法,该办法的参数便是原文的字节数组

public class digestDemo {
    public static void main(String[] args) throws NoSuchAlgorithmException {
        String input = "java";
        String algorithm = "MD5";
        MessageDigest digest = MessageDigest.getInstance(algorithm);
        byte[] bytes = digest.digest(input.getBytes());
        System.out.println(Base64.encode(bytes));
    }
}

Java加密算法
写一个直接生成MD5值的demo

public class digestDemo {
   public static void main(String[] args) throws NoSuchAlgorithmException {
       String input = "aa";
       String algorithm = "MD5";
       MessageDigest digest = MessageDigest.getInstance(algorithm);
       byte[] mdcryptData = digest.digest(input.getBytes());
       StringBuilder sb = new StringBuilder();
       for (byte b : mdcryptData) {
           String s = Integer.toHexString(b & 0xff);//将加密的byte数组转化成16进制的代码,回来String字符串
           if(s.length()==1){
               s = "0"+s;//对单个的字符高位进行补0,不然会呈现问题
           }
           sb.append(s);
       }
       System.out.println(sb.toString()); 
   }
}

完好案例

package com.red.javacodeaudit.encrypt.digest;
import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class digestDemo {
    public static void main(String[] args) throws NoSuchAlgorithmException {
        String input = "java";
        String algorithm = "MD5";
        String digest = getDigest(input, algorithm);
        System.out.println(digest);
        String sha1 = getDigest(input, "SHA-1");
        System.out.println(sha1);
        String sha256 = getDigest(input, "SHA-256");
        System.out.println(sha256);
        String sha512 = getDigest(input, "SHA-512");
        System.out.println(sha512);
    }
    private static String getDigest(String input,String algorithm) throws NoSuchAlgorithmException {
        MessageDigest digest = MessageDigest.getInstance(algorithm);
        byte[] cryptData = digest.digest(input.getBytes());
        String encode = HexBin.encode(cryptData);
        return encode;
    }
}

这儿别离是各种加密算法加密出来的数据。

Java加密算法

4.非对称加密

简介:

1.非对称加密,又名现在加密算法

2.有必要要有两个密钥,一个公钥,一个私钥

3.公钥和私钥是一对,咱们叫做密钥对

4.假如运用公钥加密,有必要运用私钥解密

5.假如运用私钥加密,有必要运用公钥解密

常见的非对劲加密算法

  • RSA

  • ECC

4.1 RSA

4.1.1 获取公钥私钥

咱们知道非对劲加密有一个密钥对,需求生成一对密钥,就先要拿到密钥对生成器,也便是KeyPairGenerator.

对于KeyPairGenerator,API中是这么说的:KeyPairGenerator类用于生成公钥和私钥对。 密钥对生成器运用getInstance工厂办法(回来给定类的实例的静态办法)结构。

通过getInstace(algorithm)办法生成一个密钥对生成器,这儿algorithm是咱们自己界说的RSA算法

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);

得到了keyPairGenerator目标是生成器,来生成密钥对,调用keyPairGenerator.generateKeyPair();办法来获取到密钥对keyPair

Java加密算法
然后得到密钥对之后,咱们就能够调用getPrivategetPublic办法来获取到 私钥公钥 了,获取到的公钥和私钥有getEncoded()办法能够将其转化成byte[]数组之后进行Base64编码显现。

public static void main(String[] args) throws Exception{
        String algorithm = "RSA";
        //获取到密钥对
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        System.out.println(Base64.encode(privateKey.getEncoded()));
        System.out.println(Base64.encode(publicKey.getEncoded()));
}

Java加密算法

4.1.2 运用私钥加密数据

Java中只要是想加密,就需求创立加密目标也便是Cipher目标,现在就需求先getInstance一个cipher.之后的步骤跟前面类似

Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE,privateKey);
byte[] bytes = cipher.doFinal(input.getBytes());
System.out.println(Base64.encode(bytes));

这儿便是最终得到的密文数据

Java加密算法

4.1.3 运用公钥解密数据

非对称算法,私钥加密数据,有必要运用公钥解密,不然会报错,有兴趣的朋友就自己动手试试了.

跟其他的解密一样,key设置为publicKey即可

cipher.init(Cipher.DECRYPT_MODE,publicKey);
byte[] bytes1 = cipher.doFinal(bytes);
System.out.println(new String(bytes1));

Java加密算法

4.1.4 保存公钥和私钥

咱们一向生成公钥和私钥就很不方便,所以一般是将公钥和私钥给保存下来

package com.red.javacodeaudit.encrypt.RSA;
import com.sun.org.apache.xml.internal.security.utils.Base64;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.*;
public class RSADemo {
    public static void main(String[] args) throws Exception{
        String input = "Red256's Java";
        String algorithm = "RSA";
        String publicKeyFile = "a.pub";
        String privateKeyFile = "a.pri";
        generatorKeyFile(algorithm,publicKeyFile,privateKeyFile);
}
    private static void generatorKeyFile(String algorithm,String pubFile,String priFile) throws NoSuchAlgorithmException, IOException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        String privatekeyString = Base64.encode(privateKey.getEncoded());
        String publickeyString = Base64.encode(publicKey.getEncoded());
      //这儿commins-IO的包中的办法
        FileUtils.writeStringToFile(new File(pubFile),publickeyString, Charset.forName("UTF-8"));
        FileUtils.writeStringToFile(new File(priFile),privatekeyString,Charset.forName("UTF-8"));
    }
}

成功的生成了公钥和私钥文件

Java加密算法

4.1.5 抽取出加密解密办法

这儿便是把都在main办法中的代码,封装成独立的办法了,没有什么值得说的。

package com.red.javacodeaudit.encrypt.RSA;
import com.sun.org.apache.xml.internal.security.utils.Base64;
import org.apache.commons.io.FileUtils;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.*;
public class RSADemo {
    public static void main(String[] args) throws Exception{
        String input = "Red256's Java";
        String algorithm = "RSA";
        String publicKeyFile = "a.pub";
        String privateKeyFile = "a.pri";
//        generatorKeyFile(algorithm,publicKeyFile,privateKeyFile);
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        String s = encryptRSA(algorithm, privateKey, input);
        System.out.println(s);
        String s1 = decryptRSA(algorithm, publicKey, s);
        System.out.println(s1);
    }
    /**
     *
     * @param algorithm     加密规矩
     * @param publicKey     公钥
     * @param encrypted     密文
     * @return
     */
    private static String decryptRSA(String algorithm,Key publicKey,String encrypted) throws Exception{
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(2,publicKey);
        byte[] decode = Base64.decode(encrypted);
        byte[] bytes = cipher.doFinal(decode);
        return new String(bytes);
    }
    /**
     *
     * @param algorithm     加密规矩
     * @param privateKey    私钥
     * @param input         原文
     * @return
     */
    private static String encryptRSA(String algorithm,Key privateKey,String input) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.ENCRYPT_MODE,privateKey);
        byte[] bytes = cipher.doFinal(input.getBytes());
        String encode = Base64.encode(bytes);
        return encode;
    }
    private static void generatorKeyFile(String algorithm,String pubFile,String priFile) throws NoSuchAlgorithmException, IOException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        String privateKeyString = Base64.encode(privateKey.getEncoded());
        String publicKeyString = Base64.encode(publicKey.getEncoded());
        FileUtils.writeStringToFile(new File(pubFile),privateKeyString, Charset.forName("UTF-8"));
        FileUtils.writeStringToFile(new File(priFile),publicKeyString,Charset.forName("UTF-8"));
    }
}

4.1.6 读取公钥私钥

写一个办法,读取出来文件中的内容,给私钥编码的规矩是PKCS8EncodedKeySpec,官方API的介绍。

Java加密算法

给公钥进行编码的规矩是X509EncodedKeySpec,这儿记住就好,下面是官方API的介绍
Java加密算法

psvm(){
  String input = "Red256's Java";
        String algorithm = "RSA";
        String publicKeyFile = "a.pub";
        String privateKeyFile = "a.pri";
        PrivateKey privateKey = getPrivateKey(privateKeyFile,algorithm);
  			PublicKey publicKey = getPublicKey(publicKeyFile,algorithm);
}
/**
     * 文件中读取私钥
     * @param privateKeyFile 私钥文件
     * @return
     * @throws IOException
     */
private static PrivateKey getPrivateKey(String privateKeyFile,String algorithm) throws IOException, NoSuchAlgorithmException, Base64DecodingException, InvalidKeySpecException {
        String privateKey = FileUtils.readFileToString(new File(privateKeyFile), Charset.defaultCharset());
  			//新建一个key工厂来生成key
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
  			//生成key的时分需求传入一个KeySpec规矩,RSA私钥对应的便是PKCS8EncodedKeySpec这个规矩
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(privateKey));
        return keyFactory.generatePrivate(keySpec);
}
 private static PublicKey getPublicKey(String publicKeyFile, String algorithm) throws Exception {
        String publicKeyString = FileUtils.readFileToString(new File(publicKeyFile), Charset.defaultCharset());
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decode(publicKeyString));
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
}

4.2 数字签名

数字签名:公钥数字签名,只有信息的发送者,才能发生他人无法伪造的一段数字串,类似于写在纸上的普通物理签名

阮一峰老师图解数字签名,解说的毁愈加的详细。

4.2.1 代码生成数字签名

运用Java生成数字签名的时分,会用到Signature这个类,Java的API是这么对它解释的。并且签名算法跟加密算法仍是有差异的常见的签名算法是sha256withrsa

Java加密算法
根据API中的描绘,给得到一个私钥的数字签名分为三步

  • 初始化 —>getInstance这儿的参数便是算法,常见的便是sha256withrsa—>initSign初始化的时分需求传入一个私钥

  • 更新—->update(input.getBytes),更新原文数据转化成字节数组更新到其间

  • 签名—>sign办法,进行签名,回来字节数组。

    public class SignatureDemo { public static void main(String[] args) throws Exception { String a = “123”; String priPath = “a.pri”; String algorithm = “RSA”; PrivateKey privateKey = RSADemo.getPrivateKey(priPath, algorithm);

        getSignature(a,"sha256withrsa",privateKey);
    }
    private static String getSignature(String input, String algorithm, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance(algorithm);
        signature.initSign(privateKey);
        signature.update(input.getBytes());
        byte[] sign = signature.sign();
        return Base64.encode(sign);
    }
    

    }

运转成果如下,把得到的签名文件打印出来了。

Java加密算法

4.2.2 校验数字签名

psvm(){
 boolean b = verifySignature(a, "sha256withrsa", publicKey, signpriKey);
 System.out.println(b);
}
private static boolean verifySignature(String input, String algorithm, PublicKey publicKey, String signpriKey) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, Base64DecodingException {
       Signature signature = Signature.getInstance(algorithm);
       signature.initVerify(publicKey);//这儿是初始化校验
       signature.update(input.getBytes());
       return signature.verify(Base64.decode(signpriKey));
}

用私钥加密的数字签名,就要公钥来解密,所以校验的算法里传入的是公钥,跟私钥加密不同的当地在于initVerify是初始化校验,而不是签名的时分的initSign()办法,这儿参数传入的是publicKey也便是公钥。并且校验办法比签名办法多了参数便是,密文参数,需求得到原文和密文才能够进行校验。

运转成果如下,判断是共同的签名。Github链接

Java加密算法