总体分类

主要分为国密和国际算法

国密算法,即国家商用密码算法,如SM系列的密码,常用的国密密码有:

密码分类

国产商用密码

国际商用密码

对称加密

分组加密(块加密)

SM1/SCB2 SM4/SMS4 SM7

DES 3DES IDEA AES RC5 RC6

序列加密(流加密)

ZUC(祖冲之算法) SSF46

RC4

非对称/公钥加密

大数分解

-

RSA DSA ECDSA Rabin

离散对数

SM2 SM9

DH DSA ECC ECDH

密码杂凑(散列)摘要算法

SM3

MD5 SHA-1 SHA-2 SHA256

  • SM1算法的加密强度与AES相当,但算法未公开,仅以IP核的形式存在于芯片中,调用该算法时,需要通过加密芯片的接口进行调用。

  • SM4算法,是无线局域网标准的分组数据算法,其加密流程介绍请阅读:SM4分组密码算法

  • SM7算法未公开,适用于非接IC卡应用包括身份识别类应用(门禁卡、工作证、参赛证),票务类应用(大型赛事门票、展会门票),支付与通卡类应用(积分消费卡、校园一卡通、企业一卡通、公交一卡通)。

国密算法

国密算法主要包括以下几类:

SM2 ‌:基于椭圆曲线密码学(ECC),用于公钥加密和签名。SM2的密钥长度为256位,适用于移动设备、物联网终端等场景‌12

SM3 ‌:哈希算法,用于生成数据的哈希值。SM3的输出长度为256位,适用于需要高安全性的场景‌12

SM4 ‌:对称加密算法,类似于AES,但密钥长度和轮数不同。SM4的密钥长度为128位,适用于国产化合规场景如政务和金融‌12

SM1 ‌:分组密码算法,主要用于无线局域网产品加密‌3

祖冲之密码算法(ZUC) ‌:流密码算法,用于移动通信和物联网终端‌3

国际算法

国际算法主要包括以下几类:

AES ‌:高级加密标准,分组密码算法,密钥长度可选128、192、256位,适用于高吞吐量场景如互联网和云计算‌13

RSA ‌:非对称加密算法,用于公钥加密和签名。RSA的密钥长度可选2048、3072、4096位,适用于传统PKI体系如SSL证书‌12

3DES ‌:三重DES算法,通过三次DES运算提高安全性,但效率较低‌4

SHA-256 ‌:哈希算法,用于生成数据的哈希值,输出长度为256位‌12

分组加密

分组加密(块加密)— Block Cyper:将明文分组成块,一次加密一个明文分组块。

从国密算法中可以知道,分组加密是对128比特的明文输入和128比特的加密密钥进行处理,生成128比特的密文输出,即分组加密算法只能加密固定长度的明文分组块

但实际情况往往是明文的长度会远超过密码分组的长度,因此需要对分组加密算法进行迭代,才能将明文全部加密,采用的迭代方法就是分组加密算法的加密工作模式。

国密与国际算法区别

1. 对称加密:SM4 vs AES

指标

SM4

AES

算法类型

分组密码(128位分组,128/256位密钥)

分组密码(128位分组,128/192/256位密钥)

运算速度

软件实现效率较低(依赖通用计算单元)

硬件加速广泛(如AES-NI指令集),速度更快

资源消耗

32轮加密,计算复杂度较高

10-14轮加密,优化后资源占用更低

适用场景

国产化合规场景(政务、金融)

高吞吐量场景(互联网、云计算)

2. 非对称加密:SM2 vs RSA/ECC

指标

SM2(基于ECC)

RSA

密钥长度

256位私钥,512位公钥

2048-4096位密钥

运算速度

签名/解密速度更快(短密钥优势)

长密钥导致计算效率低

资源占用

低内存、低带宽需求

高内存、高带宽需求

适用场景

移动设备、物联网终端

传统PKI体系(如SSL证书)

3. 哈希算法:SM3 vs SHA-256

指标

SM3

SHA-256

输出长度

256位哈希值

256位哈希值

运算速度

软件实现稍慢(结构复杂度较高)

硬件优化更好,速度快

抗碰撞性

设计安全性对标SHA-256

全球密码学界广泛验证

适用场景

国产区块链、数字签名

国际通用哈希场景(如比特币)

4.应用场景建议

场景

推荐算法组合

理由

政务/金融合规系统

SM2(签名) + SM4(加密) + SM3(哈希)

满足国产化政策要求

高并发互联网服务

AES(加密) + ECDHE(密钥交换) + SHA-256

高性能与全球兼容性兼顾

物联网终端

SM2(轻量签名) + AES(加密)

平衡安全性与低功耗需求

跨境数据互通

SM4/AES双层加密 + 双证书(SM2/RSA)

合规性与国际互通性折中方案

1. 算法种类

单向加密

对称加密

非对称加密

1.1 单向加密

1) Base64

Base64编码一般用于url的处理,或者说任何你不想让普通人一眼就知道是啥的东西都可以用Base64编码处理后再发布在网络上。

package com.amuro.strategy.base64;
import java.util.Base64;
import com.amuro.strategy.IStrategy;

/**
 * Base64算法基于64个基本字符,加密后的string中只包含这64个字符
 * @author Amuro
 *
 */
public class Base64Strategy implements IStrategy
{
    public String encode(String src)
    {
        byte[] encodeBytes = Base64.getEncoder().encode(src.getBytes());
        return new String(encodeBytes);
    }

    public String decode(String src)
    {
        byte[] decodeBytes = Base64.getDecoder().decode(src.getBytes());
        return new String(decodeBytes);
    }
}

2) MD5

一般用于确保信息的传输完整一致性,校验传输的数据是否被修改,一旦原始信息被修改,生成的 MD5 值将会变得很不同

package com.amuro.strategy.message_digest;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.binary.Hex;
import com.amuro.strategy.IStrategy;

/**
 * 消息摘要算法
 * @author Amuro
 *
 */
public class MD5Strategy implements IStrategy
{
    public String encode(String src)
    {
        try
        {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] encodeBytes = md.digest(src.getBytes());

            return Hex.encodeHexString(encodeBytes);
        }
        catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
        return null;
    }

    public String decode(String src)
    {
        throw new RuntimeException("MD5 no decode");
    }
}

3) SHA 家族

是一个密码散列函数家族,是 FIPS 所认证的安全散列算法

和 MD5 类似,都是对文本进行散列,产生一定长度的散列值

package com.amuro.strategy.message_digest;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.binary.Hex;
import com.amuro.strategy.IStrategy;
/**
 * 安全散列算法
 * @author Amuro
 *
 */
public class SHAStrategy implements IStrategy
{
    public String encode(String src)
    {
        try
        {
            MessageDigest md = MessageDigest.getInstance("SHA");
            md.update(src.getBytes());
            return Hex.encodeHexString(md.digest());
        }
        catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
        return null;
    }

    public String decode(String src)
    {
        throw new RuntimeException("SHA no decode");
    }
}

1.2 对称加密

对称加密的意思就是信息收发都有相同的一把钥匙,消息的加密解密都用这进行

1)DES

Data Encryption Standard,数据加密标准,速度较快,适用于加密大量数据的场合。

package com.amuro.strategy.des;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import org.apache.commons.codec.binary.Hex;
import com.amuro.strategy.IStrategy;

/**
 * 
 * @author Amuro
 *
 */
public class DESStrategy implements IStrategy
{
    private Cipher cipher;
    private SecretKey generateKey;
    public String encode(String src)
    {
        try
        {   //8字节加密
            KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
            keyGenerator.init(56);//size
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] keyBytes = secretKey.getEncoded();

            DESKeySpec desKeySpec = new DESKeySpec(keyBytes);
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
            generateKey = secretKeyFactory.generateSecret(desKeySpec);

            cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, generateKey);
            byte[] resultBytes = cipher.doFinal(src.getBytes());

            return Hex.encodeHexString(resultBytes);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    public String decode(String src)
    {
        try
        {
            cipher.init(Cipher.DECRYPT_MODE, generateKey);
            byte[] result = Hex.decodeHex(src.toCharArray());
            return new String(cipher.doFinal(result));
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

}

3DES,也就是“Triple DES”,中文名“三重数据加密算法”,它相当于是对每个数据块应用三次 DES 加密算法。由于计算机运算能力的增强,原版 DES 密码的密钥长度变得容易被暴力破解;3DES 即是设计用来提供一种相对简单的方法,即通过增加 DES 的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法。

package com.amuro.strategy.des;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import org.apache.commons.codec.binary.Hex;
import com.amuro.strategy.IStrategy;
public class _3DESStrategy implements IStrategy
{
    private Cipher cipher;
    private SecretKey generateKey;

    public String encode(String src)
    {
        try
        {   //16字节加密
            KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
            keyGenerator.init(168);//size
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] keyBytes = secretKey.getEncoded();

            DESedeKeySpec desKeySpec = new DESedeKeySpec(keyBytes);
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DESede");
            generateKey = secretKeyFactory.generateSecret(desKeySpec);

            cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, generateKey);
            byte[] resultBytes = cipher.doFinal(src.getBytes());

            return Hex.encodeHexString(resultBytes);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

    public String decode(String src)
    {
        try
        {
            cipher.init(Cipher.DECRYPT_MODE, generateKey);
            byte[] result = Hex.decodeHex(src.toCharArray());
            return new String(cipher.doFinal(result));
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }
}

2)AES

Advanced Encryption Standard,高级加密标准,是下一代的加密算法标准,速度快,安全级别高;

package com.amuro.strategy.des;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
import com.amuro.strategy.IStrategy;
public class AESStrategy implements IStrategy
{
    private Cipher cipher;
    private SecretKey generateKey;

    public String encode(String src)
    {
        try
        {
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(128);//size
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] keyBytes = secretKey.getEncoded();

            generateKey = new SecretKeySpec(keyBytes, "AES");

            cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, generateKey);
            byte[] resultBytes = cipher.doFinal(src.getBytes());

            return Hex.encodeHexString(resultBytes);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    public String decode(String src)
    {
        try
        {
            cipher.init(Cipher.DECRYPT_MODE, generateKey);
            byte[] result = Hex.decodeHex(src.toCharArray());
            return new String(cipher.doFinal(result));
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }
}

1.3 非对称加密

非对称加密算法是一种密钥的保密方法。 非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。 公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。

1)RSA

名称来源于发明这个算法的三个人的姓氏组成,算法大致内容就是对极大整数进行因式分解

这种算法非常可靠,密钥越长,它就越难破解。根据已经披露的文献,目前被破解的最长 RSA密钥是768个二进制位。也就是说,长度超过768位的密钥,还无法破解(至少没人公开宣布)。因此可以认为,1024位的RSA密钥基本安全,2048位的密钥极其安全

package com.amuro.strategy.asymmetric;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Hex;
import com.amuro.strategy.IStrategy;

public class RSAStrategy implements IStrategy
{
    private RSAPublicKey rsaPublicKey;
    private RSAPrivateKey rsaPrivateKey;
    public String encode(String src)
    {
        try
        {
            //初始化密钥
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(512);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
            rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();

            //私钥加密 公钥解密
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec 
                = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            byte[] resultBytes = cipher.doFinal(src.getBytes());

            //私钥解密 公钥加密
//          X509EncodedKeySpec x509EncodedKeySpec =
//                  new X509EncodedKeySpec(rsaPublicKey.getEncoded());
//          KeyFactory keyFactory = KeyFactory.getInstance("RSA");
//          PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
//          Cipher cipher = Cipher.getInstance("RSA");
//          cipher.init(Cipher.ENCRYPT_MODE, publicKey);
//          byte[] resultBytes = cipher.doFinal(src.getBytes());

            return Hex.encodeHexString(resultBytes);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    public String decode(String src)
    {
        try
        {
            //私钥加密 公钥解密
            X509EncodedKeySpec x509EncodedKeySpec =
                    new X509EncodedKeySpec(rsaPublicKey.getEncoded());
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            byte[] resultBytes = cipher.doFinal(Hex.decodeHex(src.toCharArray()));

            //私钥解密 公钥加密
//          PKCS8EncodedKeySpec pkcs8EncodedKeySpec 
//              = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
//          KeyFactory keyFactory = KeyFactory.getInstance("RSA");
//          PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
//          Cipher cipher = Cipher.getInstance("RSA");
//          cipher.init(Cipher.DECRYPT_MODE, privateKey);
//          byte[] resultBytes = cipher.doFinal(Hex.decodeHex(src.toCharArray()));

            return new String(resultBytes);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

}

2)DH

DH,全称为“Diffie-Hellman”,他是一种确保共享KEY安全穿越不安全网络的方法,也就是常说的密钥一致协议。由公开密钥密码体制的奠基人Diffie和Hellman所提出的一种思想。简单的说就是允许两名用户在公开媒体上交换信息以生成“一致”的、可以共享的密钥。也就是由甲方产出一对密钥(公钥、私钥),乙方依照甲方公钥产生乙方密钥对(公钥、私钥)。

以此为基线,作为数据传输保密基础,同时双方使用同一种对称加密算法构建本地密钥(SecretKey)对数据加密。这样,在互通了本地密钥(SecretKey)算法后,甲乙双方公开自己的公钥,使用对方的公钥和刚才产生的私钥加密数据,同时可以使用对方的公钥和自己的私钥对数据解密。不单单是甲乙双方两方,可以扩展为多方共享数据通讯,这样就完成了网络交互数据的安全通讯!

package com.amuro.strategy.asymmetric;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Objects;
import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import org.apache.commons.codec.binary.Hex;
import com.amuro.strategy.IStrategy;

public class DHStrategy implements IStrategy
{
    private Cipher cipher;
    private SecretKey receiverSecretKey;

    public String encode(String src)
    {
        try
        {
            //初始化发送方密钥
            KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator.getInstance("DH");
            senderKeyPairGenerator.initialize(512);
            KeyPair senderkeyPair = senderKeyPairGenerator.generateKeyPair();
            PrivateKey senderPrivateKey = senderkeyPair.getPrivate();
            byte[] senderPublicKeyBytes = senderkeyPair.getPublic().getEncoded();//发送方的公钥

            //初始化接收方密钥,用发送方的公钥
            KeyFactory receiverKeyFactory = KeyFactory.getInstance("DH");
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(senderPublicKeyBytes);
            PublicKey receiverPublicKey = receiverKeyFactory.generatePublic(x509EncodedKeySpec);
            DHParameterSpec dhParameterSpec = 
                    ((DHPublicKey)receiverPublicKey).getParams();
            KeyPairGenerator receiverKeyPairGenerator = KeyPairGenerator.getInstance("DH");
            receiverKeyPairGenerator.initialize(dhParameterSpec);
            KeyPair receiverKeyPair = receiverKeyPairGenerator.generateKeyPair();
            PrivateKey receiverPrivateKey = receiverKeyPair.getPrivate();
            byte[] receiverPublicKeyBytes = receiverKeyPair.getPublic().getEncoded();

            KeyAgreement receiverKeyAgreement = KeyAgreement.getInstance("DH");
            receiverKeyAgreement.init(receiverPrivateKey);
            receiverKeyAgreement.doPhase(receiverPublicKey, true);
            receiverSecretKey = receiverKeyAgreement.generateSecret("DES");

            //发送方拿到接收方的public key就可以做加密了
            KeyFactory senderKeyFactory = KeyFactory.getInstance("DH");
            x509EncodedKeySpec = new X509EncodedKeySpec(receiverPublicKeyBytes);
            PublicKey senderPublicKey = senderKeyFactory.generatePublic(x509EncodedKeySpec);
            KeyAgreement senderKeyAgreement = KeyAgreement.getInstance("DH");
            senderKeyAgreement.init(senderPrivateKey);
            senderKeyAgreement.doPhase(senderPublicKey, true);
            SecretKey senderSecretKey = senderKeyAgreement.generateSecret("DES");

            if(Objects.equals(receiverSecretKey, senderSecretKey))
            {
                cipher = Cipher.getInstance("DES");
                cipher.init(Cipher.ENCRYPT_MODE, senderSecretKey);
                byte[] result = cipher.doFinal(src.getBytes());
                return Hex.encodeHexString(result);
            }
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

    public String decode(String src)
    {
        try
        {
            cipher.init(Cipher.DECRYPT_MODE, receiverSecretKey);
            byte[] result = Hex.decodeHex(src.toCharArray());
            return new String(cipher.doFinal(result));
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

}

2)数字证书签名

package com.amuro.strategy.signature;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class RSASign
{
    public static boolean verifySign(String src)
    {
        try
        {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(512);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            PublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
            PrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();

            PKCS8EncodedKeySpec pkcs8EncodedKeySpec 
                = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Signature signature = Signature.getInstance("MD5withRSA");
            signature.initSign(privateKey);
            signature.update(src.getBytes());
            //生成签名bytes
            byte[] signBytes = signature.sign();

            X509EncodedKeySpec x509EncodedKeySpec =
                    new X509EncodedKeySpec(rsaPublicKey.getEncoded());
            keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            signature = Signature.getInstance("MD5withRSA");
            signature.initVerify(publicKey);
            signature.update(src.getBytes());
            boolean isVerified = signature.verify(signBytes);

            return isVerified;
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        return false;
    }

}

文章作者: 刘同学
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 刘同学的小站
后端 算法 Java
喜欢就支持一下吧