国密算法SM2/3/4简单比较,以及基于Java的SM4(ECB模式,CBC模式)对称加解密实现

04-10 1999阅读

常用的国密算法包含SM2,SM3,SM4。以下针对每个算法使用场景进行说明以比较其差异

国密算法SM2/3/4简单比较,以及基于Java的SM4(ECB模式,CBC模式)对称加解密实现
(图片来源网络,侵删)
  • SM2:非对称加密算法,可以替代RSA
    • 数字签名,SM2为非对称加密,加解密使用一对私钥和公钥,只有签名发行者拥有私钥,可用于加密,其他需要验证解密或验签者使用公钥进行。如果使用公钥可以成功解密,则可以确定数据、文档或其他数字资产的拥有者。
    • 因性能问题,根据实际需要常用于小体积数据加密,例如对密钥或SM3生成的hash进行加密。针对SM3生成的hash值进行加密也是一种常用的签名方式,一般先对需要签名的数据、文档或数字资产使用SM3生成hash再用SM2进行签名。

                 注:

                 如果用于加密,那么加密是用公钥进行的,解密是用私钥进行的。

                 如果用于数字签名,那么签名是用私钥进行的,验证签名则使用公钥。

    • SM3:散列哈希算法
      • 数据库中用户密码的保存,获取用户输入明文密码后,进行SM3生成hash值,再与数据库中保存的已经过SM3计算后的密码值进行比对。
      • 数据完整性验证,针对数据、文件或数据资产进行SM3生成hash并保存,在需要验证数据是否被修改时重新生成hash并与之前保存的hash值进行比对,一旦文件有被修改则会生成不同的hash值。例如可以针对数据库中关键数据字段进行hash,并保存。然后可以通过遍历定期验证hash是否一致,来发现被篡改的数据。
    • SM4:对称加密算法,性能比SM2好
      • 可以用于一般数据的加密与解密,例如可以在需要网络传输的数据发送前进行加密,对方收到数据后使用相同密钥进行解密获得明文。

      基于Java的SM4(ECB模式,CBC模式)对称加解密实现

      简单说明:加密算法依赖了groupId:org.bouncycastle中的bcprov-jdk15to18,Bouncy Castle (bcprov-jdk15to18)提供了JDK 1.5 to 1.8可使用的大量标准加密算法实现,其中包含了SM2,SM3,SM4。在这个类库基础上实现了一个SM4Util加解密工具类。注意: 此版本我在JDK1.8环境下,不同版本JDK需要找到匹配的依赖版本1.8及以上可以使用bcprov-jdk18on。Bouncy Castle同时也提供了bcutil-jdk15to18可以实现SM4加解密。

      方式一:依赖bcprov-jdk15to18(以ECB模式为例) 注如果用jdk1.8的话使用bcprov-jdk18on比bcprov-jdk15to18的加密性能要好。

          org.bouncycastle
          bcprov-jdk15to18
          1.77
      

      字节数组处理工具类: 

      public class ByteUtils {
          private static final char[] HEX_CHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e',
                  'f' };
          private ByteUtils() {
              // Utility class
          }
          public static byte[] fromHexString(String s) {
              int len = s.length();
              //
              // // Data length must be even
              // if (len % 2 != 0) {
              // throw new IllegalArgumentException("Hex string has an odd number of
              // characters");
              // }
              byte[] data = new byte[len / 2];
              for (int i = 0; i > 4) & 0x0f]);
                  sb.append(HEX_CHARS[b & 0x0f]);
              }
              return sb.toString();
          }
          public static String toHexString(byte[] input, String prefix, String separator) {
              StringBuilder sb = new StringBuilder(prefix);
              for (int i = 0; i >> 4) & 0x0f]);
                  sb.append(HEX_CHARS[input[i] & 0x0f]);
                  if (i  
      

       加解密工具类:

      import java.nio.charset.StandardCharsets;
      import java.security.Key;
      import java.security.MessageDigest;
      import java.security.SecureRandom;
      import java.security.Security;
      import java.util.Arrays;
      import javax.crypto.Cipher;
      import javax.crypto.KeyGenerator;
      import javax.crypto.spec.SecretKeySpec;
      import org.bouncycastle.jce.provider.BouncyCastleProvider;
      public class Sm4Utils {
          static {
              Security.addProvider(new BouncyCastleProvider());
          }
          private static final String ENCODING = "UTF-8";
          public static final String ALGORIGTHM_NAME = "SM4";
          public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS7Padding";
          public static final int DEFAULT_KEY_SIZE = 128;
          private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception {
              Cipher cipher = Cipher.getInstance(algorithmName, "BC");
              Key sm4Key = new SecretKeySpec(key, ALGORIGTHM_NAME);
              cipher.init(mode, sm4Key);
              return cipher;
          }
          public static byte[] generateKey(String keyString) throws Exception {
              // Use SHA-256 to hash the string and then take first 128 bits (16 bytes)
              MessageDigest digest = MessageDigest.getInstance("SHA-256");
              byte[] hash = digest.digest(keyString.getBytes(StandardCharsets.UTF_8));
              byte[] key = new byte[16];
              System.arraycopy(hash, 0, key, 0, 16);
              return key;
          }
           public static String encryptEcb(String key, String paramStr, String charset) throws Exception {
              String cipherText = "";
              if (null != paramStr && !"".equals(paramStr)) {
                  byte[] keyData = generateKey(key);
                  charset = charset.trim();
                  if (charset.length() 
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]