• Java加密与解密


    首先应当区分加密与编码并不是一回事。


    一、简介

    1. 加密方式主要有3种:

      • 可逆

        • 【对称加密】:symmetric,例如 AES、DES 等。

        • 【非对称加密】:asymmetric,例如 RSA、DSA 等。

      • 不可逆

        • 【摘要加密】:Digest/Hash,例如 MD5、SHA-1、SHA-256、HMAC 等。
    2. 加解密思想:将一种排序好的二进制,转变为另一种排序的二进制。

      • 输入:二进制数据
      • 输出:二进制数据
    3. 注意:在加密后得到的是二进制数据,一般来说我们需要将其转变为更加容易阅读的十六进制范式,两种方式

      • Base64编码:源数据3个字节为一组, 转化为4个字符表示。
      • BigInteger转码:本质十六进制,源数据的1个字节为一组, 转为2个字符表示。
      String en = Base64.getEncoder().encodeToString( endoce );
      
      • 1
      // 默认的2进制转16进制。【1】表示整数,不加可能得负值(结果出错)
      String encodeHex = new BigInteger(1,msg).toString(16);
      
      // 16进制数据转2进制
      new BigInteger("1f6f", 16).toString(2)
      
      • 1
      • 2
      • 3
      • 4
      • 5
    4. 16进制一般针对无法显示的一些二进制进行显示,常用于:

      • 加密解密。
      • 编码转换。
      • 图片表现形式转换。
    5. 【英语翻译】:

      • Bin:Binary,二进制。
      • Oct:Octal,八进制。
      • Dec:Decimal,十进制。
      • Hex:Hexadecimal,十六进制。
    6. BouncyCastle库

      ​ 一个提供了很多哈希算法和加密算法的第三方库。它包含了Java原生中所缺失的一些加密方式(如国产算法),需要时再导入。

      
      <dependency>
          <groupId>org.bouncycastlegroupId>
          <artifactId>bcprov-jdk15onartifactId>
          <version>1.70version>
      dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    7. 在接下来的章节中,为了达到快速开发的目的,我会结合着Java辅助开发框架【hutool】来讲解。

      
      <dependency>
          <groupId>cn.hutoolgroupId>
          <artifactId>hutool-cryptoartifactId>
          <version>5.8.5version>
      dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

    二、对称加密AES

    1. 简介

      • 对称加密也称私匙加密、传统密码算法,又分为两种类型:
        • 分组加密:也叫块加密(block cyphers),一次加密明文中的一个块。

        • 序列加密:也叫流加密(stream cyphers),一次加密明文中的一个位。

      • 加密和解密共用一套密匙、共用同一个密码,私匙一般不可泄露,双方需要在一开始的时候就相互协商密匙;常用的zip解压缩使用的就是对称加密算法。
      • 在加密的过程中存在三个概念:加密方式工作模式填充模式
    2. 加密方式

      • DES:Data Encryption Standard,“数据加密标准”,密匙过短,可以在短时间内被暴力破解。
      • AES:Advanced Encryption Standard,“高级加密标准”,又称Rijndael加密法,开发目的是为了取代DES,目前最流行的对称加密方式。

      image-20220810081354368

    3. 工作模式(6种)维基百科

      • ECB:Electronic codebook,电子密码本
      • CBC:Cipher-block chaining,密码块链接
      • PCBC:Propagating cipher-block chaining,填充密码块链接
      • CFB:Cipher feedback,密文反馈
      • OFB:Output feedback,输出反馈
      • CTR:Counter mode,计数器模式
    4. 填充模式(9种)

      • **No Padding:**不填充,在此填充下原始数据必须是分组大小的整数倍,非整数倍时无法使用该模式。
      • PKCS5 / PKCS7 Padding:两者基本相同,填充至符合块大小的整数倍。
        • 原始:FF FF FF FF FF FF FF FF FF
        • 填充:FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07
      • ISO10126 Padding:填充至符合块大小的整数倍,填充值最后一个字节为填充的数量数,其他字节随机处理。
        • 原始:FF FF FF FF FF FF FF FF FF
        • 填充:FF FF FF FF FF FF FF FF FF 3F 7A B4 09 14 36 07
      • ISO7816-4 Padding:填充至符合块大小的整数倍,填充值第一个字节为十六进制80,其他字节填 0。
        • 原始:FF FF FF FF FF FF FF FF FF
        • 填充:FF FF FF FF FF FF FF FF FF 80 00 00 00 00 00 00
      • ZeroByte Padding:填充至符合块大小的整数倍,填充值为 0。
        • 原始:FF FF FF FF FF FF FF FF FF
        • 填充:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00
      • X923 Padding:填充至符合块大小的整数倍,填充值最后一个字节为填充的数量数,其他字节填 0。
        • 原始:FF FF FF FF FF FF FF FF FF
        • 填充:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 07
      • TBC Padding(Trailing-Bit-Compliment):填充至符合块大小的整数倍,原文最后一位为“1”时填充 0x00,最后一位为“0”时填充“0xFF”。
        • 原始:FF FF FF FF FF FF FF FF FF
        • 填充:FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00
        • 原始:FF FF FF FF FF FF FF FF F0
        • 填充:FF FF FF FF FF FF FF FF F0 FF FF FF FF FF FF FF
      • PKCS1 Padding:RSA 加密时,需要将原文填充至密钥大小。
    5. 密匙长度

      ​ 以AES为例,密匙长度指的就是 key 的长度,有AES128、AES192、AES256之分,密匙长度越长、保护性就越强、所需要的计算量就越大。密钥长度根据指定密钥位数分别为16、24、32个字符,IV与密钥超过长度则截取,不足则在末尾填充’\0’补足,选择了对应长度的密匙加密方式,密匙本身长度也要跟上。

      在这里插入图片描述

    6. AES,ECB模式加密

      • 简介:

        • ECB模式比较简单,每次固定的密匙总会生成固定的密文。
        • 使用Cipher进行加解密,SecretKey为相对应的密匙、需要在Cipher中初始化。
      • 步骤:

        1. 根据算法名称/工作模式/填充模式获取Cipher实例;
        2. 根据算法名称初始化一个SecretKey实例,密钥必须是指定长度;
        3. 使用SerectKey初始化Cipher实例,并设置加密或解密模式;
        4. 传入明文或密文,获得密文或明文。
      • 【Java原生-加密】

      String message = "待加密内容";
      byte[] data    = message.getBytes("UTF-8");
      
      // 128位 = 16 byte 的 key 值
      byte[] key = "1234567890abcdef".getBytes("UTF-8");
      
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
      SecretKey keySpec = new SecretKeySpec(key, "AES");
      cipher.init(Cipher.ENCRYPT_MODE, keySpec);  // 初始化加密工具
      byte[] encrypted = cipher.doFinal(data);		// 加密
      
      String en = Base64.getEncoder().encodeToString(encrypted);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 【Java原生-解密】
      byte[] key = "1234567890abcdef".getBytes("UTF-8");
      byte[] decode = Base64.getDecoder()
        .decode("AYpKX4YMIhmojH89B3Pd9Q==");
      
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
      SecretKey keySpec = new SecretKeySpec(key, "AES");
      cipher.init(Cipher.DECRYPT_MODE, keySpec);  // 解密模式
      byte[] bytes = cipher.doFinal(decode);
      
      String msg     = new String(bytes,"utf-8");
      System.out.println(msg);  // 输出(正确):“待加密内容”
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 【Hutool-加解密】
      String content = "中文";
      
      //随机生成密钥,当然也可以自定义
      byte[] key = SecureUtil
       .generateKey(SymmetricAlgorithm.AES.getValue())
       .getEncoded();
      
      //构建【对称加密类(工具)】
      AES aes = SecureUtil.aes(key);
      
      // 1. 普通加密、解密
      byte[] encrypt = aes.encrypt(content);
      byte[] decrypt = aes.decrypt(encrypt);
      
      // 2. 加密、解密为16进制字符。
      String encryptHex = aes.encryptHex(content);
      String decryptStr = aes.decryptStr(encryptHex);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
    7. AES,CBC模式加密

      • 简介:

        ​ 需要一个随机数作为IV(Initialization Vector)初始化因子,这样对于同一份明文,每次生成的密文都会不同。IV参数不需要保密,在解密的时候作入参传入。IOS等移动端对AES加密有要求,必须为PKCS7Padding模式。

      • 【原生】简单复合案例

    public class Main {
        public static void main(String[] args) throws Exception {
            // 原文:
            String message = "Hello, world!";
            System.out.println("Message: " + message);
            // 256位密钥 = 32 bytes Key:
            byte[] key = "1234567890abcdef1234567890abcdef".getBytes("UTF-8");
            // 加密:
            byte[] data = message.getBytes("UTF-8");
            byte[] encrypted = encrypt(key, data);
            System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(encrypted));
            // 解密:
            byte[] decrypted = decrypt(key, encrypted);
            System.out.println("Decrypted: " + new String(decrypted, "UTF-8"));
        }
    
        // 加密:
        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 sr = SecureRandom.getInstanceStrong();
            byte[] iv = sr.generateSeed(16);
            IvParameterSpec ivps = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivps);
            byte[] data = cipher.doFinal(input);
            // IV不需要保密,把IV和密文一起返回:
            return join(iv, data);
        }
    
        // 解密:
        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);
            // 解密:
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
            IvParameterSpec ivps = new IvParameterSpec(iv);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivps);
            return cipher.doFinal(data);
        }
    
        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);
            return r;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 【hutool】
    AES aes = new AES(Mode.CBC,Padding.PKCS5Padding,
            "0123456789ABHAEQ".getBytes(),  // 密匙key
            "DYgjCEIMVrj2W9xN".getBytes());	// iv加盐
    
    // 加密、解密,16进制表示
    String encryptHex = aes.encryptHex(content);
    String decryptStr = aes.decryptStr(encryptHex);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    三、非对称加密RSA

    1. 简介

      • 公匙、私匙,常用的非对称加密方式为:
        • RSA:由Ron Rivest,Adi Shamir,Leonard Adleman这三人共同发明,名字由为三人姓氏首字母大写。RSA加密算法基于一个十分简单的数论事实,即将两个大素数相乘十分容易,但想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥
        • DSA:Digital Signature Algorithm,数字签名算法,常用于签名。
      • 某人可以向社会公布他的公匙,任何想发消息给他的人都得用公匙对消息进行加密,然后只有他可以用私匙解密对应消息。
      • 非对称加密和对称加密都不能防止【中间人攻击】,应用2种:加密、签名。
    2. 【必要性说明】

      非对称加密相较于对称加密速度慢、效率低,实际开发中,非对称加密总是和对称加密一起使用。

      • 小明生成一个随机的AES口令,然后用小红的公钥通过RSA加密这个口令,并发给小红。
      • 小红用自己的RSA私钥解密得到AES口令。
      • 双方使用这个共享的AES口令用AES加密通信。
    3. RAS加密

      • 【原生】
    public class Main {
        public static void main(String[] args) throws Exception {
            // 明文:
            byte[] plain = "Hello, encrypt use RSA".getBytes("UTF-8");
            // 创建公钥/私钥对:
            Person alice = new Person("Alice");
            // 用Alice的公钥加密:
            byte[] pk = alice.getPublicKey();
            System.out.println(String.format("public key: %x", new BigInteger(1, pk)));
            byte[] encrypted = alice.encrypt(plain);
            System.out.println(String.format("encrypted: %x", new BigInteger(1, encrypted)));
            // 用Alice的私钥解密:
            byte[] sk = alice.getPrivateKey();
            System.out.println(String.format("private key: %x", new BigInteger(1, sk)));
            byte[] decrypted = alice.decrypt(encrypted);
            System.out.println(new String(decrypted, "UTF-8"));
        }
    }
    
    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);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 【hutool】
      • 使用AsymmetricCrypto类
      • 当拥有密文和一份密匙,只需重新利用密匙构建AsymmetricCrypto即可,此时另一份密匙传入null。
    // 构建 RSA 加密工具,可传参【公匙】与【私匙】。
    AsymmetricCrypto rsa = new AsymmetricCrypto("RSA");
    
    // 获得私钥,可存储于其他文件中
    PrivateKey sk   = rsa.getPrivateKey();
    String     sk64 = rsa.getPrivateKeyBase64();
    
    // 获得公钥,可存储于其他文件中
    PublicKey pk   = rsa.getPublicKey();
    String    pk64 = rsa.getPublicKeyBase64();
    
    // 公钥加密,私钥解密
    String encode = rsa.encryptBase64("中文", KeyType.PublicKey);
    String decode = rsa.decryptStr(encode, KeyType.PrivateKey);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1. RAS签名

      • 私匙加密、公匙解密。
        • 发布者在公布自己的消息时,需要公布两份东西,一份是数据,另一份就是签名。
        • 验证时,先将数据经过散列得到Hash1,再将签名公匙解密得到Hash2,两者进行比对。
        • 事先经过hash散列的好处就是缩短了要加密的数据和生成的签名数据,进一步减轻了带宽压力。
      • 常用的数字签名算法有3种,实际上就是指定某种哈希算法进行RSA签名的方式。
        • MD5withRSA
        • SHA1withRSA
        • SHA256withRSA

      • 【原生】
      // 生成RSA公钥、私钥
      KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
      kpGen.initialize(1024);
      KeyPair    kp = kpGen.generateKeyPair();
      PrivateKey sk = kp.getPrivate();
      PublicKey  pk = kp.getPublic();
      
      // 待签名的消息
      byte[] message = "中文".getBytes(StandardCharsets.UTF_8);
      
      // 用私钥签名
      Signature signSk = Signature.getInstance("SHA1withRSA");
      signSk.initSign(sk);
      signSk.update(message);
      byte[] signed = signSk.sign();
      System.out.println(String.format("signature: %x", new BigInteger(1, signed)));
                         
      // 用公钥验证,最后得到的是Boolean值,判断真假。
      Signature signPk = Signature.getInstance("SHA1withRSA");
      signPk.initVerify(pk);
      signPk.update(message);
      boolean valid = signPk.verify(signed);
      System.out.println("valid? " + valid);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 【hutool】
      byte[] data = "中文".getBytes();
      Sign   sign = SecureUtil.sign(SignAlgorithm.MD5withRSA);
      
      //签名
      byte[] signed = sign.sign(data);
      
      //验证签名
      boolean verify = sign.verify(data, signed);
      System.out.println(verify);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      // 可以将本次生成的私匙与公匙保存到文件
      PublicKey pk = sign.getPublicKey();
      PrivateKey sk = sign.getPrivateKey();
      
      • 1
      • 2
      • 3

    四、摘要加密Hash

    1. 简介

      • 哈希严格来说只是一种摘要算法Digest而不是加密算法。
      • 特点:
        • 对于任意输入,都输出固定长度的值。
        • “不可逆”算法。
      • 应用领域:
        • 加密,MD5加盐散列。
        • 数据完整性验证。
    2. 加盐思想:为什么加盐能够防止黑客通过彩虹表破解?

      ​ 因为在没有加盐时,黑客拥有一张通过大量时间计算得出来的“彩虹表1”,可以轻易的碰撞到原始密码。当我们加盐之后,由于盐值可以是随机的(比如盐值为用户名),此时黑客就需要重新计算大量数据,这种计算是极其耗费时间的。

    3. Java原生哈希算法:输入任意字符,输出固定4字节int型整数。

      // 1. hash 后获得十进制数
      Integer code = "Java".hashCode();
      
      // 2. 将十进制数转为十六进制数
      String  hashString    = Integer.toHexString(code);
      
      // 3. 输出(0x)231e42,4字符 = 32位 = 长度为2+6的十六进制数。
      System.out.println(hashString);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    4. 常见Hash算法

      image-20220809151616625

      • MD5占内存128位,32字符。
      • MD5与SHA-1算法现已可破解,不推荐敏感程序使用(MD5更快、SHA-1更安全)。
      • SHA算法可分为3代,分别为:
        • SHA-1系列:SHA-1。
        • SHA-2系列:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。
        • SHA-3系列:SHA3-224、SHA3-256、SHA3-384、SHA3-512。
    5. hutool提供了一些哈希算法实现

      image-20220810075442556

    6. MD5加密不加盐版

      • 【原生】
      // 获取MessageDigest实例:
      MessageDigest md = MessageDigest.getInstance("MD5");
      
      // 反复调用update输入数据:
      md.update("中".getBytes("UTF-8"));
      md.update("文".getBytes("UTF-8"));
      
      // a7bac2239fcdcb3a067903d8077c4a07
      byte[] result = md.digest(); 
      System.out.println(new BigInteger(1, result).toString(16));
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 【hutool】
      String   testStr = "中文";
      Digester md5     = new Digester(DigestAlgorithm.MD5);
      String digestHex = md5.digestHex(testStr);
      
      // a7bac2239fcdcb3a067903d8077c4a07
      System.out.println(digestHex);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    7. MD5加密加盐版。

      • 加盐本质:拼接字符串再加密。

      • 【原生】:直接拼接字符串,将 key 与 原文拼接一起再 encry。

      • 【Hmac算法】:Hash-based Message Authentication Code,Java原生类,一种更安全的哈希算法,适用于任何可迭代的哈希算法,例如md5、SHA-1等。

      KeyGenerator keyGen = KeyGenerator.getInstance("HmacMD5");
      SecretKey key = keyGen.generateKey();
      
      // 打印随机生成的key:
      byte[] skey = key.getEncoded();
      System.out.println(new BigInteger(1, skey).toString(16));
      
      Mac mac = Mac.getInstance("HmacMD5");
      mac.init(key);
      mac.update("HelloWorld".getBytes("UTF-8"));
      byte[] result = mac.doFinal();
      System.out.println(new BigInteger(1, result).toString(16));
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 【hutool】
      byte[] salt = "password".getBytes();  
      HMac   hmac = new HMac(HmacAlgorithm.HmacMD5, salt);
      
      // b977f4b13f93f549e06140971bded384
      String hmacHex = hmac.digestHex("中文".getBytes("UTF-8"));
      System.out.println(macHex);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6

    五、国产加密SM

    重要章节

    1. 简介:

      • 【hutool】框架工具类SmUtil
      • 涉及到国产加密算法,需导入Bouncy Castle包。
      <dependency>
          <groupId>org.bouncycastlegroupId>
          <artifactId>bcprov-jdk15onartifactId>
          <version>1.70version>
      dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
    2. 国密加密主要分为:

      • 非对称加密和签名:SM2、SM9。
      • 摘要签名算法:SM3
      • 对称加密:SM1、SM4、SM7、祖冲之密码(ZUC)。
    3. SM1算法不公开,仅以IP核的方式存在于芯片中,例如智能门锁、智能IC卡等,成本高。

    4. 非对称加密SM2

      • 【加密】
      String text = "中文";
      SM2 sm2 = SmUtil.sm2();
      
      // 随机公钥加密、私钥解密,自定义直接构造时传入或set__()即可
      String enStr = sm2.encryptBcd(text, KeyType.PublicKey);
      byte[] de = sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey);
      String deStr = new String(decode);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 【签名】

        HexUtil是将字符串或byte数组与16进制表示转换的工具类,效果与使用BigInteger一样,其两者底层实现一样,可以互用。

      String content = "中文";
      final SM2 sm2 = SmUtil.sm2();
      
      // 先转为十六进制数据Hex,然后再签名
      String sign = sm2.signHex(HexUtil.encodeHexStr(content));
      
      // true
      boolean v = sm2.verifyHex(HexUtil.encodeHexStr(content), sign);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    5. 摘要加密SM3

      String digestHex = SmUtil.sm3("中文");
      
      • 1
    6. 对称加密SM4

      String content = "test中文";
      SymmetricCrypto sm4 = SmUtil.sm4();
      
      String encryptHex = sm4.encryptHex(content);
      String decryptStr = sm4.decryptStr(encryptHex);
      
      • 1
      • 2
      • 3
      • 4
      • 5
  • 相关阅读:
    使用【VBScript】从Excel电子表格中读取数据的简单教程
    vue组件传参
    SEO优化排名的技巧与注意点(百度SEO排名的五大注意点)
    Spring底层架构核心概念解析
    JAVA毕业设计的工资管理系统计算机源码+lw文档+系统+调试部署+数据库
    uni-app云打包后,uni.getLocation获取不到位置信息
    c/c++内存管理详解
    06 科技英语|控制与优化学科词汇
    销售团队可以借助CRM系统做什么?
    NIO工作方式浅析
  • 原文地址:https://blog.csdn.net/qq_35760825/article/details/126356394