大家好,欢迎来到IT知识分享网。
文章目录
国密即国家密码局认定的国产密码算法,即商用密码,主要用于对不涉及国家秘密内容但又具有敏感性的内部信息、行政事务信息、经济信息等进行加密保护。。具体包括
- SM1,对称加密算法,加密强度为128位,采用硬件实现
- SM2为国家密码管理局公布的公钥算法,其加密强度为256位
- SM3,密码杂凑算法,杂凑值长度为32字节,和SM2算法同期公布,参见《国家密码管理局公告(第 22 号)》
- SMS4,对称加密算法,随WAPI标准一起公布,可使用软件实现,加密强度为128位。
分组密码算法
- 概念:将明文数据按固定长度进行分组,然后在同一密钥控制下逐组进行加密,从而将各个明文分组变换成一个等长的密文分组的密码。其中二进制明文分组的长度称为该分组密码的分组规模。
- 原则:
- 必须实现起来比较简单,知道密钥时加密和脱密都十分容易,适合硬件和(或)软件实现.
- 加脱密速度和所消耗的资源和成本较低,能满足具体应用范围的需要.
- 遵循混淆和扩散
- 混淆原则:就是将密文、明文、密钥三者之间的统计关系和代数关系变得尽可能复杂,使得敌手即使获得了密文和明文,也无法求出密钥的任何信息;即使获得了密文和明文的统计规律,也无法求出明文的任何信息。
- 扩散原则:就是应将明文的统计规律和结构规律散射到相当长的一段统计中去。也就是说让明文中的每一位影响密文中的尽可能多的位,或者说让密文中的每一位都受到明文中的尽可能多位的影响。例如对英文消息M=m1,m2…m3 的加密操作:
其中ord(m)是求字母对应的序号,chr(i)是求序号i对应的字母,密文字母y是由明文中k个连续的字母相加而得
- Feistel密码结构:加密算法的输入是分组长为2w的明文和一个密钥K 。将每组明文分成左右两半 L0和R0 ,在进行完n轮迭代后,左右两半再合并到一起以产生密文分组。其第i轮迭代的输入为前轮输出的函数:
结构图:
国际DES
- 初始置换与逆初始置换:表示第58位换到第一位
2. 选择扩展运算:将红框中的部分重复,已达到扩展的目的
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
Rijndael的轮函数由四个不同的计算部件组成,分别是:字节代换(ByteSub)、行移位(ShiftRow)、列混合(MixColumn)、密钥加(AddRoundKey)。
- 字节代换:字节代换是非线形变换,独立地对状态的每个字节进行。代换表(即S-盒)是可逆的,由以下两个变换的合成得到:
1. 仿射变换:
2. 字节代换: - 行移位:不同状态行的位移量不同
- 列混合:将状态阵列的每个列视为GF(2^8)上的多项式,再与一个固定的多项式c(x)进行模x4+1乘法。当然要求c(x)是模x4+1可逆的多项式,否则列混合变换就是不可逆的,因而会使不同的输入分组对应的输出分组可能相同。Rijndael的设计者给出的c(x)为(系数用16进制数表示):
c(x)是与x4+1互素的,因此是模x4+1可逆的。 - 密钥加:密钥加是将轮密钥简单地与状态进行逐比特异或。轮密钥由种子密钥通过密钥编排算法得到,轮密钥长度等于分组长度Nb。
国产SM4
算法结构图:
基本密码部件
- S盒:S盒是以字节为单位的非线性替换,其密码学作用是混淆,它的输入和输出都是8位的字节。设输入字节为a ,输出字节为b, 则S盒的运算可表示为:S(a)=b
- 非线性变换r:以字为单位的,它由4个S盒并置构成
- 线性变换部件L:以字为处理单位,输入输出都是32位的字,它的密码学作用是扩散。设 的输入为字 ,输出为字 ,则
- 合成变换T:由非线性变换和线性变换复合而成,数据处理的单位是字
轮函数:轮函数由上述基本密码部件构成。设轮函数 的输入为4个32位字 ,共128位,轮密钥为一个32位的字 。输出也是一个32位的字
化简得:
加密算法可表示如下:
为了与解密算法需要的顺序一致,同时也与人们的习惯顺序一致,在加密算法之后还需要一个反序处理 :
解密算法:
与加密算法之后需要一个反序处理同样的道理,在解密算法之后也需要一个反序处理 :
密钥扩展算法
SM4算法加密时输入128位的密钥,采用32轮迭代结构,每一轮使用一个32位的轮密钥,共使用32个轮密钥。使用密钥扩展算法,从加密密钥产生出32个轮密钥。
- 常数FK
- 固定参数:共使用32个固定参数CK,每个CK是一个字,其产生规则如下:设CK<i,j>为CK的第j字节,CK=(CK(i,0),CK(i,1),CK(i,2),CK(i,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算法的实现如下:
- 寻找出两个大素数p和q
- 计算出n=pq 和φ(n)=(p-1)(q-1)
- 选择一个随机数e,gcd(e,φ(n))=1.
- 使用辗转相除法计算d=e^-1(modφ(n))
- 在目录中公开n和e作为公钥
正确性证明见:国密算法总结
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
导入 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
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/121583.html