其中明文分组长为64比特,密钥长为56比特。图的左边是明文的处理过程,有三个阶段,首先是一个初始置换IP,用于重排明文分组的64比特数据。然后是具有相同功能的16轮变换,每轮中都有置换和代换运算,第16轮变换的输出分为左右两半,并被交换次序。最后再经过一个逆初始置换IP^-1(为IP的逆)从而产生64比特的密文。除初始置换和逆初始置换外,DES的结构和图3-3所示的Feistel密码结构完全相同。算法结构图:
轮结构:
其中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); } }
线性混合层:确保多轮之上的高度扩散。
非线性层:将具有最优的“最坏情况非线性特性”的S盒并行使用。
密钥加层:单轮子密钥简单地异或到中间状态上,实现一次性掩盖。
为了使加密算法和解密算法在结构上更加接近,最后一轮的线性混合层与前面各轮的线性混合层不同,这类似于DES的最后一轮不做左右交换一样。可以证明这种设计不以任何方式提高或降低该密码的安全性。
算法的中间结果也须分组,称算法中间结果的分组为状态,所有的操作都在状态上进行。状态可以用以字节为元素的矩阵阵列表示,该阵列有4行,列数记为Nb,Nb等于分组长度除以32。
种子密钥类似地用一个以字节为元素的矩阵阵列表示,该阵列有4行,列数记为Nk,Nk等于分组长度除以32。
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密码算法的基本运算有模2加和循环移位。
① 模2加:记为⊕,为32位逐比特异或运算。
② 循环移位:<<< i,把32位字循环左移i位。
化简得:
为了与解密算法需要的顺序一致,同时也与人们的习惯顺序一致,在加密算法之后还需要一个反序处理 :
与加密算法之后需要一个反序处理同样的道理,在解密算法之后也需要一个反序处理 :
SM4算法加密时输入128位的密钥,采用32轮迭代结构,每一轮使用一个32位的轮密钥,共使用32个轮密钥。使用密钥扩展算法,从加密密钥产生出32个轮密钥。
未完待续。。。。。后面都是大纲
公钥密码学是非对称的,它使用两个独立的密钥,即密钥分为公钥和私钥,因此称双密钥体制。双钥体制的公钥可以公开,因此称为公钥算法
RSA算法既可用于加密,又可用于数字签名,已得到广泛采用,并被许多标准化组织(如ISO、ITU、IETF和SWIFT等)接纳。目前许多国家标准仍采用RSA算法或它的变型。
RSA算法的实现如下:
正确性证明见: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算法使用的方程为:y2= x3 + ax + b
摘要加密(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是在SHA-256基础上改进实现的一种算法。SM3算法采用Merkle-Damgard结构,消息分组长度为512位,摘要值长度为256位。