-
如何设计一个高效的算法来解决特定问题?
了解问题首先,需要对问题进行深入的了解,包括问题的具体要求、输入输出格式、数据规模等。确定算法思路在了解问题的基础上,需要确定合适的算法思路。可以根据问题的特点和数据规模选择贪心、动态规划、分治、回溯等算法。编写代码在确定了算法思路后,需要编写代码实现算法。在编写代码时,需要注意代码的可读性、可维护性和效率。测试和优化编写完代码后,需要进行测试和优化。测试需要覆盖各种边界情况和异常情况。优化可以从算法、数据结构、代码实现等方面入手。总结最后,需要总结整个设计算法的过程,包括问题的解决过程、算法的优缺点、代码的实现思路和效率等,为以后的算法设计提供参考。设计高效算法需要深入了解问题、确定算法思路、编写代码、测试和优化,并且需要不断总结和改进。
-
什么是算法复杂度分析?
算法复杂度分析是什么?算法复杂度分析是一种衡量算法效率的方法,通过对算法代码的时间复杂度和空间复杂度进行评估,来衡量算法的执行效率。为什么要进行算法复杂度分析?算法的执行效率是衡量一个算法好坏的重要指标之一,因此需要进行算法复杂度分析来评估算法的执行效率。在实际应用中,如果算法的复杂度过高,会导致程序运行缓慢,甚至无法完成任务。因此,对算法的复杂度进行分析,可以帮助我们优化算法,提高程序的执行效率。如何进行算法复杂度分析?算法复杂度分析通常从时间复杂度和空间复杂度两个方面来考虑。时间复杂度是指算法执行所需要的时间量级,通常用大O符号表示。例如,常见的时间复杂度有O(1)、O(logn)、O(n)、O(nlogn)、O(n^2)等。空间复杂度是指算法执行所需要的存储空间量级,也通常用大O符号表示。例如,常见的空间复杂度有O(1)、O(n)、O(n^2)等。在进行算法复杂度分析时,需要结合具体的算法实现代码进行评估,通常可以通过递推公式、主定理等方法来求解算法的时间复杂度。算法复杂度分析的应用算法复杂度分析在计算机科学中有着广泛的应用,例如在算法设计、数据结构选择、程序优化等方面都需要考虑算法的复杂度。在实际开发中,了解算法复杂度分析的方法可以帮助我们更好地选择合适的算法,提高程序的执行效率。
-
如何编写高效的算法?
编写高效的算法编写高效的算法是每个程序员都应该掌握的技能。以下是一些编写高效算法的技巧:1.选择正确的数据结构不同的数据结构适用于不同的问题,因此选择正确的数据结构非常重要。例如,如果需要快速查找元素,则哈希表可能是更好的选择。2.优化循环循环是算法中最常见的操作之一。优化循环可以大大提高算法的效率。例如,使用前缀和数组可以减少循环次数。3.避免重复计算在算法中重复计算是常见的问题,可以使用记忆化搜索或动态规划来避免重复计算。4.减少内存使用内存使用是算法效率的一个重要因素。使用较小的数据类型,避免使用大型数组等可以减少内存使用。5.使用适当的算法不同的问题适用于不同的算法。要选择适当的算法,需要了解各种算法的优缺点。6.测试和调试测试和调试是编写高效算法的关键。使用单元测试和性能测试可以帮助发现潜在的问题并进行调整。综上所述,编写高效算法需要掌握多种技巧,包括选择正确的数据结构、优化循环、避免重复计算、减少内存使用、使用适当的算法以及测试和调试。
-
AES加密详解
文章目录推荐AES简介对称加密加密模式填充模式常见填充模式PKCS5Padding到底是什么?偏移量字符集实际工作中的加密流程AES加密/解密注意的问题实战AES加解密AES默认实现类AES随机加密推荐AES加密—详解RSA加密—详解AES简介DES全称为DataEncryptionStandard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS)AES密码学中的高级加密标准(AdvancedEncryptionStandard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES(DataEncryptionStandard),已经被多方分析且广为全世界所使用。为什么DES被废弃?我们知道数据加密标准(DataEncryptionStandard:DES)的密钥长度是56比特,因此算法的理论安全强度是2的56次方。但二十世纪中后期正是计算机飞速发展的阶段,元器件制造工艺的进步使得计算机的处理能力越来越强,DES将不能提供足够的安全性。简单来说,DES标准的秘钥长度要求太短,安全性不够。为什么AES算法被称为Rijndael算法?1997年1月2号,美国国家标准技术研究所(NationalInstituteofStandardsandTechnology:NIST)宣布希望征集高级加密标准(AdvancedEncryptionStandard:AES)[3],用以取代DES。AES得到了全世界很多密码工作者的响应,先后有很多人提交了自己设计的算法。最终有5个候选算法进入最后一轮:Rijndael,Serpent,Twofish,RC6和MARS,下图分别为其中的5位作者。最终经过安全性分析、软硬件性能评估等严格的步骤,Rijndael算法获胜。为什么AES算法安全性高?AES的区块长度固定为128位,密钥长度则可以是128bit,192bit或256位bit。换算成字节长度,就是密码必须是16个字节,24个字节,32个字节。AES密码的长度更长了,破解难度就增大了,所以就更安全。对称加密对称加密:也就是加密秘钥和解密秘钥是一样的。非对称加密:也就是加密秘钥和解密秘钥是不一样的。AES是对称加密算法,优点:加密速度快;缺点:如果秘钥丢失,就容易解密密文,安全性相对比较差RSA是非对称加密算法,优点:安全;缺点:加密速度慢AES加密需要:明文+密钥+偏移量(IV)+密码模式(算法/模式/填充)AES解密需要:密文+密钥+偏移量(IV)+密码模式(算法/模式/填充)AES的算法模式一般为AES/CBC/PKCS5Padding加密模式AES的加密模式有以下几种电码本模式(ECB)密码分组链接模式(CBC)计算器模式(CTR)密码反馈模式(CFB)输出反馈模式(OFB)密码分组链接模式(CBC):将整段明文切成若干小段,然后每一小段与初始块或者上一段的密文段进行异或运算后,再与密钥进行加密。电码本模式ECB(Electroniccodebook,ECB):需要加密的消息按照块密码的块大小被分为数个块,并对每个块进行独立加密。根据图示,在CBC模式下,使用AES加解密方式进行分组加解密时,需要用到的两个参数1、初始化向量,也就是偏移量2、加解密秘钥填充模式如电子密码本(ECB)和密文块链接(CBC)。为对称密钥加密设计的块密码工作模式要求输入明文长度必须是块长度的整数倍,因此信息必须填充至满足要求。常见填充模式算法/模式/填充16字节加密后数据长度不满16字节加密后长度AES/CBC/NoPadding16不支持AES/CBC/PKCS5Padding3216AES/CBC/ISO10126Padding3216AES/CFB/NoPadding16原始数据长度AES/CFB/PKCS5Padding3216AES/CFB/ISO10126Padding3216AES/ECB/NoPadding16不支持AES/ECB/PKCS5Padding3216AES/ECB/ISO10126Padding3216AES/OFB/NoPadding16不支持AES/OFB/PKCS5Padding3216AES/OFB/ISO10126Padding3216AES/PCBC/NoPadding16不支持AES/PCBC/PKCS5Padding3216AES/PCBC/ISO10126Padding3216PKCS5Padding到底是什么?为什么JAVA里指定算法时,写的是AES/CBC/PKCS5Padding,每个都是什么含义,又有什么作用。AES,加解密算法CBC,数据分组模式PKCS5Padding,数据按照一定的大小进行分组,最后分剩下那一组,不够长度,就需要进行补齐,也可以叫补齐模式简单的说:拿到一个原始数据以后,首先需要对数据进行分组,分组以后如果长度不满足分组条件,需要进行补齐,最后形成多个分组,在使用加解密算法,对这多个分组进行加解密。所以这个过程中,AES,CBC,PKCS5Padding缺一不可。在对数据进行加解密时,通常将数据按照固定的大小(blocksize)分成多个组,那么随之就产生了一个问题,如果分到最后一组,不够一个blocksize了,要怎么办?此时就需要进行补齐操作。补齐规则:Thevalueofeachaddedbyteisthenumberofbytesthatareadded,i.e.Nbytes,eachofvalueNareadded.举例:36位的UUID,如果按照blocksize=16字节(即128比特),那么就需要补齐到48位,差12个字节。那么最后填充的12个字节的内容,都是字节表示的0x0c(即12)。偏移量偏移量的添加一般是为了增加AES加密的复杂度,增加数据的安全性。一般在AES_256中会使用到偏移量,而在AES_128加密中不会使用到。字符集在AES加密中,特别也要注意到字符集的问题。一般用到的字符集是utf-8和gbk。实际工作中的加密流程在实际的工作中,客户端跟服务器交互一般都是字符串格式,所以一个比较好的加密流程是:加密流程:明文通过密钥(有时也需要偏移量),利用AES加密算法,然后通过Base64转码,最后生成加密后的字符串。解密流程:加密后的字符串通过密钥(有时也需要偏移量),利用AES解密算法,然后通过Base64转码,最后生成解密后的字符串。AES加密/解密注意的问题AES加密/解密的时候,通常是用在服务端和客户端通讯的过程中,一端加密传输,另一端解密使用。虽然AES加密看似简单,但在使用过程过程中,仍然会出现在一端加密ok,但是另一端解密失败的情况。一旦出现AES解密失败,我们可以通过以下几个方面进行排查:1. AES 加密/解密 使用相同的密钥2. 若涉及到偏移量,则AES 加密/解密 使用的偏移量要一样3. AES 加密/解密 要使用相同加密数位,如都使用`AES_256`4. AES 加密/解密 使用相同的字符集5. AES 加密/解密 使用相同的加密,填充模式,如都使用`AES/CBC/PKCS5Padding`模式6. 由于不同开发语言(如C 和 Java)及不同开发环境(如 Java 和 Android)的影响,可能相同的加解密算法在实现上出现差异,若你们注意到这个差异,就可能导致加解密出现问题123456最后,当我们需要验证自己的AES解密算法是否与别人的加密方法为一套的时候。可以让加密方发你一份加密后的密文和加密前的明文,然后你用密文解密,看解密结果和加密方发你的是否一致。需要注意的是,加密方给你的明文要尽量简洁,如就中国二字,这样既能看出加密方和解密方的字符集是否一致,而且能避免复制粘贴等环节出现空格,回车等转义字符对验证结果的干扰。实战AES加解密首先定义加密、解密工具类import javax.crypto.Cipher;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;import java.io.IOException;import java.security.GeneralSecurityException;/** * AES加解密工具类 */public class AES { /** * AES加密 * * @param key * @param iv * @throws GeneralSecurityException * @throws IOException */ public static byte[] encryptAes(byte[] data, byte[] key, byte[] iv) throws GeneralSecurityException, IOException { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv)); return cipher.doFinal(data); } /** * AES解密 * * @param key * @param iv * @return * @throws GeneralSecurityException * @throws IOException */ public static byte[] decryptAesToByteString(byte[] data, byte[] key, byte[] iv) throws GeneralSecurityException, IOException { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv)); return cipher.doFinal(data); }}12345678910111213141516171819202122232425262728293031323334353637383940414243加密和解密的代码很像,唯一的不同点是,加密Cipher.ENCRYPT_MODE,解密用的是Cipher.DECRYPT_MODE下面我们写一个测试代码: try { //加密密码 String key = "zhaoyanjunzhaoy1"; //偏移量 String iv = "1234567890123456"; String message = "今天是周二,我好开心"; //加密 byte[] encryResult = AES.encryptAes(message.getBytes(), key.getBytes(), iv.getBytes()); //解密 byte[] decryResult = AES.decryptAesToByteString(encryResult, key.getBytes(), iv.getBytes()); System.out.println("解密数据 = " + new String(decryResult)); } catch (IOException | GeneralSecurityException e) { e.printStackTrace(); }123456789101112131415161718输出结果:解密数据 = 今天是周二,我好开心1可以看到数据已经正常解密了。AES默认实现类不带模式和填充来获取AES算法的时候,其默认使用AES/ECB/PKCS5Padding(输入可以不是16字节,也不需要填充向量),所以不需要偏移量参数Cipher cipher = Cipher.getInstance("AES");1我下面封装一个工具类import javax.crypto.Cipher;import javax.crypto.spec.SecretKeySpec;import java.io.IOException;import java.security.GeneralSecurityException;/** * AES加解密工具类 */public class AES { /** * AES加密 * * @param key * @throws GeneralSecurityException */ public static byte[] encryptAes(byte[] data, byte[] key) throws GeneralSecurityException { Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES")); return cipher.doFinal(data); } /** * AES解密 * * @param key * @return * @throws GeneralSecurityException * @throws IOException */ public static byte[] decryptAesToByteString(byte[] data, byte[] key) throws GeneralSecurityException, IOException { Cipher cipher = Cipher.getInstance("AES"); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES")); return cipher.doFinal(data); }}12345678910111213141516171819202122232425262728293031323334353637测试代码public class T2 { public static void main(String[] args) { try { //加密密码 String key = "zhaoyanjunzhaoy1"; //加密正文 String message = "今天是周二,我好开心"; //加密 byte[] encryResult = AES.encryptAes(message.getBytes(), key.getBytes()); //解密 byte[] decryResult = AES.decryptAesToByteString(encryResult, key.getBytes()); System.out.println("解密数据 = " + new String(decryResult)); } catch (IOException | GeneralSecurityException e) { e.printStackTrace(); } }}12345678910111213141516171819202122测试结果解密数据 = 今天是周二,我好开心1AES随机加密在上面的例子中,我们在AES加密中,需要指定规定长度的密码,偏移量。在Java中还给我们提供了KeyGenerator类来随机生成一个密码和偏移量,解决了我们动脑想密码的问题。我们来看看随机加密怎么用。 /** * AES加密/解密 * * @throws GeneralSecurityException */ public void encryptAes() throws GeneralSecurityException { //原始数据 String message = "今天是周四,好开心哦"; byte[] data = message.getBytes(); //指定加密类型 KeyGenerator keygen = KeyGenerator.getInstance("AES"); //指定秘钥长度 keygen.init(256); SecretKey secretKey = keygen.generateKey(); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); cipher.init(Cipher.ENCRYPT_MODE, secretKey); //获取秘钥 byte[] key = secretKey.getEncoded(); //获取偏移量 byte[] iv = cipher.getIV(); //解密数据 byte[] ciphertext = cipher.doFinal(data); //解密数据 cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv)); byte[] decryMessage = cipher.doFinal(ciphertext); System.out.println("解密数据 = " + new String(decryMessage)); }123456789101112131415161718192021222324252627282930313233这种加密key,iv都是随机产生的,每次加密后的密文都不一样,适合一定的特殊场景。随机是怎么发生的,我们就看cipher.init(Cipher.ENCRYPT_MODE, secretKey);1在init方法的时候,JceSecurity.RANDOM产生随机数,源码如下: public final void init(int opmode, Key key) throws InvalidKeyException { init(opmode, key, JceSecurity.RANDOM); }123具体细节就不看了,知道原理就行。
-
对称加密与非对称加密算法
1、对称加密 1.1、加密类型 1.1.1、流加密 1.1.2、块加密 1.2、对称加密算法 1.2.1、DES 1.2.2、3DES 1.2.4、AES 1.2.5、SM1 1.2.6、SM4 1.2.7、RC2 1.2.8、RC4 1.2.9、RC5说明 2、非对称加密 2.1、非对称加密算法 2.1.1、RSA 2.1.2、ECC 2.1.3、SM2 3、对称加密与非对称加密技术比较 4、实践 4.1、对称加密工具 4.1.1、AES加解密 4.1.2、DES加解密 4.2、非对称加密工具 4.2.1、RSA加密 4.2.2、ECC加密参考资料1、对称加密 对称加密算法又称为传统密码算法,加密密钥和解密密钥是相同的。对称加密算法要求通信双方在开始通信前,要首先商定一个用于加密和解密的密钥。算法的安全性就依赖于这个密钥,如果这个密钥被泄露了,就意味着通信不再安全。1.1、加密类型根据加密方式不一样,对称加密算法又分为两种加密类型:流加密和块加密。1.1.1、流加密流加密:每次只对明文中的单个位或单个字节进行加密操作。优点是能够实时进行数据传输和解密,缺点是抗攻击能力比较弱。1.1.2、块加密块加密(也称为分组加密):每次对明文中的一组数据进行加密操作。现在使用的分组加密算法典型的分组长度是64位,这个长度大到足以防止破译攻击,而又小到足以方便使用。块加密算法优点是抗攻击能力强,但实时性稍差。算法模式是块加密法中一系列基本算法步骤的组合。块加密法常用的加密模式:电子编码簿模式(ECB),加密块链接模式(CBC),加密反馈模式(CFB),输出反馈模式(OFB),计数器模式(CTR)。电子编码簿模式(ECB)电子编码簿模式是最简单的操作模式,将输入明文消息分为64位块,然后单独加密每个块,消息中所有块使用相同密钥加密。加密步骤如下:从加密步骤我们可以看出,ECB模式中用同一个密钥加密消息的所有块,如果原消息中重复明文块,则加密消息中的相应密文块也会重复。如果输入中一个明文块多次出现,则输出中相应的密文块也会多次出现,从而让攻击者找到漏洞进行破解。 加密块链接模式(CBC)为了解决ECB模式中相同明文产生相同密文的问题,出现了CBC加密模式。CBC加密模式保证了即使输入中明文块相同,也能得到不同的密文块。CBC加密模式使用了反馈机制。加密步骤如下:第一步接收两个输入:明文块1和一个随机文本块IV(InitializationVector),称为初始化向量。初始向量没有什么特别意义,只是使每个消息唯一。初始化向量是随机生成的,可以保证明文块1即使相同也能产生不同密文块1(随机生成的初始化向量相同的概率是很小的)。加密时第一步使用IV和明文1作异或运算,加密后得到密文1,第二步用密文1和明文2作异或运算,加密后得到密文2,后面依此类推。初始化向量只在第一个明文块中使用,但所有明文块加密依旧使用相同密钥。 加密反馈模式(CFB)不是所有应用程序都能处理数据块,面向字符的应用程序也需要安全性。这时要使用流加密法,可以使用加密反馈模式。加密反馈模式中,数据用更小的单元加密(可以是8位,即一个字符的长度),这个长度小于定义的块长(通常是64位)。假设我们一次处理j位(j通常取8)。第一步: 与CBC模式一样,加密反馈模式也使用64位的初始化向量。初始化向量放在移位寄存器中,第一步产生相应的64位初始化向量密文 第二步: 加密初始化向量最左边的j位与明文前j位进行异或运算,产生密文第一部分密文C。第三步: 初始化向量的位左移j位,使移位寄存器最右边的j位为不可预测的数据,在其中填入C的内容。第四步: 重复1~3步,直到加密所有明文单元总体加密过程如下 输出反馈模式(OFB)输出反馈模式与CFB很相似,唯一差别是,CFB中密文填入加密过程下一阶段,而在OFB中,IV加密过程的输入填入加密过程下一阶段。 计数器模式(CTR)计数器模式与OFB模式非常类似。它使用序号(称为计数器)作为算法的输入。每个块加密后,要填充到寄存器中,使用下一个寄存器值。通常使用一个常数作为初始计数器的值,并且每次迭代后递增(通常是增加1)。计数器块的大虚哎等于明文块的大小。加密时,计数器加密后与明文块作XOR运算,得到密文。 1.2、对称加密算法1.2.1、DES全称为DataEncryptionStandard,即数据加密标准。DES是一种块加密算法,按64位块长加密数据,即把64位明文作为DES的输入,产生64位密文输出。DES工作原理DES使用56位密钥。实际上,最初的密钥为64位,但在DES过程开始之前放弃密钥的每个第八位,从而得到56位密钥,即放弃第8、16、24、32、40、48、56、64位。1.2.2、3DES即三重DES,就是三次执行DES,分为两个大类三个密钥的三重DES首先用密钥K1加密明文块P,然后用密钥K2加密,最后用密钥K3加密,其中K1,K2,K3各不相同两个密钥的三重DES1.2.4、AES全称为AdvancedEncryptionStandard,即高级加密标准,这个标准用来替代原先的DES。1998年6月,Rijndael算法提交给美国国家标准与技术协会(NIST),作为AES的候选算法之一。最初有15种候选算法。2000年10月,NIST宣布AES最终选择Rijndael。Rijndael使用的密钥和区块长度可以是32位的整数倍,以128位为下限,256位为上限。AES只选择了区块长度固定为128位,密钥长度为128,192或256位。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。1.2.5、SM1SM1为对称加密。其加密强度与AES相当。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。1.2.6、SM4SM4由我国国家密码管理局在2012年发布,常用于无线互联网加密等领域。与DES和AES算法类似,SM4算法也是一种分组加密算法。其分组长度为128位,密钥长度也为128位。1.2.7、RC2RC2是一种块加密算法。输入和输出块大小都是64位。而密钥是可变的,从1字节到128字节。1.2.8、RC4RC4是一种流加密算法。1.2.9、RC5RC5是一种块加密算法。块长、轮数、密钥长度都是可变的。块长可取16,32和64位。密钥长度为0~2040位。RC5算法的特定实例记作R5-w/r/b,其中w为分组长度,r为轮数,b为密钥长度。RC5-32/16/16表示RC5的块长为64位(RC5一次加密2字节),16轮和16字节(128位)密钥。说明上面介绍的几种对称加密算法,只有RC4是流加密,其他都是分组加密。上面这些只是对对称加密算法进行了一个简单介绍,没有介绍这些算法的加密步骤,如果你对这些加密算法的步骤感兴趣,推荐两本书籍,可以自行去查阅:《密码编码学与网络安全》-[美]WilliamStallings著 电子工业出版社《密码学与网络安全》-AtulKahate著 清华大学出版社 后面如果有时间和精力,我会单独写文章介绍这些加密算法的加密步骤。2、非对称加密 非对称加密算法是现代密码学取得的最大成就之一,也是密码学近20年来能够快速发展和推广应用的主要原因之一。非对称加密算法中加密密钥和解密密钥不一样,并且解密密钥理论上很难根据加密密钥推算出来。 非对称加密算法的加密密钥是公开的,理论上任何人都可以获得这个公开的加密密钥进行数据加密。但是,使用公开的加密密钥加密的信息只有相应的解密密钥才能解开,而这个解密密钥一般是不公开的。在非对称加密算法中,加密密钥也叫公钥,解密密钥称为私钥。2.1、非对称加密算法2.1.1、RSA RSA是被研究得最广泛的公钥算法,从提出到现在,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。 RSA公开密钥密码体制的原理是:根据数论,寻求两个大素数比较简单,而将它们的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。 RSA算法生成密钥对以及加解密过程: (1)选择两个大素数P,Q 设P=7,Q=17 (2)计算N=PxQ N=7x17=119 (3)选择一个公钥E,使其不是(P-1)与(Q-1)的因子 (P-1)=6=2x3 (Q-1)=16=2x2x2x2 因此我们选的公钥E不能有因子2和3。我们取E=5 (4)选择私钥D,满足:(DxE)mod(P-1)x(Q-1)=1 (Dx5)mod6x16=1 (Dx5)mod96=1 经计算,取D=77 (5)加密时,从明文PT计算密文CT:CT= modN 假设明文为10 CT= mod119=40 (6)将密文CT发送给接收方 将40发送给接收方 (7)解密时,从密文CT得到明文PT:PT= modN PT= mod119=10 从上述例子可以看出,RSA算法本身很简单,关键是选择正确的密钥。 假设B要接收A的加密消息,首先生成公钥E和私钥D,私钥D自己保留,公钥E和数字N发布出去,攻击者拿到公钥E和数字N,似乎可以通过试错法计算出私钥D。这里就到了问题的关键,从上述例子可以看出,攻击者只要从N中分解出P和Q,就可以破解私钥。我们上述例子中选择的N很小,实际N是很大的,而大素数分解是极其困难的。2.1.2、ECC大多数使用公钥密码学进行加密和数字签名的产品和标准都使用RSA算法。我们知道,为了保证RSA使用的安全性,最近这些年来密钥的位数一直在增加,这对使用RSA的应用是很重的负担,对进行大量安全交易的电子商务更是如此(从上面RSA加解密的例子可以推测,当要使用1024位密钥时,计算量是很大的)。与RSA相比,ECC可以使用比RSA短得多得密钥得到相同得安全性,因此可以减少处理负荷。另一方面,虽然关于ECC的理论已经很成熟,但ECC的可信度还没有RSA高。ECC全称为ellipticcurvecryptography,即椭圆曲线密码学算法。安全性建立在以下数学困难问题基础之上:椭圆曲线上的离散对数问题:已知有限域Fp椭圆曲线点群Ep(a,b)及其生成元点P∈Ep(a,b),P的阶是一个大素数。已知整数k∈Fp和点P,求点Q=kP是容易的,但已知点P和Q求整数k则是困难的。椭圆曲线上的两个点P和Q,k为整数,Q=kP,椭圆曲线加密的数学原理:点P称为基点,k为私钥,Q为公钥。给定k和P,计算Q很容易。但给定P和Q,求k非常困难。椭圆曲线方程:y= +a+b加解密过程:(1)用户选定一条椭圆曲线Ep(a,b),并取椭圆曲线上一点作为基点P(2)用户A选择大数k作为私钥,并生成公钥Q=kP(3)用户A将Ep(a,b),公钥Q和基点P传给B用户(4)用户B接受到信息后,将待传输的明文编码到Ep(a,b)上的一点M,并产生一个随机整数r。(5)用户B计算点C1=M+rQ,C2=rP(6)用户B将C1和C2传给A(7)用户A接收到信息后,计算C1-kC2,就可以得到点M(C1-kC2=M+rQ-krP=M+r(Q-kP)=M)。(8)再对M进行解码就可以得到明文。假设在加密过程中,有一个第三者H,H只能知道椭圆曲线Ep(a,b)、公钥Q、基点P、密文点C(C1,C2),而通过公钥Q、基点P求私钥k或者通过密文点C(C1,C2)、基点P求随机数r都是非常困难的,因此得以保证数据传输的安全。密码学中,描述一条Fp上的椭圆曲线,常用到六个参量:T=(p,a,b,n,x,y)。(p、a、b)用来确定一条椭圆曲线,p为素数域内点的个数,a和b是其内的两个大数;x,y为G基点的坐标,也是两个大数;n为点G基点的阶;以上六个量就可以描述一条椭圆曲线。2.1.3、SM2SM2算法是我国自主知识产权的商业密码算法,是ECC的一种。ECC是基于椭圆曲线方程y= +a+b,SM通过指定系数a,b确定了唯一的一条曲线。简单理解就是ECC选取的椭圆曲线可以有无数个,而SM2只是选取了唯一的一条椭圆曲线。SM2椭圆曲线公钥密码算法推荐曲线参数推荐使用素数域256位椭圆曲线。椭圆曲线方程:y= +a+b曲线参数:p=FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFFa=FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFCb=28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93n=FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123Gx=32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7Gy=BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0国家密码管理局已经发布了《SM2椭圆曲线公钥密码算法》公告,对SM2算法有非常详细的说明,感兴趣的读者可以自行去查阅。国家密码管理局关于发布《SM2椭圆曲线公钥密码算法》公告(国密局公告第21号)_国家密码管理局(oscca.gov.cn)https://oscca.gov.cn/sca/xxgk/2010-12/17/content_1002386.shtml3、对称加密与非对称加密技术比较对称加密优点:加密速度快缺点:密钥管理分配困难,安全性较低非对称加密优点:安全性较高缺点:加密速度慢对称加密技术加密和解密使用的都是同一个密钥,因此密钥的管理非常困难,在分发密钥的过程中,如果密钥被截获,那后面的通信就是不安全的。而非对称加密技术就很好的解决了这一问题,非对称加密技术使用公钥加密,私钥加密。通信前把公钥发布出去,私钥只有自己保留,即便你的公钥被攻击者拿到,没有私钥,就无法进行解密。那有了非对称加密技术,对称加密是不是就被淘汰了?当然不是,因为非对称加密技术加解密比较慢,不适合对大量数据的加解密。4、实践接下来我们就实际操作一下,先介绍一下开源库openssl。OpenSSL是一个开源且功能强大的包含丰富的密码算法和SSL/TLS协议的库,主要包括的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供了多用途的命令行工具。使用c语言编写,跨平台性能好,支持Linux、Windows、BDS、Mac、VMS等平台。 Openssl由3部分组成 -TheCryptolibrary(密码学算法库) -TheSSLlibrary(SSL/TLS协议库) -Commandlinetool(命令行工具) ubuntu下安装命令:sudoapt-getinstallopensslsudoapt-getinstalllibssl-dev安装后就可以直接使用openssl命令行工具。windows可以通过源码安装或者直接下载安装包安装安装包下载地址:Win32/Win64OpenSSLInstallerforWindows-ShiningLightProductions(slproweb.com)http://slproweb.com/products/Win32OpenSSL.html4.1、对称加密工具enc是openssl提供的一个对称加解密命令行工具。安装openssl后,执行命令opensslenc-list,可以看到enc支持的所有对称加密算法lng@ubuntu:~$ openssl enc -listSupported ciphers:-aes-128-cbc -aes-128-cfb -aes-128-cfb1-aes-128-cfb8 -aes-128-ctr -aes-128-ecb-aes-128-ofb -aes-192-cbc -aes-192-cfb-aes-192-cfb1 -aes-192-cfb8 -aes-192-ctr-aes-192-ecb -aes-192-ofb -aes-256-cbc-aes-256-cfb -aes-256-cfb1 -aes-256-cfb8-aes-256-ctr -aes-256-ecb -aes-256-ofb-aes128 -aes128-wrap -aes192-aes192-wrap -aes256 -aes256-wrap-aria-128-cbc -aria-128-cfb -aria-128-cfb1-aria-128-cfb8 -aria-128-ctr -aria-128-ecb-aria-128-ofb -aria-192-cbc -aria-192-cfb-aria-192-cfb1 -aria-192-cfb8 -aria-192-ctr-aria-192-ecb -aria-192-ofb -aria-256-cbc-aria-256-cfb -aria-256-cfb1 -aria-256-cfb8-aria-256-ctr -aria-256-ecb -aria-256-ofb-aria128 -aria192 -aria256-bf -bf-cbc -bf-cfb-bf-ecb -bf-ofb -blowfish-camellia-128-cbc -camellia-128-cfb -camellia-128-cfb1-camellia-128-cfb8 -camellia-128-ctr -camellia-128-ecb-camellia-128-ofb -camellia-192-cbc -camellia-192-cfb-camellia-192-cfb1 -camellia-192-cfb8 -camellia-192-ctr-camellia-192-ecb -camellia-192-ofb -camellia-256-cbc-camellia-256-cfb -camellia-256-cfb1 -camellia-256-cfb8-camellia-256-ctr -camellia-256-ecb -camellia-256-ofb-camellia128 -camellia192 -camellia256-cast -cast-cbc -cast5-cbc-cast5-cfb -cast5-ecb -cast5-ofb-chacha20 -des -des-cbc-des-cfb -des-cfb1 -des-cfb8-des-ecb -des-ede -des-ede-cbc-des-ede-cfb -des-ede-ecb -des-ede-ofb-des-ede3 -des-ede3-cbc -des-ede3-cfb-des-ede3-cfb1 -des-ede3-cfb8 -des-ede3-ecb-des-ede3-ofb -des-ofb -des3-des3-wrap -desx -desx-cbc-id-aes128-wrap -id-aes128-wrap-pad -id-aes192-wrap-id-aes192-wrap-pad -id-aes256-wrap -id-aes256-wrap-pad-id-smime-alg-CMS3DESwrap -rc2 -rc2-128-rc2-40 -rc2-40-cbc -rc2-64-rc2-64-cbc -rc2-cbc -rc2-cfb-rc2-ecb -rc2-ofb -rc4-rc4-40 -seed -seed-cbc-seed-cfb -seed-ecb -seed-ofb-sm4 -sm4-cbc -sm4-cfb-sm4-ctr -sm4-ecb -sm4-ofbenc完整命令openssl enc -ciphername [-in filename] [-out filename] [-pass arg] [-e ] [-d ] [-a ] [-A] [-k password ] [-kfile filename] [-K key] [-iv IV] [-p] [-P] [-bufsize number] [-nopad] [-debug]-ciphername:对称算法名称(就是上面执行opensslenc-list命令后展示的那些)-infilename:输入文件,默认为标准输入。-outfilename:输出文件,默认为标准输出。-passarg:输入文件如果有密码保护,指定密码来源。-e:进行加密操作,默认操作。-d:进行解密操作。-a:当进行加解密时,它只对数据进行运算,有时需要进行base64转换。设置此选项后,加密结果进行base64编码;解密前先进行base64解码。-A:默认情况下,base64编码结果在文件中是多行的。如果要将生成的结果在文件中只有一行,需设置此选项;解密时,必须采用同样的设置,否则读取数据时会出错。-kpassword:指定加密口令,不设置此项时,程序会提示用户输入口令。-kfilefilename:指定口令存放的文件。-Kkey:密钥,为16进制。-ivIV:初始化向量,为16进制。-p:打印出使用的salt、口令以及初始化向量IV。-P:打印使用的salt、口令以及IV,不做加密和解密操作。-bufsizenumber:设置I/O操作的缓冲区大小,因为一个文件可能很大,每次读取的数据是有限的。-debug:打印调试信息。4.1.1、AES加解密加密命令openssl enc -aes-128-cbc -in in.txt -out out.txt -a -K 001122334455BBCCDDEEFF0011223344 -iv 0123456789ABCDEF0123456789ABCDEF我们选择的密钥长度为128位,从上面列表可以知道,密钥长度可以选取128位,192位,256位。选择的加密模式为cbc,加密模式可以选取ecb,cbc,cfb,ofb,ctr。加密模式是什么意思在上面已经将的很清楚了。演示lng@ubuntu:~/CSDN/enc$ cat in.txthello wordlng@ubuntu:~/CSDN/enc$ openssl enc -aes-128-cbc -in in.txt -out out.txt -a -K 001122334455BBCCDDEEFF0011223344 -iv 0123456789ABCDEF0123456789ABCDEFlng@ubuntu:~/CSDN/enc$ lsin.txt out.txtlng@ubuntu:~/CSDN/enc$ cat out.txtBqbu9rk0uOXRgahyZWW7tA==lng@ubuntu:~/CSDN/enc$解密命令openssl enc -aes-128-cbc -in out.txt -out inin.txt -d -a -K 001122334455BBCCDDEEFF0011223344 -iv 0123456789ABCDEF0123456789ABCDEF演示lng@ubuntu:~/CSDN/enc$ openssl enc -aes-128-cbc -in out.txt -out inin.txt -d -a -K 001122334455BBCCDDEEFF0011223344 -iv 0123456789ABCDEF0123456789ABCDEFlng@ubuntu:~/CSDN/enc$ lsinin.txt in.txt out.txtlng@ubuntu:~/CSDN/enc$ cat inin.txthello wordlng@ubuntu:~/CSDN/enc$注意:如果你要阅读密文,要指定参数-a进行base64编码,否则密文是二进制文件,解密时也要指定-a参数,先进行base64解码,再进行解密。 默认是加密操作,加密时可以不指定参数,但解密时我们要指定参数-d ecb模式是没有初始化向量的,所以ecb模式我们不用指定-iv参数你可以选择不同的密钥长度和不同的加密模式,看看密文有什么不同。我这里就不演示了 4.1.2、DES加解密des密钥长度是固定的,为64位,所以我们只需要选择加密模式。lng@ubuntu:~/CSDN/enc$ cat in.txthello wordlng@ubuntu:~/CSDN/enc$ openssl enc -des-ecb -K 0123456789AAAAAA -in in.txt -out out.txt -alng@ubuntu:~/CSDN/enc$ lsin.txt out.txtlng@ubuntu:~/CSDN/enc$ cat out.txtmunBF17bqEeZ28tiddZVxg==lng@ubuntu:~/CSDN/enc$ openssl enc -des-ecb -d -K 0123456789AAAAAA -in out.txt -out inin.txt -alng@ubuntu:~/CSDN/enc$ lsinin.txt in.txt out.txtlng@ubuntu:~/CSDN/enc$ cat inin.txthello wordlng@ubuntu:~/CSDN/enc$4.2、非对称加密工具4.2.1、RSA加密这里介绍下openssl命令行工具的两个命令genrsa 生成rsa密钥rsa 用于处理rsa密钥,格式转换和打印信息生成私钥# private.key 为私钥文件,其中包含公钥和私钥,1024为密钥长度openssl genrsa -out private.key 1024导出公钥# 从私钥文件中导出公钥openssl rsa -in private.key -pubout -out public.key使用公钥加密openssl rsautl -encrypt -pubin -inkey public.key -in in.txt -out out.txt使用私钥解密openssl rsautl -decrypt -inkey private.key -in out.txt -out inin.txt4.2.2、ECC加密ecparam 椭圆曲线密钥参数生成及操作ec 椭圆曲线密钥处理工具查看支持的椭圆曲线openssl ecparam -list_curves可以看到支持的所有椭圆曲线,最前面的就是曲线名称。 secp112r1 : SECG/WTLS curve over a 112 bit prime field secp112r2 : SECG curve over a 112 bit prime field secp128r1 : SECG curve over a 128 bit prime field secp128r2 : SECG curve over a 128 bit prime field secp160k1 : SECG curve over a 160 bit prime field secp160r1 : SECG curve over a 160 bit prime field secp160r2 : SECG/WTLS curve over a 160 bit prime field secp192k1 : SECG curve over a 192 bit prime field secp224k1 : SECG curve over a 224 bit prime field secp224r1 : NIST/SECG curve over a 224 bit prime field secp256k1 : SECG curve over a 256 bit prime field secp384r1 : NIST/SECG curve over a 384 bit prime field secp521r1 : NIST/SECG curve over a 521 bit prime field prime192v1: NIST/X9.62/SECG curve over a 192 bit prime field prime192v2: X9.62 curve over a 192 bit prime field prime192v3: X9.62 curve over a 192 bit prime field prime239v1: X9.62 curve over a 239 bit prime field prime239v2: X9.62 curve over a 239 bit prime field prime239v3: X9.62 curve over a 239 bit prime field prime256v1: X9.62/SECG curve over a 256 bit prime field sect113r1 : SECG curve over a 113 bit binary field sect113r2 : SECG curve over a 113 bit binary field sect131r1 : SECG/WTLS curve over a 131 bit binary field sect131r2 : SECG curve over a 131 bit binary field sect163k1 : NIST/SECG/WTLS curve over a 163 bit binary field sect163r1 : SECG curve over a 163 bit binary field sect163r2 : NIST/SECG curve over a 163 bit binary field sect193r1 : SECG curve over a 193 bit binary field sect193r2 : SECG curve over a 193 bit binary field sect233k1 : NIST/SECG/WTLS curve over a 233 bit binary field sect233r1 : NIST/SECG/WTLS curve over a 233 bit binary field sect239k1 : SECG curve over a 239 bit binary field sect283k1 : NIST/SECG curve over a 283 bit binary field sect283r1 : NIST/SECG curve over a 283 bit binary field sect409k1 : NIST/SECG curve over a 409 bit binary field sect409r1 : NIST/SECG curve over a 409 bit binary field sect571k1 : NIST/SECG curve over a 571 bit binary field sect571r1 : NIST/SECG curve over a 571 bit binary field c2pnb163v1: X9.62 curve over a 163 bit binary field c2pnb163v2: X9.62 curve over a 163 bit binary field c2pnb163v3: X9.62 curve over a 163 bit binary field c2pnb176v1: X9.62 curve over a 176 bit binary field c2tnb191v1: X9.62 curve over a 191 bit binary field c2tnb191v2: X9.62 curve over a 191 bit binary field c2tnb191v3: X9.62 curve over a 191 bit binary field c2pnb208w1: X9.62 curve over a 208 bit binary field c2tnb239v1: X9.62 curve over a 239 bit binary field c2tnb239v2: X9.62 curve over a 239 bit binary field c2tnb239v3: X9.62 curve over a 239 bit binary field c2pnb272w1: X9.62 curve over a 272 bit binary field c2pnb304w1: X9.62 curve over a 304 bit binary field c2tnb359v1: X9.62 curve over a 359 bit binary field c2pnb368w1: X9.62 curve over a 368 bit binary field c2tnb431r1: X9.62 curve over a 431 bit binary field wap-wsg-idm-ecid-wtls1: WTLS curve over a 113 bit binary field wap-wsg-idm-ecid-wtls3: NIST/SECG/WTLS curve over a 163 bit binary field wap-wsg-idm-ecid-wtls4: SECG curve over a 113 bit binary field wap-wsg-idm-ecid-wtls5: X9.62 curve over a 163 bit binary field wap-wsg-idm-ecid-wtls6: SECG/WTLS curve over a 112 bit prime field wap-wsg-idm-ecid-wtls7: SECG/WTLS curve over a 160 bit prime field wap-wsg-idm-ecid-wtls8: WTLS curve over a 112 bit prime field wap-wsg-idm-ecid-wtls9: WTLS curve over a 160 bit prime field wap-wsg-idm-ecid-wtls10: NIST/SECG/WTLS curve over a 233 bit binary field wap-wsg-idm-ecid-wtls11: NIST/SECG/WTLS curve over a 233 bit binary field wap-wsg-idm-ecid-wtls12: WTLS curve over a 224 bit prime field Oakley-EC2N-3:IPSec/IKE/Oakley curve #3 over a 155 bit binary field.Not suitable for ECDSA.Questionable extension field! Oakley-EC2N-4:IPSec/IKE/Oakley curve #4 over a 185 bit binary field.Not suitable for ECDSA.Questionable extension field! brainpoolP160r1: RFC 5639 curve over a 160 bit prime field brainpoolP160t1: RFC 5639 curve over a 160 bit prime field brainpoolP192r1: RFC 5639 curve over a 192 bit prime field brainpoolP192t1: RFC 5639 curve over a 192 bit prime field brainpoolP224r1: RFC 5639 curve over a 224 bit prime field brainpoolP224t1: RFC 5639 curve over a 224 bit prime field brainpoolP256r1: RFC 5639 curve over a 256 bit prime field brainpoolP256t1: RFC 5639 curve over a 256 bit prime field brainpoolP320r1: RFC 5639 curve over a 320 bit prime field brainpoolP320t1: RFC 5639 curve over a 320 bit prime field brainpoolP384r1: RFC 5639 curve over a 384 bit prime field brainpoolP384t1: RFC 5639 curve over a 384 bit prime field brainpoolP512r1: RFC 5639 curve over a 512 bit prime field brainpoolP512t1: RFC 5639 curve over a 512 bit prime field SM2 : SM2 curve over a 256 bit prime field生成参数文件选择一条曲线生成参数文件openssl ecparam -name secp256k1 -out secp256k1.pem显示参数文件参数openssl ecparam -in secp256k1.pem -text -param_enc explicit -noout使用参数文件生成私钥openssl ecparam -in secp256k1.pem -genkey -out secp256k1-key.key从私钥中导出公钥openssl ec -in secp256k1-key.key -pubout -out public.key参考资料《密码编码学与网络安全》-[美]WilliamStallings著 电子工业出版社《密码学与网络安全》-AtulKahate著 清华大学出版社
-
MD5算法的优缺点
MD5算法的优点:1.计算速度快:MD5算法的计算速度比较快,可以在短时间内完成大量的数据加密;2.安全性高:MD5算法具有较高的安全性,可以有效地防止数据被篡改;3.抗碰撞性强:MD5算法具有较强的抗碰撞性,即使输入的数据相同,也能产生不同的消息摘要;4.可靠性高:MD5算法具有较高的可靠性,可以有效地保证数据的完整性和真实性。MD5算法的缺点:1.抗破解性较弱:MD5算法的抗破解性较弱,即使知道了消息摘要,也无法根据消息摘要反推出原始的输入数据;2.容易被攻击:MD5算法容易受到碰撞攻击,即可以通过构造两个不同的输入数据,使其产生相同的消息摘要;3.不能反向计算:MD5算法不能反向计算,即无法根据消息摘要反推出原始的输入数据。
-
MD5算法的应用实例
一、MD5简介 MD5是一个安全的散列算法,输入两个不同的明文不会得到相同的输出值,根据输出值,不能得到原始的明文,即其过程不可逆;所以要解密MD5没有现成的算法,只能用穷举法,把可能出现的明文,用MD5算法散列之后,把得到的散列值和原始的数据形成一个一对一的映射表,通过比在表中比破解密码的MD5算法散列值,通过匹配从映射表中找出破解密码所对应的原始明文。 对信息系统或者网站系统来说,MD5算法主要用在用户注册口令的加密,对于普通强度的口令加密,可以通过以下三种方式进行破解: (1)在线查询密码。一些在线的MD5值查询网站提供MD5密码值的查询,输入MD5密码值后,如果在数据库中存在,那么可以很快获取其密码值。 (2)使用MD5破解工具。网络上有许多针对MD5破解的专用软件,通过设置字典来进行破解。 (3)通过社会工程学来获取或者重新设置用户的口令。 因此简单的MD5加密是没有办法达到绝对的安全的,因为普通的MD5加密有多种暴力破解方式,因此如果想要保证信息系统或者网站的安全,需要对MD5进行改造,增强其安全性,本文就是在MD5加密算法的基础上进行改进!二、MD5算法的应用(1)用于密码管理当我们需要保存某些密码信息以用于身份确认时,如果直接将密码信息以明码方式保存在数据库中,不使用任何保密措施,系统管理员就很容易能得到原来的密码信息,这些信息一旦泄露,密码也很容易被破译。为了增加安全性,有必要对数据库中需要保密的信息进行加密,这样,即使有人得到了整个数据库,如果没有解密算法,也不能得到原来的密码信息。MD5算法可以很好地解决这个问题,因为它可以将任意长度的输入串经过计算得到固定长度的输出,而且只有在明文相同的情况下,才能等到相同的密文,并且这个算法是不可逆的,即便得到了加密以后的密文,也不可能通过解密算法反算出明文。这样就可以把用户的密码以MD5值(或类似的其它算法)的方式保存起来,用户注册的时候,系统是把用户输入的密码计算成MD5值,然后再去和系统中保存的MD5值进行比较,如果密文相同,就可以认定密码是正确的,否则密码错误。通过这样的步骤,系统在并不知道用户密码明码的情况下就可以确定用户登录系统的合法性。这样不但可以避免用户的密码被具有系统管理员权限的用户知道,而且还在一定程度上增加了密码被破解的难度。(2)电子签名MD5算法还可以作为一种电子签名的方法来使用,使用MD5算法就可以为任何文件(不管其大小、格式、数量)产生一个独一无二的“数字指纹”,借助这个“数字指纹”,通过检查文件前后MD5值是否发生了改变,就可以知道源文件是否被改动。我们在下载软件的时候经常会发现,软件的下载页面上除了会提供软件的下载地址以外,还会给出一串长长的字符串。这串字符串其实就是该软件的MD5值,它的作用就在于下载该软件后,对下载得到的文件用专门的软件(如WindowsMD5check等)做一次MD5校验,以确保我们获得的文件与该站点提供的文件为同一文件。利用MD5算法来进行文件校验的方案被大量应用到软件下载站、论坛数据库、系统文件安全等方面。(3)垃圾邮件筛选在电子邮件使用越来越普遍的情况下,可以利用MD5算法在邮件接收服务器上进行垃圾邮件的筛选,以减少此类邮件的干扰,具体思路如下:建立一个邮件MD5值资料库,分别储存邮件的MD5值、允许出现的次数(假定为3)和出现次数(初值为零)。对每一封收到的邮件,将它的正文部分进行MD5计算,得到MD5值,将这个值在资料库中进行搜索。如未发现相同的MD5值,说明此邮件是第一次收到,将此MD5值存入资料库,并将出现次数置为1,转到第五步。如发现相同的MD5值,说明收到过同样内容的邮件,将出现次数加1,并与允许出现次数相比较,如小于允许出现次数,就转到第五步。否则中止接收该邮件。结束。————————————————版权声明:本文为CSDN博主「cc876」的原创文章
-
MD5算法的安全性分析
MD5是MessageDigestAlgorithm的缩写,译为信息摘要算法,它是Java语言中使用很广泛的一种加密算法。MD5可以将任意字符串,通过不可逆的字符串变换算法,生成一个唯一的MD5信息摘要,这个信息摘要也就是我们通常所说的MD5字符串。那么问题来了,MD5加密安全吗?这道题看似简单,其实是一道送命题,很多人尤其是一些新入门的同学会觉得,安全啊,MD5首先是加密的字符串,其次是不可逆的,所以它一定是安全的。如果你这样回答,那么就彻底掉进面试官给你挖好的坑了。为什么呢?因为答案是“不安全”,而不是“安全”。1.彩虹表MD5之所以说它是不安全的,是因为每一个原始密码都会生成一个对应的固定密码,也就是说一个字符串生成的MD5值是永远不变的。这样的话,虽然它是不可逆的,但可以被穷举,而穷举的“产品”就叫做彩虹表。什么是彩虹表?彩虹表是一个用于加密散列函数逆运算的预先计算好的表,为破解密码的散列值(或称哈希值、微缩图、摘要、指纹、哈希密文)而准备。一般主流的彩虹表都在100G以上。这样的表常常用于恢复由有限集字符组成的固定长度的纯文本密码。这是空间/时间替换的典型实践,比每一次尝试都计算哈希的暴力破解处理时间少而储存空间多,但却比简单的对每条输入散列翻查表的破解方式储存空间少而处理时间多。简单来说,彩虹表就是一个很大的,用于存放穷举对应值的数据表。以MD5为例,“1”的MD5值是“C4CA4238A0B923820DCC509A6F75849B”,而“2”的MD5值是“C81E728D9D4C2F636F067F89CC14862C”,那么就会有一个MD5的彩虹表是这样的:原始值加密值1C4CA4238A0B923820DCC509A6F75849B2C81E728D9D4C2F636F067F89CC14862C......大家想想,如果有了这张表之后,那么我就可以通过MD5的密文直接查到原始密码了,所以说数据库如果只使用MD5加密,这就好比用了一把插了钥匙的锁一样不安全。2.解决方案想要解决以上问题,我们需要引入“加盐”机制。盐(Salt):在密码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为“加盐”。说的通俗一点“加盐”就像炒菜一样,放不同的盐,炒出菜的味道就是不同的,咱们之前使用MD5不安全的原因是,每个原始密码所对应的MD5值都是固定的,那我们只需要让密码每次通过加盐之后,生成的最终密码都不同,这样就能解决加密不安全的问题了。3.实现代码加盐是一种手段、是一种解决密码安全问题的思路,而它的实现手段有很多种,我们可以使用框架如SpringSecurity提供的BCrypt进行加盐和验证,当然,我们也可以自己实现加盐的功能。本文为了让大家更好的理解加盐的机制,所以我们自己来动手来实现一下加盐的功能。实现加盐机制的关键是在加密的过程中,生成一个随机的盐值,而且随机盐值尽量不要重复,这时,我们就可以使用Java语言提供的UUID(UniversallyUniqueIdentifier,通用唯一识别码)来作为盐值,这样每次都会生成一个不同的随机盐值,且永不重复。加盐的实现代码如下:import org.springframework.util.DigestUtils;import org.springframework.util.StringUtils;import java.util.UUID; public class PasswordUtil { /** * 加密(加盐处理) * @param password 待加密密码(需要加密的密码) * @return 加密后的密码 */ public static String encrypt(String password) { // 随机盐值 UUID String salt = UUID.randomUUID().toString().replaceAll("-", ""); // 密码=md5(随机盐值+密码) String finalPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes()); return salt + "$" + finalPassword; }}从上述代码我们可以看出,加盐的实现具体步骤是:使用UUID产生一个随机盐值;将随机盐值+原始密码一起MD5,产生一个新密码(相同的原始密码,每次都会生成一个不同的新密码);将随机盐值+"$"+上一步生成的新密码加在一起,就是最终生成的密码。那么,问题来了,既然每次生成的密码都不同,那么怎么验证密码是否正确呢?要验证密码是否正确的关键是需要先获取盐值,然后再使用相同的加密方式和步骤,生成一个最终密码和和数据库中保存的加密密码进行对比,具体实现代码如下:import org.springframework.util.DigestUtils;import org.springframework.util.StringUtils;import java.util.UUID; public class PasswordUtil { /** * 加密(加盐处理) * @param password 待加密密码(需要加密的密码) * @return 加密后的密码 */ public static String encrypt(String password) { // 随机盐值 UUID String salt = UUID.randomUUID().toString().replaceAll("-", ""); // 密码=md5(随机盐值+密码) String finalPassword = DigestUtils.md5DigestAsHex((salt + password).getBytes()); return salt + "$" + finalPassword; } /** * 解密 * @param password 要验证的密码(未加密) * @param securePassword 数据库中的加了盐值的密码 * @return 对比结果 true OR false */ public static boolean decrypt(String password, String securePassword) { boolean result = false; if (StringUtils.hasLength(password) && StringUtils.hasLength(securePassword)) { if (securePassword.length() == 65 && securePassword.contains("$")) { String[] securePasswordArr = securePassword.split("\\$"); // 盐值 String slat = securePasswordArr[0]; String finalPassword = securePasswordArr[1]; // 使用同样的加密算法和随机盐值生成最终加密的密码 password = DigestUtils.md5DigestAsHex((slat + password).getBytes()); if (finalPassword.equals(password)) { result = true; } } } return result; }}总结只是简单的使用MD5加密是不安全的,因为每个字符串都会生成固定的密文,那么我们就可以使用彩虹表将密文还原出来,所以它不是安全的。想要解决这个问题,我们需要通过加盐的手段,每次生成一个不同的密码,就把这个问题解决了。————————————————版权声明:本文为CSDN博主「mark10!」的原创文章,遵循CC4.0BY-SA版权协议原文链接:https://blog.csdn.net/m0_48144113/article/details/127426737
-
MD5加密算法的实现
MD5加密算法的实现主要分为以下几个步骤:将输入的数据按照512位(64字节)分组,每组16个字节;对每组数据进行4轮处理,每轮处理16次;将4轮处理的结果与初始的4个32位的链接变量进行异或运算;将最终的4个32位的链接变量转换成128位的消息摘要。