国密算法总结


国密即国家密码局认定的国产密码算法,即商用密码,主要用于对不涉及国家秘密内容但又具有敏感性的内部信息、行政事务信息、经济信息等进行加密保护。。具体包括

  1. SM1,对称加密算法,加密强度为128位,采用硬件实现
  2. SM2为国家密码管理局公布的公钥算法,其加密强度为256位
  3. SM3,密码杂凑算法,杂凑值长度为32字节,和SM2算法同期公布,参见《国家密码管理局公告(第 22 号)》
  4. SMS4,对称加密算法,随WAPI标准一起公布,可使用软件实现,加密强度为128位。

分组密码算法

  • 概念:将明文数据按固定长度进行分组,然后在同一密钥控制下逐组进行加密,从而将各个明文分组变换成一个等长的密文分组的密码。其中二进制明文分组的长度称为该分组密码的分组规模。
  • 原则:
    1. 必须实现起来比较简单,知道密钥时加密和脱密都十分容易,适合硬件和(或)软件实现.
    2. 加脱密速度和所消耗的资源和成本较低,能满足具体应用范围的需要.
    3. 遵循混淆和扩散
      1. 混淆原则:就是将密文、明文、密钥三者之间的统计关系和代数关系变得尽可能复杂,使得敌手即使获得了密文和明文,也无法求出密钥的任何信息;即使获得了密文和明文的统计规律,也无法求出明文的任何信息。
      2. 扩散原则:就是应将明文的统计规律和结构规律散射到相当长的一段统计中去。也就是说让明文中的每一位影响密文中的尽可能多的位,或者说让密文中的每一位都受到明文中的尽可能多位的影响。例如对英文消息M=m1,m2…m3 的加密操作:在这里插入图片描述
        其中ord(m)是求字母对应的序号,chr(i)是求序号i对应的字母,密文字母y是由明文中k个连续的字母相加而得
    4. Feistel密码结构:加密算法的输入是分组长为2w的明文和一个密钥K 。将每组明文分成左右两半 L0和R0 ,在进行完n轮迭代后,左右两半再合并到一起以产生密文分组。其第i轮迭代的输入为前轮输出的函数:
      在这里插入图片描述
      结构图:在这里插入图片描述
国际DES

其中明文分组长为64比特,密钥长为56比特。图的左边是明文的处理过程,有三个阶段,首先是一个初始置换IP,用于重排明文分组的64比特数据。然后是具有相同功能的16轮变换,每轮中都有置换和代换运算,第16轮变换的输出分为左右两半,并被交换次序。最后再经过一个逆初始置换IP^-1(为IP的逆)从而产生64比特的密文。除初始置换和逆初始置换外,DES的结构和图3-3所示的Feistel密码结构完全相同。算法结构图:
![在这里插入图片描述](https://img-blog.csdnimg.cn/2021070417150125.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2M2MzA4NDM5MDE=,size_16,color_FFFFFF,t_70

  1. 初始置换与逆初始置换:表示第58位换到第一位在这里插入图片描述2. 选择扩展运算:将红框中的部分重复,已达到扩展的目的
    在这里插入图片描述

轮结构:
在这里插入图片描述
其中S盒如下:输入6位,输出4位在这里插入图片描述在这里插入图片描述

JAVA代码:

import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

	public class DesUtils {    
		private static final String DES = "DES";
		private static final String ***KEY*** = "3YxxxxxxxxxZF"; //自定义
		
		private DesUtils() {}
		
		private static byte[] encrypt(byte[] src, byte[] key) throws Exception {
		    SecureRandom sr = new SecureRandom();
		    DESKeySpec dks = new DESKeySpec(key);
		    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
		    SecretKey secretKey = keyFactory.generateSecret(dks);
		    Cipher cipher = Cipher.getInstance(DES);
		    cipher.init(Cipher.ENCRYPT_MODE, secretKey, sr);
		    return cipher.doFinal(src);
		}
		
		private static byte[] decrypt(byte[] src, byte[] key) throws Exception {
		    SecureRandom sr = new SecureRandom();
		    DESKeySpec dks = new DESKeySpec(key);
		    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
		    SecretKey secretKey = keyFactory.generateSecret(dks);
		    Cipher cipher = Cipher.getInstance(DES);
		    cipher.init(Cipher.DECRYPT_MODE, secretKey, sr);
		    return cipher.doFinal(src);
		}
		
		private static String byte2hex(byte[] b) {
		    String hs = "";
		String temp = "";
		for (int n = 0; n < b.length; n++) {
		    temp = (java.lang.Integer.toHexString(b[n] & 0XFF));
		    if (temp.length() == 1)
		        hs = hs + "0" + temp;
		        else
		            hs = hs + temp;
		    }
		    return hs.toUpperCase();
		
		}
		
		private static byte[] hex2byte(byte[] b) {
		    if ((b.length % 2) != 0)
		        throw new IllegalArgumentException("length not even");
		    byte[] b2 = new byte[b.length / 2];
		    for (int n = 0; n < b.length; n += 2) {
		        String item = new String(b, n, 2);
		        b2[n / 2] = (byte) Integer.parseInt(item, 16);
		    }
		    return b2;
		}
		
		private static String decode(String src, String key) {
		    String decryptStr = "";
		    try {
		        byte[] decrypt = decrypt(hex2byte(src.getBytes()), key.getBytes());
		        decryptStr = new String(decrypt);
		    } catch (Exception e) {
		        e.printStackTrace();
		    }
		    return decryptStr;
		}
		
		private static String encode(String src, String key){
		    byte[] bytes = null;
		    String encryptStr = "";
		    try {
		        bytes = encrypt(src.getBytes(), key.getBytes());
		    } catch (Exception ex) {
		        ex.printStackTrace();
		    }
		    if (bytes != null)
		        encryptStr = byte2hex(bytes);
		    return encryptStr;
		}
		
		/**
		 * 解密
		 */
		public static String decode(String src) {
		    return decode(src, KEY);
		}
		
		/**
		 * 加密
		 */
		public static String encode(String src) {
		    return encode(src, KEY);
		}
		
		//测试方法main
		public static void main(String[] args) {
		    String ss = "dawng";
		    String encodeSS = encode(ss);
		    System.out.println(encodeSS);
		    String decodeSS = decode(encodeSS);
		    System.out.println(decodeSS);
		}
}

AES Rijndael

线性混合层:确保多轮之上的高度扩散。
非线性层:将具有最优的“最坏情况非线性特性”的S盒并行使用。
密钥加层:单轮子密钥简单地异或到中间状态上,实现一次性掩盖。

为了使加密算法和解密算法在结构上更加接近,最后一轮的线性混合层与前面各轮的线性混合层不同,这类似于DES的最后一轮不做左右交换一样。可以证明这种设计不以任何方式提高或降低该密码的安全性。
在这里插入图片描述

算法的中间结果也须分组,称算法中间结果的分组为状态,所有的操作都在状态上进行。状态可以用以字节为元素的矩阵阵列表示,该阵列有4行,列数记为Nb,Nb等于分组长度除以32。
种子密钥类似地用一个以字节为元素的矩阵阵列表示,该阵列有4行,列数记为Nk,Nk等于分组长度除以32。


Rijndael的轮函数由四个不同的计算部件组成,分别是:字节代换(ByteSub)、行移位(ShiftRow)、列混合(MixColumn)、密钥加(AddRoundKey)。

  1. 字节代换:字节代换是非线形变换,独立地对状态的每个字节进行。代换表(即S-盒)是可逆的,由以下两个变换的合成得到:
    1. 仿射变换:在这里插入图片描述
    2. 字节代换:在这里插入图片描述

  2. 行移位:不同状态行的位移量不同在这里插入图片描述

  3. 列混合:将状态阵列的每个列视为GF(2^8)上的多项式,再与一个固定的多项式c(x)进行模x4+1乘法。当然要求c(x)是模x4+1可逆的多项式,否则列混合变换就是不可逆的,因而会使不同的输入分组对应的输出分组可能相同。Rijndael的设计者给出的c(x)为(系数用16进制数表示):
    在这里插入图片描述
    c(x)是与x4+1互素的,因此是模x4+1可逆的。

  4. 密钥加:密钥加是将轮密钥简单地与状态进行逐比特异或。轮密钥由种子密钥通过密钥编排算法得到,轮密钥长度等于分组长度Nb。
    在这里插入图片描述

国产SM4

算法结构图:

在这里插入图片描述


SM4密码算法的基本运算有模2加和循环移位。
① 模2加:记为⊕,为32位逐比特异或运算。
② 循环移位:<<< i,把32位字循环左移i位。


基本密码部件
  1. S盒:S盒是以字节为单位的非线性替换,其密码学作用是混淆,它的输入和输出都是8位的字节。设输入字节为a ,输出字节为b, 则S盒的运算可表示为:S(a)=b
  2. 非线性变换r:以字为单位的,它由4个S盒并置构成在这里插入图片描述
  3. 线性变换部件L:以字为处理单位,输入输出都是32位的字,它的密码学作用是扩散。设 的输入为字 ,输出为字 ,则在这里插入图片描述
  4. 合成变换T:由非线性变换和线性变换复合而成,数据处理的单位是字在这里插入图片描述

轮函数:轮函数由上述基本密码部件构成。设轮函数 的输入为4个32位字 ,共128位,轮密钥为一个32位的字 。输出也是一个32位的字

在这里插入图片描述
化简得:在这里插入图片描述

在这里插入图片描述


加密算法可表示如下:

在这里插入图片描述为了与解密算法需要的顺序一致,同时也与人们的习惯顺序一致,在加密算法之后还需要一个反序处理 :在这里插入图片描述


解密算法:

在这里插入图片描述与加密算法之后需要一个反序处理同样的道理,在解密算法之后也需要一个反序处理 :
在这里插入图片描述

密钥扩展算法

SM4算法加密时输入128位的密钥,采用32轮迭代结构,每一轮使用一个32位的轮密钥,共使用32个轮密钥。使用密钥扩展算法,从加密密钥产生出32个轮密钥。

  1. 常数FK在这里插入图片描述
  2. 固定参数:共使用32个固定参数CK,每个CK是一个字,其产生规则如下:设CK<i,j>为CK的第j字节,CK=(CK(i,0),CK(i,1),CK(i,2),CK(i,3))
    在这里插入图片描述
  3. 算法:
    设输入的加密密钥为MK=(MK<0>,MK<1>,MK<2>,MK<3>) ,输出轮密钥为rk< i>,i∈[0,31] ,密钥扩展算法可描述如下,其中 K< i> ,i∈[0,35] 为中间数据:
    在这里插入图片描述与轮函数唯一不同的是线性变换部件L改为了在这里插入图片描述

未完待续。。。。。后面都是大纲

公钥密码算法

公钥密码学是非对称的,它使用两个独立的密钥,即密钥分为公钥和私钥,因此称双密钥体制。双钥体制的公钥可以公开,因此称为公钥算法
在这里插入图片描述

国际RSA

RSA算法既可用于加密,又可用于数字签名,已得到广泛采用,并被许多标准化组织(如ISO、ITU、IETF和SWIFT等)接纳。目前许多国家标准仍采用RSA算法或它的变型。


  • 费马小定理:如果p是一个质数,而整数a不是p的倍数,则有a^(p-1)≡1(mod p)。
  • 欧拉算法:若r0​>r1​,我们可计算q使得r0​=q⋅r1​+r2​,其中r2​<r1​,则gcd(r0​,r1​)=gcd(r1​,r2​)。
  • 扩展欧拉算法:给定两个正整数r0​和r1​,存在 s和t使得s⋅r0​+t⋅r1​=gcd(r0​,r1​),其中s和t是整数。
  • 欧拉函数:对于正整数m,小于m的整数中与m互质的数的数目为Φ(m),Φ称为欧拉函数。
  • 欧拉定理:若a为整数,m为正整数,且a与m互质,则a^Φ(m)≡1 mod m

RSA算法的实现如下:

  1. 寻找出两个大素数p和q
  2. 计算出n=pq 和φ(n)=(p-1)(q-1)
  3. 选择一个随机数e,gcd(e,φ(n))=1.
  4. 使用辗转相除法计算d=e^-1(modφ(n))
  5. 在目录中公开n和e作为公钥

正确性证明见:https://blog.csdn.net/Krone_/article/details/84868865

java代码:

import java.security.Key;
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;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
 
public class RSAUtils{
    public static final String KEY_ALGORITHM="RSA";
    public static final String SIGNATURE_ALGORITHM="MD5withRSA";
    private static final int KEY_SIZE=1024;	//长度和加密时一致
    private static final String PUBLIC_KEY="RSAPublicKey";
    private static final String PRIVATE_KEY="RSAPrivateKey";
    public static String str_pubK = "MIGxxxxxxxxxxxxx8=";	//和前端加密的私钥对应起来
    
      
      /**
       * 使用getPublicKey得到公钥,返回类型为PublicKey
       * @param base64 String to PublicKey
       * @throws Exception
       */
      public static PublicKey getPublicKey(String key) throws Exception {
            byte[] keyBytes;
            keyBytes = (new BASE64Decoder()).decodeBuffer(key);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            return publicKey;
      }
      /**
       * 转换私钥
       * @param base64 String to PrivateKey
       * @throws Exception
       */
      public static PrivateKey getPrivateKey(String key) throws Exception {
            byte[] keyBytes;
            keyBytes = (new BASE64Decoder()).decodeBuffer(key);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
            return privateKey;
      }

      //***************************签名和验证*******************************
      public static byte[] sign(byte[] data) throws Exception{
        PrivateKey priK = getPrivateKey(str_priK);
          Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);        
          sig.initSign(priK);
          sig.update(data);
          return sig.sign();
      }
      
      public static boolean verify(byte[] data,byte[] sign) throws Exception{
          PublicKey pubK = getPublicKey(str_pubK);
          Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
          sig.initVerify(pubK);
          sig.update(data);
          return sig.verify(sign);
      }
      
      //************************加密解密**************************
      public static byte[] encrypt(byte[] bt_plaintext)throws Exception{
          PublicKey publicKey = getPublicKey(str_pubK);
          Cipher cipher = Cipher.getInstance("RSA");
          cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] bt_encrypted = cipher.doFinal(bt_plaintext);
        return bt_encrypted;
      }
      
      public static byte[] decrypt(byte[] bt_encrypted)throws Exception{
        PrivateKey privateKey = getPrivateKey(str_priK);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] bt_original = cipher.doFinal(bt_encrypted);
        return bt_original;
      }
      
      //********************main函数:加密解密和签名验证*********************
      public static void main(String[] args) throws Exception {
            String str_plaintext = "这是一段用来测试密钥转换的明文";
            System.err.println("明文结果:"+str_plaintext);
            byte[] bt_cipher = encrypt(str_plaintext.getBytes());
            System.out.println("加密后结果:"+Base64.encodeBase64String(bt_cipher));
    	  
            byte[] bt_original = decrypt(bt_cipher);
            String str_original = new String(bt_original);
            System.out.println("解密结果:"+str_original);
            
            String str="被签名的内容";
            System.err.println("\n原文:"+str);
            byte[] signature=sign(str.getBytes());
            System.out.println("产生签名值:"+Base64.encodeBase64String(signature));
            boolean status=verify(str.getBytes(), signature);
            System.out.println("验证结果:"+status);
      }
 
}

国产SM2(椭圆曲线算法)

SM2算法使用的方程为:y2= x3 + ax + b

在这里插入图片描述

摘要算法

MD5

摘要加密(MD5):消息摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,目前可以被解密逆向的只有CRC32算法,只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。
注:项目配置一个shiro的jar即可

导入 import org.apache.shiro.crypto.hash.Md5Hash;

注册时对用户输入的密码继续MD5加密,将加密的密码存入数据库
    //  密码            				盐值 搅拌次数
Md5Hash mh = new Md5Hash(Password,"yanzhi",3);
Password = mh.toString(); 

登录时对用户登录的密码进行相同加密,用加密后的值与数据库中加密的密码继续匹配
Md5Hash mh = new Md5Hash(Password,"yanzhi",3);
Password = mh.toString(); 
国产SM3

广泛应用在数字签名,消息认证,数据完整性检测等领域。摘要函数通常被认为需要满足三个基本特性:碰撞稳固性,原根稳固性和第二原根稳固性。
SM3是在SHA-256基础上改进实现的一种算法。SM3算法采用Merkle-Damgard结构,消息分组长度为512位,摘要值长度为256位。

### 回答1: SSM2国密算法是一种国家密码算法,也被称为SM2(无线局域网密码算法)和MIL-STD-1756A算法。它是由国家密码管理局提出的一种非对称加密算法。下面介绍一下SSM2国密算法在不同JDK版本中的对应情况。 在JDK版本8之前,SSM2国密算法并没有被原生支持。但是,可以通过使用第三方的Bouncy Castle等库来实现SSM2国密算法。你需要下载相应版本的Bouncy Castle库,然后通过配置文件来使用该库提供的SSM2国密算法功能。 在JDK版本9及以上,Java原生库开始原生支持SSM2国密算法。你可以直接使用Java原生库来实现SSM2国密算法。可以使用如下代码来生成SSM2密钥对: ```java import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.Security; import org.bouncycastle.jce.provider.BouncyCastleProvider; public class SSM2Example { public static void main(String[] args) throws NoSuchAlgorithmException { Security.addProvider(new BouncyCastleProvider()); KeyPairGenerator generator = KeyPairGenerator.getInstance("SM2", "BC"); generator.initialize(256); // 设置密钥长度 KeyPair keyPair = generator.generateKeyPair(); System.out.println("PrivateKey: " + keyPair.getPrivate()); System.out.println("PublicKey: " + keyPair.getPublic()); } } ``` 上述代码在JDK版本9及以上中可以直接运行并输出SSM2密钥对。注意该代码中的算法名为"SM2",使用了Bouncy Castle作为提供者。 总结来说,SSM2国密算法在不同JDK版本中的对应情况为:在JDK版本8及以下需要使用第三方库(如Bouncy Castle)来实现;在JDK版本9及以上,可以直接使用Java原生库实现。 ### 回答2: ssm2国密算法是一种对称加密算法,也是中国国家密码管理办公室颁布的SM2密码算法的一个实现。SM2密码算法是基于椭圆曲线加密的一种算法,具有高度的安全性和效率。 SSM2国密算法在Java开发中可以与各个版本的JDK一起使用。但需要注意的是,首先要确保JDK支持椭圆曲线算法(ECC),因为SM2密码算法基于椭圆曲线加密。自JDK 7u71和JDK 8u31以后的版本中,JDK开始支持ECC算法。 具体来说,对应不同JDK版本使用SSM2国密算法的步骤如下: 1. 在项目的依赖管理中引入相关的国密算法库,如Bouncycastle(BC)。 2. 在代码中导入相关的包和类,如org.bouncycastle.crypto.CipherParameters、org.bouncycastle.crypto.params.ECPrivateKeyParameters、org.bouncycastle.crypto.params.ECPublicKeyParameters等。 3. 使用具体版本的JDK提供的API来生成SM2参数,如生成SM2密钥对等。 4. 使用SSM2算法进行加密、解密、签名、验签等操作,可以通过调用相应的方法实现。 需要注意的是,由于SSM2国密算法是中国特有的算法,不被国际通用密码标准所接受,因此在使用过程中需要特别注意相关法律和政策的约束。另外,为了确保安全性,建议使用最新版本的JDK和国密算法库,并及时更新补丁。 总之,SSM2国密算法可以与不同版本的JDK一起使用,只需根据相应的JDK版本选择合适的库和API进行集成和开发。 ### 回答3: ssm2国密算法是中国自主研发的一种密码算法集合,由国家密码管理局发布。它是对原有的sm2国密算法进行了改进和优化,提供了更高的安全性和可靠性。 ssm2国密算法主要用于数字签名、密钥交换和公钥加密等密码应用场景。其中,数字签名算法可以用于确保数据的完整性和身份认证,密钥交换算法可以用于确保通信双方的密钥安全,公钥加密算法可以用于确保通信内容的机密性。 对于ssm2国密算法的jdk版本支持,目前常用的JDK版本都具备了对于国密算法的支持。例如,jdk 1.7及以上版本都可以通过引入相关的国密算法库来实现对ssm2国密算法的调用和使用。 在使用ssm2国密算法时,我们可以采用以下步骤来搭建国密环境和调用算法: 1. 首先,需要从官方渠道下载相应的国密算法实现库,如GM-Tools或者BCTLS。 2. 将下载好的库文件导入项目的classpath中,确保可以正常访问。 3. 在代码中引入相关的国密算法工具类,比如SM2Util或者SM2Cipher。 4. 根据具体的功能需求,调用相应的国密算法方法,比如生成密钥对、进行数字签名或者解密操作等。 需要注意的是,由于国密算法涉及到一些加密和解密的敏感操作,建议在正式使用前咨询相关的法律和安全专业人士,确保符合国家相关法律法规的要求,并确保密钥和算法安全性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值