首页 » 网站推广 » phpdesede向量技巧_Java教程一文详解信息安然的密码学

phpdesede向量技巧_Java教程一文详解信息安然的密码学

访客 2024-12-10 0

扫一扫用手机浏览

文章目录 [+]

本文中提到的密码是什么呢?实际上,密码(cryptography)是一个极其弘大繁芜的信息处理体系,涉及到信息的机密性、完全性、认证、不可否认性等浩瀚方面,由此衍生出的很多保护我们信息安全的技能,这些技能我们一样平常统称为密码技能。
密码技能是密码学的核心。

数学与密码技能的关系:数学是密码技能的根本,繁芜的密码技能每每都会涉及到繁芜的数学公式。

phpdesede向量技巧_Java教程一文详解信息安然的密码学

密码学:密码学是网络安全、信息安全、区块链等领域的根本,常见的对称密码、公钥密钥、散列函数等,都属于密码学范畴。
密码学中的密码技能比如“密码”可以让窃听者无法解读盗取的信息,“单项散列函数”可以检测出是否被修改,“数字署名”可以确定是否来源于合法的发送者。

phpdesede向量技巧_Java教程一文详解信息安然的密码学
(图片来自网络侵删)
三、信息安全1. 观点

信息安全是指信息网络的硬件、软件及其系统中的数据受到保护,不受有时的或者恶意的缘故原由而遭到毁坏 、 变动 、透露、否认等,系统连续可靠正常地运行,信息做事不中断。
信息安全安全是建立在以密码技能为根本的打算机安全领域,辅以通信技能、打算机技能与网络技能等方面的内容。

2. 与密码学的关系密码学是保障信息安全的核心技能 ,但不是供应信息安全的唯一办法 。
信息安全是密码学研究与发展的目的 。
信息安全的理论根本是密码学,信息安全的问题根本办理每每依赖密码学理论 。
3. 密码学与信息安全知识不要利用保密的密码算法利用低强度的密码比不进行加密更危险任何密码总有一天会被破解密码只是信息安全的一部分四、当代密码学体系

信息安全及密码学技能,是全体信息技能的基石。
在西方语文中,密码学一词源于希腊语,krypto意思是隐蔽,graphene是书写的意思。
密码学的发展统共经历了四个阶段:远古密码、古典密码、近代密码和当代密码,这四个阶段的发展历史详细先容可拜会文章末了的附录部分,接下来本文内容紧张先容的是当代密码学所涉及到的密码知识。

1. 信息安全威胁与密码技能

该图完全的展示了信息安全面临的威胁与办理方案中会用到的密码技能,本文侧重于先容有关于担保数据机密性的密码技能。

2. 密码算法及主要观点

将明文通过处理变换为密文的规则称为加密算法,将密文规复成明文的规则称为解密算法,加密解密一起称为密码算法。

明文 (Plaintext): 信息的原始数据密文(Ciphertext):明文经由编码变换所天生的数据加密(Encryption):对明文进行编码变换天生密文的过程解密(Decryption):将密文规复成明文的过程密钥:密码算法须要用到密钥的,密钥就相称于保险库大门的钥匙,主要性不言而喻,以是牢记不要透露密码的密钥。
密钥 (Key):掌握明文与密文之间相互变换的,分为加密密钥和解密密钥。
3. ASCII编码

ASCII码 是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646 。
在这个页面,你可以找到8位的256个字符、ASCII码表和Windows-1252 (code page 1252,它是国际标准ISO 8859-1的一个扩展字符集) 标准保持同等;

ASCII码 是 American Standard Code for Information Interchange 的缩写,而不是ASCⅡ(罗马数字2),有很多人在这个地方产生误解;

ASCII码 规范于1967年第一次发布,末了一次更新是在1986年,它包含了33个掌握字符(具有某些分外功能但是无法显示的字符)和95个可显示字符;

ASCII码大致可以分作三部分组成。

第一部分是:ASCII非打印掌握字符 第二部分是:ASCII打印字符 第三部分是:扩展ASCII打印字符

3.1 第一部分:ASCII非打印掌握字符表

ASCII表上的数字0–31分配给了掌握字符,用于掌握像打印机等一些外围设备。
例如,12代表换页/新页功能。
此命令指示打印机跳到下一页的开头。
(参详ASCII码表中0-31)

3.2 第二部分:ASCII打印字符

数字 32–126 分配给了能在键盘上找到的字符,当您查看或打印文档时就会涌现。
数字127代表 DELETE 命令。
(参详ASCII码表中32-127)

3.3 第三部分:扩展ASCII打印字符

扩展的ASCII字符知足了对更多字符的需求。
扩展的ASCII包含ASCII中已有的128个字符(数字0–32显示不才图中),又增加了128个字符,统共是256个。
纵然有了这些更多的字符,许多措辞还是包含无法压缩到256个字符中的符号。
因此,涌现了一些ASCII的变体来席卷地区性字符和符号。
例如,许多软件程序把ASCII表(又称作ISO8859-1)用于北美、西欧、澳大利亚和非洲的措辞。

4. 字符串的ASCII码与二进制位

public class ASCIITest { @Test public void test01() { String str = "heima"; byte[] bytes = str.getBytes(); for (byte b : bytes) { //打印ascii码 System.out.println(b); //获取二进制位 String s = Integer.toBinaryString(b); System.out.println(s); } } @Test public void test02() throws UnsupportedEncodingException { String str = "黑马"; //中文UTF-8编码一个汉字占3个字节,中文GBK编码一个汉字占2个字节。
byte[] bytes = str.getBytes("UTF-8"); System.out.println("字节个数:"+ bytes.length); char[] chars = str.toCharArray(); for (char c : chars) { //打印字符 System.out.println(c); //字符类型会自动提升为int类型,获取二进制值(10进制转二进制) String s = Integer.toBinaryString(c); System.out.println(s); } }}
5. Hex编码与Base64编码

我们知道在打算机中的字节共有256个组合,对应便是ascii码,而ascii码的128~255之间的值是不可见字符。
而在网络上交流数据时,比如说从A地传到B地,每每要经由多个路由设备,由于不同的设备对字符的处理办法有一些不同,这样那些不可见字符就有可能被处理缺点,这是不利于传输的。
以是我们须要将字节转为精确的课可见字符,须要对字节数组进行进一步编码,常用编码格式用Hex编码和Base64编码。

5.1 Hex编码

1字节=8位2进制,比如小写字母a,ASCII表对应十进制为97,二进制表示为01100001

1字节=2位16进制,比如小写字母a,ASCII表对应十进制为97, 十六进制表示为61

由于一个字节中存在8个 bit可以表示256个字符,而非扩展 ASCII 码只能表示0-127种字符,为了能完全地表示一个字节,可以将二进制数据转换为十六进制数据的办法来实现。
以是 Hex 编码也被称作为 Base16 编码,比较于原来8位表示一个字节,Hex 编码能够只用2位表示一个字节。
Hex 编码最常用于二进制文件查看时展示的编码,如010Editor 就可以支持查看二进制文件。
利用16个可见字符来表示一个二进制数组,编码后数据大小将x21个字符须要用2个可见字符来表示5.1.1 代码示例

引入依赖

<dependencies> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.14</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.5</version> <scope>test</scope> </dependency> </dependencies>

单元测试:

public class HexDemoTest { @Test public void test01() { String data = "itcast" ; byte[] bytes = data.getBytes() ; //测试hex String encoded = Hex.encodeHexString(bytes) ; System.out.println(encoded); }} 5.2 base64编码Base64编码哀求把3个8位字节(3乘8=24)转化为4个6位的字节(4乘6=24),之后在6位的前面补两个0,形成8位一个字节的形式。
如果剩下的字符不敷3个字节,则用0添补,输出字符利用'=',因此编码后输出的文本末端可能会涌现1或2个'='。
为了担保所输出的编码位可读字符,Base64制订了一个编码表,以便进行统一转换。
编码表的大小为2^6=64,这也是Base64名称的由来。
标准base64只有64个字符(大写A到Z、小写a到z、数字0到9、“+”和“/”)以及用作后缀等号;Base64是网络上最常见的用于传输8Bit字节码的可读性编码算法之一以每 3 个 字符(1Byte=8bit)为一组,然后针对每组,首先获取每个字符的 ASCII 编码(字符'a'=97=01100001),然后将 ASCII 编码转换成 8 bit 的二进制,得到一组 3 8=24 bit 的字节。
然后再将这 24 bit 划分为 4 个 6 bit 的字节,并在每个 6 bit 的字节前面都填两个高位 0,得到 4 个 8 bit 的字节,然后将这 4 个 8 bit 的字节转换成十进制,对照 BASE64 编码表 (下表),得到对应编码后的字符。
利用64个可见字符来表示一个二进制数组,编码后数据大小变成原来的4/33个字符用4个可见字符来表示

5.2.1 事理示例1-足够三字节

第一步:"jay"、“a”、"n"对应的ASCII码值分别为106,97,121,对应的二进制值是01101010、01100001、01111001。
如图第二三行所示,由此组成一个24位的二进制字符串。
第二步:如图第四行,将24位每6位二进制位一组分成四组。
第三步:在上面每一组前面补两个0(赤色背景),扩展成32个二进制位,此时变为四个字节:00011010、00100110、00000101、00111001。
分别对应的值(Base64编码索引)为:26、38、5、57。
第四步:用上面的值在Base64编码表中进行查找,分别对应:a、m、F、5。
因此“jay”Base64编码之后就变为:amF5。
5.2.2 代码示例1-足够三字节

单元测试:

public class Base64DemoTest { @Test public void test01() { //jay恰好三个字节,编码后输出的结果没有= System.out.println(Base64.encodeBase64String("jay".getBytes())); }}5.2.3 事理示例2-不足三字节

如果字节不敷三个怎么办,分组的时候不组8位的都补0,打算没结果的=号代替

5.2.4 代码示例2-不足三字节

单元测试:

public class Base64Demo { @Test public void test02() { //ja不足三个字节,编码后一定会有= System.out.println(Base64.encodeBase64String("ja".getBytes())); }}5.3 代码示例-编码与解码

单元测试:

/ hex编码与base64编码测试 /public class HexAndBase64Test { @Test public void test() throws DecoderException { String data = "黑马程序员" ; byte[] bytes = data.getBytes() ; //测试hex String encryStr = Hex.encodeHexString(bytes) ; String decryStr = new String(Hex.decodeHex(encryStr.toCharArray())) ; System.out.println("Hex编码解码:"+ encryStr + " | " + decryStr) ; //测试base64 encryStr = Base64.encodeBase64String(bytes) ; decryStr = new String(Base64.decodeBase64(encryStr.getBytes()) ); System.out.println("Base64编码解码:"+ encryStr + " | " + decryStr) ; }}

上面我们已经看到了Base64便是用6位(2的6次幂便是64)表示字符,因此成为Base64。
同理,Base32便是用5位,Base16便是用4位。

比拟: hex编码速率快,体历年夜;base64编码速率慢,体积小

6. 密码分类6.1 对称密码

加密密钥和解密密钥相同,又称传统密码系统编制、共享密钥密码系统编制、秘密密钥系统编制或单密钥系统编制。
从密钥利用办法上分为分组密码和序列密码 ,这点后文会有先容。

对称加密算法的优点:算法公开、打算量小、加密速率快、加密效率高。

对称加密算法的缺陷:交易双方都利用同样钥匙,安全性得不到担保。
此外,每对用户每次利用对称加密算法时,都须要利用其他人不知道的惟一钥匙,这会使得发收信双方所拥有的钥匙数量呈几何级数增长,密钥管理成为用户的包袱。
对称加密算法在分布式网络系统上利用较为困难,紧张是由于密钥管理困难,利用本钱较高。

对称加密常日利用的是相对较小的密钥,一样平常小于256 bit。
由于密钥越大,加密越强,但加密与解密的过程越慢。
如果你只用1 bit来做这个密钥,那黑客们可以先试着用0来解密,弗成的话就再用1解;但如果你的密钥有1 MB大,黑客们可能永久也无法破解,但加密和解密的过程要花费很长的韶光。
密钥的大小既要照顾到安全性,也要照顾到效率,是一个trade-off。

常用对称加密算法

DES(Data Encryption Standard):数据加密标准,速率较快,适用于加密大量数据的场合。
3DES(Triple DES):是基于DES,对一块数据用三个不同的密钥进行三次加密,强度更高。
AES(Advanced Encryption Standard):高等加密标准,是下一代的加密算法标准,速率快,安全级别高,支持128、192、256、512位密钥的加密。

算法特色

加密方和解密方利用同一个密钥,一旦密钥文件泄露, 就会导致数据暴露加密解密的速率比较快,适宜数据比较永劫的利用,可以加密大文件密钥传输的过程不屈安,且随意马虎被破解,密钥管理也比较麻烦。
加密后编码表找不到对应字符, 涌现乱码一样平常结合Base64利用6.1.1 DESDES是1997年美国联邦信息处理标准中所采取的一种对称密码算法,一贯以来被美国以及其他国家确当局和银行等广泛采取。
随着打算机的快速发展,DES已经被暴力破解,1997年用时96天破译密钥,1998年41天破译密钥,到了1999年只用22小时15分钟就可以破译。
DES技能是一种将64比特的明文加密成64比特的密文的对称密码算法,因此理论上来讲,他的密钥长度也是64位,但由于在DES的密钥中每隔7比特,就会设置一个用于缺点检讨的比特,以是实际上DES的密钥的长度只有56比特。
DES因此64比特的明文(比特序列)为一个单位进行加密,这64比特的单位成为分组,一样平常来说,以分组为单位进行处理的密码算法称为分组密码。
DES每次每次只能加密64比特的数据,如果要加密的明文比较长,就须要对DES加密进行迭代(反复),而迭代的详细方案就称为模式。

Java中有关对称和非对称加密的核心类:javax.crypto.Cipher

代码示例

/ DES加密算法测试 /public class DesTest { / 测试DES加密 / @Test public void testEncrypt() throws Exception { //明文 String text = "黑马程序员"; //密钥,长度必须为8个字节(字符) byte[] secretKeyBytes = "12345678".getBytes(); //secretKeyBytes = generateSecretKey("DES", 56); // Cipher:获取密码工具,参数按"算法/模式/添补模式" Cipher cipher = Cipher.getInstance("DES"); // 参数1:密钥,key的字节数组,参数2:加密算法 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "DES"); //加密工具初始化数据,参数1:模式,有加密模式和解密模式,参数2:密钥规则 cipher.init(Cipher.ENCRYPT_MODE,sks); //实行加密,得到加密结果 byte[] bytes = cipher.doFinal(text.getBytes()); //输出字节,由于ascii码有负数,解析不出来,以是乱码 //将byte数组转成ASCII编码,必须确保byte数组的值在ASCII的可视字符范围,否则会涌现乱码, //由于ASCII的取值范围比byte小,byte的取值范围是-128到127 for (byte b : bytes) { System.out.println(b); } // 打印密文 System.out.println(new String(bytes)); //将byte数组转成Base64编码。
String result = Base64.encodeBase64String(bytes); System.out.println("加密后的值:" + result); } / 测试DES解密 / @Test public void testDecrypt() throws Exception { //密文 String crpyt = "+rBmhkThnKQf8IJTM/qmMA=="; //密钥,长度必须为8个字节(字符) byte[] secretKeyBytes = "12345678".getBytes(); //获取Cipher工具 Cipher cipher = Cipher.getInstance("DES"); // 指定密钥规则 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "DES"); cipher.init(Cipher.DECRYPT_MODE, sks); //解密,上面利用的base64编码,下面直接用密文 byte[] bytes = cipher.doFinal(Base64.decodeBase64(crpyt)); // 由于是明文,以是直接返回 String text = new String(bytes); System.out.println("解密后的值:"+ text) ; } / 天生密钥 @param algorithm 算法 @param len 密钥长度 / public static byte[] generateSecretKey(String algorithm, int len) throws NoSuchAlgorithmException { KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);//密钥天生器 keyGenerator.init(len);//密钥长度 SecretKey secretKey = keyGenerator.generateKey();//天生密钥 return secretKey.getEncoded(); //密钥字节数组转字符串 }}
6.1.2 3DES三重DES,是为了加强DES的强度,将DES重复3次所得到的一种密码算法。
明文需经由3次DES处理才能得到末了密文,由于DES密钥实际长度为56比特,因此3DES的密钥密钥实际长度便是563=168比特。
通过增加迭代次数提高安全性,常运用在银行等金融机构。
DES密钥长度是8字节(64比特),3DES密钥长度是24字节(192比特)三重DES不是进行三次DES加密(加密-加密-加密),而是加密-解密-加密的过程。
加密过程:用第一支密钥对原文进行加密,再利用第二支密钥对第一步操作后的信息进行解密,末了利用第三支密钥对第二步操作后的信息进行加密得到终极密文。
解密过程:用第三支密钥对密文进行解密,再采取第二支密钥进行加密,末了采取第一支密钥解密得到原文。
三重DES中所有密钥都相同时,三重DES等同于普通DES,由于前两步加密解密后得到的是原来的明文。
EDE:表示加密(Encryption)-> 解密(Decryption)->加密(Encryption)这个流程。
缺陷:处理速率较慢、密钥打算韶光较长、加密效率不高。

/ 3DES加密算法测试 /public class Des3Test { / 测试3DES加密 / @Test public void testEncrypt() throws Exception { //明文 String text = "黑马程序员"; //密钥,长度必须24个字节(字符) byte[] secretKeyBytes = "123456781234567812345678".getBytes(); //可指定密钥实际长度是168 //secretKeyBytes = generateSecretKey("DESede", 168); // Cipher:获取密码工具,参数按"算法/模式/添补模式" Cipher cipher = Cipher.getInstance("DESede"); // 参数1:密钥,key的字节数组,参数2:加密算法 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "DESede"); //加密工具初始化数据,参数1:模式,有加密模式和解密模式,参数2:密钥规则 cipher.init(Cipher.ENCRYPT_MODE,sks); //实行加密,得到加密结果 byte[] bytes = cipher.doFinal(text.getBytes()); //将byte数组转成Base64编码。
String result = Base64.encodeBase64String(bytes); System.out.println("加密后的值:" + result); } / 测试3DES解密 / @Test public void testDecrypt() throws Exception { //密文 String crpyt = "+rBmhkThnKQf8IJTM/qmMA=="; //密钥,长度必须24个字节(字符) byte[] secretKeyBytes = "123456781234567812345678".getBytes(); //获取Cipher工具 Cipher cipher = Cipher.getInstance("DESede"); // 指定密钥规则 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "DESede"); cipher.init(Cipher.DECRYPT_MODE, sks); //解密,上面利用的base64编码,下面直接用密文 byte[] bytes = cipher.doFinal(Base64.decodeBase64(crpyt)); // 由于是明文,以是直接返回 String text = new String(bytes); System.out.println("解密后的值:"+ text) ; } / 天生密钥 @param algorithm 算法 @param len 密钥长度 / public static byte[] generateSecretKey(String algorithm, int len) throws NoSuchAlgorithmException { KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);//密钥天生器 keyGenerator.init(len);//密钥长度 SecretKey secretKey = keyGenerator.generateKey();//天生密钥 return secretKey.getEncoded(); //密钥字节数组转字符串 }}
6.1.3 AESAES(Advanced Encryption Standard)是取代其前任标准(DES)而称为新标准的一种对称算法。
AES分组长度为128比特,密钥长度有128、192、256比特三种,AES-128、AES192和AES-256。
至今还没有有效破解AES的办法

还是之前的代码,更换密钥值和加密算法即可

/ AES加密算法测试 /public class AesTest { / 测试AES加密 / @Test public void testEncrypt() throws Exception { //明文 String text = "黑马程序员"; //密钥,长度必须为16个字节(字符) byte[] secretKeyBytes = "1234567812345678".getBytes(); //密钥实际长度128比特 //secretKeyBytes = generateSecretKey("AES", 128); // Cipher:获取密码工具,参数按"算法/模式/添补模式" Cipher cipher = Cipher.getInstance("AES"); // 参数1:密钥,key的字节数组,参数2:加密算法 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "AES"); //加密工具初始化数据,参数1:模式,有加密模式和解密模式,参数2:密钥规则 cipher.init(Cipher.ENCRYPT_MODE,sks); //实行加密,得到加密结果 byte[] bytes = cipher.doFinal(text.getBytes()); //将byte数组转成Base64编码。
String result = Base64.encodeBase64String(bytes); System.out.println("加密后的值:" + result); } / 测试AES解密 / @Test public void testDecrypt() throws Exception { //密文 String crpyt = "j9qMqmunoPEtMRpNYPWfCw=="; //密钥,长度必须为16个字节(字符) byte[] secretKeyBytes = "1234567812345678".getBytes(); //获取Cipher工具 Cipher cipher = Cipher.getInstance("AES"); //指定密钥规则 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "AES"); cipher.init(Cipher.DECRYPT_MODE, sks); //解密,上面利用的base64编码,下面直接用密文 byte[] bytes = cipher.doFinal(Base64.decodeBase64(crpyt)); //由于是明文,以是直接返回 String text = new String(bytes); System.out.println("解密后的值:"+ text) ; } / 天生密钥 @param algorithm 算法 @param len 密钥长度 / public static byte[] generateSecretKey(String algorithm, int len) throws NoSuchAlgorithmException { KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);//密钥天生器 keyGenerator.init(len);//密钥长度 SecretKey secretKey = keyGenerator.generateKey();//天生密钥 return secretKey.getEncoded(); //密钥字节数组转字符串 }}
6.1.4 破解AES的难度

据统计,完备破解要花费时长为2104亿年,花费电量1.1201 10^22 kWh,电费1.368 10^13 亿美元

6.1.5 选用哪一种?

DES已被破解不要再利用,3DES在部分金融机构内还有在利用将来会被AES取代,推举利用AES。

6.2 分组密码6.2.1 观点

按对明文的处理办法,密码算法可以分为分组密码( Blok cipher)和流密码(Stream cipher)。

6.2.2 分组密码:也叫块加密(block cyphers),每次只能处理特定长度的一块数据的密码算法,“一块”称为分组,一个分组的比特数便是分组长度。
一次加密明文中的一个块,将明文按一定的位长分组,明文组经由加密运算得到密文组,密文组经由解密运算(加密运算的逆运算),还原成明文组。
比如:DES和3DES的分组长度都是64比特,一次性只能加密64比特的明文并天生64比特的密文。

6.2.3 序列密码:也叫流加密(stream cyphers),对数据流进行连续处理的密码算法,是指利用少量的密钥(制乱元素)通过某种繁芜的运算(密码算法)产生大量的伪随机位流,用于对明文位流的加密。
解密是指用同样的密钥和密码算法及与加密相同的伪随机位流,用以还原明文位流。
流密码中一样平常以1比特、8比特或32比特等为单位进行加解密。

6.2.4 比拟:分组密码处理一个分组就结束,无需通过内部状态记录加密进度;流密码是对一串数据流进行连续处理,须要保持内部状态。

前文所提到的DES、3DES、AES等大部分对称加密算法都属于分组密码。
流密码的范例例子有一次性密码本。

本文内容紧张讲解的是分组密码。

6.2.2 加密模式

分组算法只能加密固定长度的分组,但有时加密的明文长度会超过分组密码的分组长度,此时就须要对分组密码进行迭代,以便将一段很长的明文全部加密。
迭代的方法就称为分组密码的加密模式(model)。

加密模式的种类:常见的有ECB模式(电子密码本模式)、CBC模式(密码分组链接模式)、CTR模式(计数器模式)等,本课中重点解释ECB模式和CBC模式。

6.2.3 明文分组与密文分组

明文分组: 分组密码算法中作为加密工具的明文。
明文分组的长度与分组密码算法的分组长度相等。

密文分组:分组加密算法中对明文分组加密之后产生的密文。

6.2.4 ECB与CBC1) ECB

ECB加密模式:须要加密的明文按照块密码的块大小被分为数个块(组),并对每个块进行独立加密。
明文分组与密文分组是逐一对应的关系,每个明文分组都各自独立地进行加密和解密。
如果明文中存在多个相同的明文分组,那么明文分组将被转换为相同的密文分组,这样的话可以通过不雅观察密文来推测出明文的组合,从而可能破译密码,以是ECB模式存在一定风险。

ECB的一个非常大的弱点便是可以在不破译密文的情形下操作明文,比如银行转账例子中:付款人、收款人、转账金额分别可以对应三个明文分组,分别加密对应三个密文分组,如果将收款人密文分组和付款人密文分组顺序调换,那么全体银行转行的操作便是完备相反的。
也便是说在ECB模式中,只要对任意密文分组进行更换,对应的明文分组也会被替,如果直接将密文分组删除,那么明文分组也会被删除,如果对密文分组卖力,那么明文分组也会被复制。

由于ECB模式的巨大漏洞,作为程序员,牢记千万不能利用ECB模式进行加解密。

2) CBC

CBC加密模式:密文分组像链条一样拼接在一起,详细过程是首先将明文分组与前一个密文分组进行XOR运行,然后在进行加密。

比拟ECB模式和CBC模式个中一个分组的加密过程,创造他们的差异在于ECB模式只进行了加密,而CBC模式在加密之提高行了一次XOR运算。

CBC模式在加密一个明文分组时,由于不存在前一个密文分组,以是须要提前准备好一个长度为一个分组的比特序列来当做前一个密文分组,这个比特序列称为初始化向量(initialization vector),缩写是IV。
每次加密时都会随机产生一个不同的比特序列当做初始化向量。

CBC模式就算是明文分组中的某两个组比如分组1和明文分组2值相等,由于有XOR运算。
密文分组1和2的值也不一定相等。
以是CBC模式不存在ECB模式中的毛病。

由于CBC模式的安全性,CBC被运用在在互联网安全通信协议IPsec中,在此协议中紧张利用了3DES-CBC以及AES-CBC,CBC模式还被运用在Kerberos verson 5的认证系统中。

6.2.5 添补模式

大多数密码算法都是块密码算法,须要将明文切成固定大小的块,一块一块地进行加密。
例如DES就须要将切割成一个个64位的块。
如果长度不是64的整数倍,末了一个块就不足64位,这时就要对末了一个块进行添补。
添补办法有很多种,如果加密时以某种办法添补,解密时就得利用这种添补办法并去除添补内容。

NoPadding

不添补,在DES加密算法下, 哀求原文长度必须是8byte的整数倍,在AES加密算法下, 哀求原文长度必须是16byte的整数倍

PKCS5Padding

数据块的大小为8位, 不足就补足

6.2.6 Java的运用

有关加密模式与添补模式,在Java中的运用,有如下几点须要把稳

javax.crypto.Cipher类是Java中供应加密和解密功能的核心类,Cipher工具创建的办法有如下两种:Cipher c = Cipher.getInstance("算法/模式/添补");或Cipher c = Cipher.getInstance("算法")默认情形下, 加密模式和添补模式为 : ECB/PKCS5Padding如果利用CBC模式, 在初始化Cipher工具时, 须要增加参数, 初始化向量IV : IvParameterSpec iv = new IvParameterSpec(key.getBytes());Cipher创建的第一种办法中,参数一样平常称为转换名,转换名由"算法/模式/添补"构成。
Java平台的每个实现都须要支持以下标准Cipher转换:- `AES/CBC/NoPadding` (128) - `AES/CBC/PKCS5Padding` (128) - `AES/ECB/NoPadding` (128) - `AES/ECB/PKCS5Padding` (128) - `DES/CBC/NoPadding` (56) - `DES/CBC/PKCS5Padding(56)` - `DES/ECB/NoPadding(56)` - `DES/ECB/PKCS5Padding` (56) - `DESede/CBC/NoPadding` (168) - `DESede/CBC/PKCS5Padding` (168) - `DESede/ECB/NoPadding` (168) - `DESede/ECB/PKCS5Padding` (168) - `RSA/ECB/PKCS1Padding` ( `1024,2048` ) - `RSA/ECB/OAEPWithSHA-1AndMGF1Padding` ( `1024,2048` ) - `RSA/ECB/OAEPWithSHA-256AndMGF1Padding` ( `1024,2048` )6.2.7 改进DES示例

将DesTest类中,加密测试用例里只改动一行,改动获取Cipher的办法改为:

Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");

运行加密测试用例多次,创造每次加密结果都不一样,是由于初始向量IV由于加密时我们没有指定,以是会每次加密的时候系统随机天生IV,将每次加密后的值都拿去解密,创造全部解密失落败,由于解密时须要IV值却不知道IV值是什么。
以是程序须要进一步改进为加密时指定IV值,以方便解密时利用同样的IV值来解密。

再次改进加密和解密都是用相同的IV值:

/ DES加密算法测试 /public class DesTest { / 测试DES加密 / @Test public void testEncrypt() throws Exception { //明文 String text = "黑马程序员"; //密钥,长度必须为8个字节(字符) byte[] secretKeyBytes = "12345678".getBytes(); //secretKeyBytes = generateSecretKey("DES", 56); // Cipher:获取密码工具,参数按"算法/模式/添补模式" Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); // 参数1:密钥,key的字节数组,参数2:加密算法 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "DES"); //加密工具初始化数据,参数1:模式,有加密模式和解密模式,参数2:密钥规则,参数3:IV初始向量值 IvParameterSpec iv = new IvParameterSpec("22446688".getBytes()); cipher.init(Cipher.ENCRYPT_MODE, sks, iv); //实行加密,得到加密结果 byte[] bytes = cipher.doFinal(text.getBytes()); //将byte数组转成Base64编码。
String result = Base64.encodeBase64String(bytes); System.out.println("加密后的值:" + result); } / 测试DES解密 / @Test public void testDecrypt() throws Exception { //密文 String crpyt = "FeHL4fKM/N1RSYOKJJ6ZZQ=="; //密钥,长度必须为8个字节(字符) byte[] secretKeyBytes = "12345678".getBytes(); //获取Cipher工具 Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); // 指定密钥规则 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "DES"); //加密工具初始化数据,参数1:模式,有加密模式和解密模式,参数2:密钥规则,参数3:IV初始向量值 IvParameterSpec iv = new IvParameterSpec("22446688".getBytes()); cipher.init(Cipher.DECRYPT_MODE, sks, iv); //解密,上面利用的base64编码,下面直接用密文 byte[] bytes = cipher.doFinal(Base64.decodeBase64(crpyt)); // 由于是明文,以是直接返回 String text = new String(bytes); System.out.println("解密后的值:"+ text) ; } / 天生密钥 @param algorithm 算法 @param len 密钥长度 / public static byte[] generateSecretKey(String algorithm, int len) throws NoSuchAlgorithmException { KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);//密钥天生器 keyGenerator.init(len);//密钥长度 SecretKey secretKey = keyGenerator.generateKey();//天生密钥 return secretKey.getEncoded(); //密钥字节数组转字符串 }}

3DS、AES的改进思路类似:第一步修正转换为DESede/CBC/PKCS5Padding、AES/CBC/PKCS5Padding,第二步在加密和解密的时候设置初始化向量为同一值。

3DES终极代码:

/ 3DES加密算法测试 /public class Des3Test { / 测试3DES加密 / @Test public void testEncrypt() throws Exception { //明文 String text = "黑马程序员"; //密钥,长度必须24个字节(字符) byte[] secretKeyBytes = "123456781234567812345678".getBytes(); //可指定密钥长度是168 //secretKeyBytes = generateSecretKey("DESede", 168); // Cipher:获取密码工具,参数按"算法/模式/添补模式" Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding"); //参数1:密钥,key的字节数组,参数2:加密算法 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "DESede"); //加密工具初始化数据,参数1:模式,有加密模式和解密模式,参数2:密钥规则,参数3:IV初始向量值 IvParameterSpec iv = new IvParameterSpec("22446688".getBytes()); cipher.init(Cipher.ENCRYPT_MODE, sks, iv); //实行加密,得到加密结果 byte[] bytes = cipher.doFinal(text.getBytes()); //将byte数组转成Base64编码。
String result = Base64.encodeBase64String(bytes); System.out.println("加密后的值:" + result); } / 测试3DES解密 / @Test public void testDecrypt() throws Exception { //密文 String crpyt = "FeHL4fKM/N1RSYOKJJ6ZZQ=="; //密钥,长度必须24个字节(字符) byte[] secretKeyBytes = "123456781234567812345678".getBytes(); // 获取Cipher工具 Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding"); // 指定密钥规则 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "DESede"); //加密工具初始化数据,参数1:模式,有加密模式和解密模式,参数2:密钥规则,参数3:IV初始向量值 IvParameterSpec iv = new IvParameterSpec("22446688".getBytes()); cipher.init(Cipher.DECRYPT_MODE, sks, iv); // 解密,上面利用的base64编码,下面直接用密文 byte[] bytes = cipher.doFinal(Base64.decodeBase64(crpyt)); // 由于是明文,以是直接返回 String text = new String(bytes); System.out.println("解密后的值:"+ text) ; } / 天生密钥 @param algorithm 算法 @param len 密钥长度 / public static byte[] generateSecretKey(String algorithm, int len) throws NoSuchAlgorithmException { KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);//密钥天生器 keyGenerator.init(len);//密钥长度 SecretKey secretKey = keyGenerator.generateKey();//天生密钥 return secretKey.getEncoded(); //密钥字节数组转字符串 }}

AES终极代码

/ AES加密算法测试 /public class AesTest { / 测试AES加密 / @Test public void testEncrypt() throws Exception { //明文 String text = "黑马程序员"; //密钥,长度必须为16个字节(字符) byte[] secretKeyBytes = "1234567812345678".getBytes(); //secretKeyBytes = generateSecretKey("AES", 128); // Cipher:获取密码工具,参数按"算法/模式/添补模式" Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 参数1:密钥,key的字节数组,参数2:加密算法 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "AES"); //加密工具初始化数据,参数1:模式,有加密模式和解密模式,参数2:密钥规则,参数3:IV初始向量值 IvParameterSpec iv = new IvParameterSpec("1122334455667788".getBytes()); cipher.init(Cipher.ENCRYPT_MODE, sks, iv); //实行加密,得到加密结果 byte[] bytes = cipher.doFinal(text.getBytes()); //将byte数组转成Base64编码。
String result = Base64.encodeBase64String(bytes); System.out.println("加密后的值:" + result); } / 测试AES解密 / @Test public void testDecrypt() throws Exception { //密文 String crpyt = "VG+sz7FleJ5QMMe+elTkpg=="; //密钥,长度必须为16个字节(字符) byte[] secretKeyBytes = "1234567812345678".getBytes(); //获取Cipher工具 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //指定密钥规则 SecretKeySpec sks = new SecretKeySpec(secretKeyBytes, "AES"); //加密工具初始化数据,参数1:模式,有加密模式和解密模式,参数2:密钥规则,参数3:IV初始向量值 IvParameterSpec iv = new IvParameterSpec("1122334455667788".getBytes()); cipher.init(Cipher.DECRYPT_MODE, sks, iv); //解密,上面利用的base64编码,下面直接用密文 byte[] bytes = cipher.doFinal(Base64.decodeBase64(crpyt)); // 由于是明文,以是直接返回 String text = new String(bytes); System.out.println("解密后的值:"+ text) ; } / 天生密钥 @param algorithm 算法 @param len 密钥长度 / public static byte[] generateSecretKey(String algorithm, int len) throws NoSuchAlgorithmException { KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);//密钥天生器 keyGenerator.init(len);//密钥长度 SecretKey secretKey = keyGenerator.generateKey();//天生密钥 return secretKey.getEncoded(); //密钥字节数组转字符串 }}
6.3 非对称密码

加密密钥和解密密钥不相同,并且从一个很难(实际上不可能实现)推出另一个,又称公钥密码系统编制(public-key cryptography system) 。
公钥密码系统编制用一个密钥进行加密( (验证 ),而用另一个进行解密( 署名)。
个中一个密钥可以公开,成为公开密钥(pulic key),简称公钥;另一个密钥须要秘密保存,称为私有密钥(private key),简称私钥 。

公钥和私钥是一对如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密。
如果用私有密钥对数据进行加密,只有用对应的公开密钥才能解密。

非对称加密算法的优点:安全性更高,公钥是公开的,密钥是自己保存的,不须要将私钥给别人。

非对称加密算法的缺陷:加密和解密花费韶光长、速率慢,只适宜对少量数据进行加密。

非对称加密算法: RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法),常见的有RSA、ECC。

当代打算机和互联网安全体系,很大程度上都依赖于公钥密码,但公钥密钥也存在风险,比如中间人攻击。

6.3.1 中间人攻击

中间人攻击指的是主动攻击者混入发送者和吸收者中间,对发送者伪装成吸收者,对吸收者伪装成发送者的攻击办法。
如果要防御中间人攻击,我们须要一种手段来确认吸收者收到的公钥是否真的属于发送者,这种手段称为认证,可以利用公钥的证书来实现。

6.3.2 天生密钥对

public class RSATest { / 测试天生密钥对 公钥和私钥 / @Test public void testCreatePubKeyPriKey() throws NoSuchAlgorithmException { //创建密钥对天生器工具 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); //天生密钥对 KeyPair keyPair = keyPairGenerator.generateKeyPair(); //天生私钥 PrivateKey privateKey = keyPair.getPrivate(); //天生公钥 PublicKey publicKey = keyPair.getPublic(); //获取私钥字节数组 byte[] privateKeyEncoded = privateKey.getEncoded(); //获取公钥字节数组 byte[] publicKeyEncoded = publicKey.getEncoded(); //进行base64编码 String privateKeyString = Base64.encodeBase64String(privateKeyEncoded); String publicKeyString = Base64.encodeBase64String(publicKeyEncoded); //输出私钥 System.out.println(privateKeyString); //输出公钥 System.out.println(publicKeyString); } }6.3.3 私钥加密公钥解密

private String privateKeyString = "私钥的值"; private String publicKeyString = "公钥的值"; private String algorithm = "RSA"; / 测试私钥加密 @throws Exception / @Test public void testPrikKeyEncrypt() throws Exception { String text = "传智播客"; PrivateKey privateKey = getPrivateKey(); //创建加密工具 Cipher cipher = Cipher.getInstance(algorithm); //初始化加密,参数1:加密模式,参数2:利用私钥进行加密 cipher.init(Cipher.ENCRYPT_MODE,privateKey); //对明文进行加密 byte[] bytes = cipher.doFinal(text.getBytes()); System.out.println(Base64.encodeBase64String(bytes)); } / 测试公钥解密 / @Test public void testPubKeyDecrypt() throws Exception { String encrypt = "加密的值"; PublicKey publicKey = getPublicKey(); //创建加密工具 Cipher cipher = Cipher.getInstance(algorithm); //初始化加密,参数1:解密模式,参数2:利用公钥进行解密 cipher.init(Cipher.DECRYPT_MODE,publicKey); //对密文进行解密 byte[] bytes = cipher.doFinal(Base64.decodeBase64(encrypt)); System.out.println(new String(bytes)); } / 获取私钥工具 / private PrivateKey getPrivateKey() throws Exception{ //获取密钥工厂 KeyFactory keyFactory = KeyFactory.getInstance(algorithm); //构建密钥规范 进行Base64解码 PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString)); //天生私钥 return keyFactory.generatePrivate(spec); } / 获取公钥工具 / private PublicKey getPublicKey() throws Exception{ //获取密钥工厂 KeyFactory keyFactory = KeyFactory.getInstance(algorithm); //构建密钥规范 进行Base64解码 X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyString)); //天生公钥 return keyFactory.generatePublic(spec); }6.3.4 公钥加密私钥解密

/ 测试公钥加密 @throws Exception / @Test public void testPubKeyEncrypt() throws Exception { String text = "传智播客"; PublicKey publicKey = getPublicKey(); //创建加密工具 Cipher cipher = Cipher.getInstance(algorithm); //初始化加密,参数1:加密模式,参数2:利用公钥进行加密 cipher.init(Cipher.ENCRYPT_MODE,publicKey); //对明文进行加密 byte[] bytes = cipher.doFinal(text.getBytes()); System.out.println(Base64.encodeBase64String(bytes)); } / 测试私钥解密 / @Test public void testPriKeyDecrypt() throws Exception { String encrypt = "加密的值"; //公钥进行解密 PrivateKey publicKey = getPrivateKey(); //初始化加密,参数1:解密模式,参数2:利用私钥进行解密 Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.DECRYPT_MODE,publicKey); //对密文进行解密 byte[] bytes = cipher.doFinal(Base64.decodeBase64(encrypt)); System.out.println(new String(bytes)); }6.3.5 代码重构测试加解密

/ 测试加密解密 @throws Exception / @Test public void testEncryptDecrypt() throws Exception { PrivateKey privateKey = getPrivateKey(); PublicKey publicKey = getPublicKey(); //1.1私钥加密 String priEnrypt = encrypt(privateKey, "传智播客"); //1.1公钥解密 decrypt(publicKey,priEnrypt); //2.1公钥加密 String pubEnrypt = encrypt(publicKey, "传智播客"); //2.1私钥解密 decrypt(privateKey,pubEnrypt); } / 加密数据 / private String encrypt(Key key, String input) throws Exception{ //创建加密工具 Cipher cipher = Cipher.getInstance(algorithm); //初始化加密,参数1:加密模式,参数2:利用key进行加密 cipher.init(Cipher.ENCRYPT_MODE, key); //私钥加密 byte[] bytes = cipher.doFinal(input.getBytes()); //对密文进行Base64编码 System.out.println("加密结果:"+ Base64.encodeBase64String(bytes)); return Base64.encodeBase64String(bytes); } / 解密数据 / private String decrypt(Key key, String encrypted) throws Exception{ //创建加密工具 Cipher cipher = Cipher.getInstance(algorithm); //初始化加密,参数1:解密模式,参数2:利用key进行解密 cipher.init(Cipher.DECRYPT_MODE,key); //由于密文进行了Base64编码, 在这里须要进行解码 byte[] decode = Base64.decodeBase64(encrypted); //对密文进行解密,不须要利用base64,由于原文不会乱码 byte[] bytes = cipher.doFinal(decode); System.out.println("解密结果:"+ new String(bytes)); return new String(bytes); }6.3.6 密钥对保存及读取保存公钥和私钥到文件

private String pubKeyPath = "test.pub"; private String priKeyPath = "test.pri"; / 测试天生密钥对 公钥和私钥 / @Test public void testCreatePubKeyPriKey() throws NoSuchAlgorithmException, IOException { //创建密钥对天生器工具 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); //天生密钥对 KeyPair keyPair = keyPairGenerator.generateKeyPair(); //天生私钥 PrivateKey privateKey = keyPair.getPrivate(); //天生公钥 PublicKey publicKey = keyPair.getPublic(); //获取私钥字节数组 byte[] privateKeyEncoded = privateKey.getEncoded(); //获取公钥字节数组 byte[] publicKeyEncoded = publicKey.getEncoded(); //进行base64编码 String privateKeyString = Base64.encodeBase64String(privateKeyEncoded); String publicKeyString = Base64.encodeBase64String(publicKeyEncoded); //输出私钥 System.out.println(privateKeyString); //输出公钥 System.out.println(publicKeyString); // 保存文件 FileUtils.writeStringToFile(new File(pubKeyPath), publicKeyString, Charset.forName("UTF-8")); FileUtils.writeStringToFile(new File(priKeyPath), privateKeyString, Charset.forName("UTF-8")); }从文件读取公钥和私钥

/ 获取私钥工具 / private PrivateKey getPrivateKey() throws Exception{ String privateKeyString = FileUtils.readFileToString(new File(priKeyPath), Charset.defaultCharset()); //获取密钥工厂 KeyFactory keyFactory = KeyFactory.getInstance(algorithm); //构建密钥规范 进行Base64解码 PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString)); //天生私钥 return keyFactory.generatePrivate(spec); } / 获取公钥工具 / private PublicKey getPublicKey() throws Exception{ String publicKeyString = FileUtils.readFileToString(new File(pubKeyPath), Charset.defaultCharset()); //获取密钥工厂 KeyFactory keyFactory = KeyFactory.getInstance(algorithm); //构建密钥规范 进行Base64解码 X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyString)); //天生公钥 return keyFactory.generatePublic(spec); }6.4 随机数6.4.1 观点

对付密码技能来说,算法的强度再高,只要攻击者知道了密钥,那么安全就形同虚设。
我们须要利用一种技能来随机成成密钥,使得攻击者无法看穿,那么这项技能便是随机数技能。

随机数技能的运用处景:

天生密钥:用于对称密码和认证码。
天生密钥对:用于公钥密码和数字署名天生初始向量(IV):用于分组密码的CBC、CFB和OFB模式。
天生nonce:用于防御重放共计及分组密码的CTR模式天生盐:用于基于口令的密码(PBE)

随机数技能分类:

随机性:完备凌乱的数列不可预测性:不能从过去的数列推测出下一个涌现的数不可重现性:除非将数列本身保存下来,佛则不能重现相同的数列

由上到下越来越严格,密码技能利用的随机数仅仅靠随机性是不足的,至少还要具备不可预测性才行。
具备不可预测性的随机数,一定具备随机性。
具备不可重现性的随机数,一定具随机性和不可预测性。

随机性

不可预测性

不可重现性

解释

弱随机数

具备

只具备随机属性,不可用与密码技能

强伪随机数

具备

具备

具备不可预测性,可用于密码技能

真随机数

具备

具备

具备

具备不可重现性,可用于密码技能

严格程度,从低到高:随机性->不可预测性->不可重现性

6.4.2 伪随机数天生器

随机数可以通过硬件来天生,也可以通过软件天生。

天生随机数的硬件设备称为随机数天生器,天生随机数的软件称为伪随机数天生器。

1) 详细的伪随机数天生器

线性同余法不具备不可预测性,不可用于密码技能,比如Java中的java.util.Random。
核心是将当前随机数乘以A再加上C,然后除以M得到的余数作为下一个伪随机数。
单项散列函数法具备不可预测性,可用于密码技能。
核心在于单项散列函数的单向性。
密码法具备不可预测性,可用于密码技能。
何在在于密码的机密性。
ASNI X9.17具备不可预测性,可用于密码技能。

2)伪随机数天生器的攻击

由于伪随机数天生器承担了天生密钥的重任,会常常被当做攻击工具。
如果攻击者知道了伪随机数的种子,那么他就能够知道这个伪随机数天生器所天生的全部伪随机数数列。
我们须要利用具备不可重现性的真随机数作为种子。

实现办法:事先准备好随机池,随机池内容要保护好,当密码软件须要伪随机数的种子时,可以从随机池中取出来须要的长度的随机比特序列来利用。

随机池:

比如linux中的/dev/random和/dev/urandom文件便是一个根据硬件设备驱动存储真随机数的随机池比如Windows操作系统的CryptGenRandom接口6.4.3 Java随机数示例

Java编程中,能担保不可预测的随机算法类是SecureRandom,可用于密码技能

/ 随机数天生测试 /public class RandomTest { @Test public void testRandom() throws NoSuchAlgorithmException { //linux环境下会读取/dev/urandom非壅塞天生随机数 SecureRandom random = new SecureRandom(); for (int i = 0; i < 100; i++) { System.out.println(random.nextLong()); } }}6.5 稠浊密码系统6.5.1 观点对称密码问题:毛病在于对付密钥的管理上,以及在非安全信道中通讯时,密钥交流的安全性不能保障,而公钥密码则办理了这个问题(也称密钥配送问题)公钥密码问题1:处理速率远远低于对称密码公钥密码问题2:会涌现中间人攻击

以是在实际的网络环境中,会将两者稠浊利用,将对称密码和非对称密码结合起来的办法便是稠浊密码。
稠浊密码系统可以办理公钥密码速率慢的问题,中间人共计须要用到认证技能。

6.5.2 稠浊密码系统组成机制用对称密码加密通过伪随机天生器天生对称密码加密中利用的会话密钥用公钥密码加密会话密钥从稠浊密码系统外部授予公钥密码加密时利用的密钥

稠浊密码系统利用了伪随机数天生器、对称密码、公钥密码这三种密码技能,充分利用了对称密码和公钥密码的上风。
比如密码软件PGP,SSL/TLS技能都利用了稠浊密码系统。

1)加密过程

加密会话密钥会话密钥指的是为本次通信天生的临时密钥,一样平常通过伪随机数天生器产生,产生会话密钥的同时会传给右侧作为对称密码的密钥利用。
接着通过公钥对会话密钥进行加密,公钥密码加密所利用的密钥是吸收者的公钥利用对称密码进行加密,密钥为会话密钥。
如果内容很长,对称密钥依然能快速完成加密根据第一步和第二部的加密结果,按顺序拼接成稠浊密码系统的密文2)解密过程

分离密文:根据发送者和吸收者事先约定好的密文构造,将密文分离成两部分解密会话密钥:用公钥密码解密会话密钥,解密密钥是吸收者的私钥。
解密后的会话密钥将被用作解密的密钥解密:利用解密后的会话密钥利用对称密码进行解密6.5.3 把稳事变会话密钥通过伪随机数天生器天生,以是要选择高强度的伪随机数天生器对称密码被用来加密,以是要选择高强度对称密码算法确保密钥足够的长度,并且选择分组密码模式。
公钥密码被用来加密会话密钥,以是要选择高强度的公钥密码算法确保密钥足够的长度公钥密码的强度最好高于对称密码的强度,对称密码的会话密钥如果被破译只影响这次通信,公钥密码如果被破译,会导致从过去到未来(用相同公钥加密的)所有的通信内容都被破译6.5.4 代码示例

AES工具类:

/ AES加解密工具类 /public class AESUtil { / AES加密 @param text 待加密的明文 @param secretKey 密钥 @param iv 初始向量 / public static String encrypt(byte[] text,byte[] secretKey,byte[] iv) throws Exception { // Cipher:获取密码工具,参数按"算法/模式/添补模式" Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 参数1:密钥,key的字节数组,参数2:加密算法 SecretKeySpec sks = new SecretKeySpec(secretKey, "AES"); //加密工具初始化数据,参数1:模式,有加密模式和解密模式,参数2:密钥规则,参数3:IV初始向量值 IvParameterSpec ivParam = new IvParameterSpec(iv); cipher.init(Cipher.ENCRYPT_MODE, sks, ivParam); //实行加密,得到加密结果 byte[] bytes = cipher.doFinal(text); //将byte数组转成Base64编码。
String result = Base64.encodeBase64String(bytes); return result; } / AES加密 @param text 待加密的明文 @param secretKey 密钥 / public static String encrypt(byte[] text,byte[] secretKey) throws Exception { // Cipher:获取密码工具,参数按"算法/模式/添补模式" Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 参数1:密钥,key的字节数组,参数2:加密算法 SecretKeySpec sks = new SecretKeySpec(secretKey, "AES"); //加密工具初始化数据,参数1:模式,有加密模式和解密模式,参数2:密钥规则 cipher.init(Cipher.ENCRYPT_MODE, sks); //实行加密,得到加密结果 byte[] bytes = cipher.doFinal(text); //将byte数组转成Base64编码。
String result = Base64.encodeBase64String(bytes); return result; } / AES解密 @param encrypted 待解密的密文 @param secretKey 密钥 @param iv 初始向量值 / public static String decrypt(String encrypted,byte[] secretKey, byte[] iv) throws Exception { //秘钥,长度必须为16个字节(字符) //获取Cipher工具 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //指定密钥规则 SecretKeySpec sks = new SecretKeySpec(secretKey, "AES"); //加密工具初始化数据,参数1:模式,有加密模式和解密模式,参数2:密钥规则,参数3:IV初始向量值 IvParameterSpec ivParam = new IvParameterSpec(iv); cipher.init(Cipher.DECRYPT_MODE, sks, ivParam); //解密,上面利用的base64编码,下面直接用密文 byte[] bytes = cipher.doFinal(Base64.decodeBase64(encrypted)); // 由于是明文,以是直接返回 String text = new String(bytes); return text; } / AES解密 @param encrypted 待解密的密文 @param secretKey 密钥 / public static String decrypt(byte[] encrypted,byte[] secretKey) throws Exception { //秘钥,长度必须为16个字节(字符) //获取Cipher工具 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //指定密钥规则 SecretKeySpec sks = new SecretKeySpec(secretKey, "AES"); //加密工具初始化数据,参数1:模式,有加密模式和解密模式,参数2:密钥规则 cipher.init(Cipher.DECRYPT_MODE, sks); //解密,上面利用的base64编码,下面直接用密文 byte[] bytes = cipher.doFinal(encrypted); // 由于是明文,以是直接返回 String text = new String(bytes); return text; } / 天生密钥 @param algorithm 算法 @param len 密钥长度 / public static byte[] generateSecretKey(String algorithm, int len) throws NoSuchAlgorithmException { KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);//密钥天生器 keyGenerator.init(len);//密钥长度 SecretKey secretKey = keyGenerator.generateKey();//天生密钥 return secretKey.getEncoded(); //密钥字节数组转字符串 }}

RSA 工具类:

/ RSA加解密工具类 /public class RSAUtil { private static String algorithm = "RSA"; / 加密数据 @param key 公钥或者私钥 @param text 待加密的明文 / public static String encrypt(Key key, byte[] text) throws Exception{ //创建加密工具 Cipher cipher = Cipher.getInstance(algorithm); //初始化加密,参数1:加密模式,参数2:利用key进行加密 cipher.init(Cipher.ENCRYPT_MODE, key); //私钥加密 byte[] bytes = cipher.doFinal(text); //对密文进行Base64编码 return Base64.encodeBase64String(bytes); } / 解密数据 @param key 公钥或者私钥 @param encrypted 待解密的密文 / public static byte[] decrypt(Key key, String encrypted) throws Exception{ //创建加密工具 Cipher cipher = Cipher.getInstance(algorithm); //初始化加密,参数1:解密模式,参数2:利用key进行解密 cipher.init(Cipher.DECRYPT_MODE,key); //由于密文进行了Base64编码, 在这里须要进行解码 byte[] decode = Base64.decodeBase64(encrypted); //对密文进行解密,不须要利用base64,由于原文不会乱码 byte[] bytes = cipher.doFinal(decode); return bytes; } private static String pubKeyPath = "test.pub"; private static String priKeyPath = "test.pri"; / 天生密钥对公钥和私钥 / public static void createPubKeyPriKey() throws NoSuchAlgorithmException, IOException { //创建密钥对天生器工具 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); //天生密钥对 KeyPair keyPair = keyPairGenerator.generateKeyPair(); //天生私钥 PrivateKey privateKey = keyPair.getPrivate(); //天生公钥 PublicKey publicKey = keyPair.getPublic(); //获取私钥字节数组 byte[] privateKeyEncoded = privateKey.getEncoded(); //获取公钥字节数组 byte[] publicKeyEncoded = publicKey.getEncoded(); //进行base64编码 String privateKeyString = Base64.encodeBase64String(privateKeyEncoded); String publicKeyString = Base64.encodeBase64String(publicKeyEncoded); //输出私钥 System.out.println(privateKeyString); //输出公钥 System.out.println(publicKeyString); // 保存文件 FileUtils.writeStringToFile(new File(pubKeyPath), publicKeyString, Charset.forName("UTF-8")); FileUtils.writeStringToFile(new File(priKeyPath), privateKeyString, Charset.forName("UTF-8")); } / 获取私钥工具 / public static PrivateKey getPrivateKey() throws Exception{ String privateKeyString = FileUtils.readFileToString(new File(priKeyPath), Charset.defaultCharset()); //获取密钥工厂 KeyFactory keyFactory = KeyFactory.getInstance(algorithm); //构建密钥规范 进行Base64解码 PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyString)); //天生私钥 return keyFactory.generatePrivate(spec); } / 获取公钥工具 / public static PublicKey getPublicKey() throws Exception{ String publicKeyString = FileUtils.readFileToString(new File(pubKeyPath), Charset.defaultCharset()); //获取密钥工厂 KeyFactory keyFactory = KeyFactory.getInstance(algorithm); //构建密钥规范 进行Base64解码 X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyString)); //天生公钥 return keyFactory.generatePublic(spec); } public static void main(String[] args) throws Exception { PrivateKey privateKey = RSAUtil.getPrivateKey(); PublicKey publicKey = RSAUtil.getPublicKey(); String pubEnrypt = encrypt(publicKey, "传智播客".getBytes()); System.out.println(pubEnrypt); //2.1私钥解密 byte[] decrypt = decrypt(privateKey, pubEnrypt); System.out.println(new String(decrypt)); }}

稠浊密码测试类:

/ 稠浊密码测试 /public class MixCryptTest { @Test public void testMxiCrypt() throws Exception { //准备好公钥与私钥,天生到文件中 RSAUtil.createPubKeyPriKey(); //个中公钥给客户端利用,私钥做事端保留,下方代码表示客户端给做事端发送稠浊加密 // 客户端发送开始 // //准备明文 byte[] text = "大家好,我来自传智播客大家好,我来自传智播客".getBytes(); //伪随机数天生器天生会话密钥 byte[] sessionSecretKey = AESUtil.generateSecretKey("AES", 128); //公钥密码算法用公钥加密会话密钥 String secretKeyEncrypted = RSAUtil.encrypt(RSAUtil.getPublicKey(), sessionSecretKey); System.out.println("[客户端]会话密钥加密结果:" + secretKeyEncrypted); //为对称加密算法准备加密时候初始向量值 byte[] iv = AESUtil.generateSecretKey("AES", 128); //对称密码算法用会话密钥加密 String textEncrypt = AESUtil.encrypt(text, sessionSecretKey, iv); System.out.println("[客户端]明文加密结果:" + textEncrypt); //拼接两个加密后的值 byte[] b1 = Base64.decodeBase64(secretKeyEncrypted); int len1 = b1.length; byte[] b2 = Base64.decodeBase64(textEncrypt); int len2 = b2.length; //拼接两个加密后的值 String splitFlag = "==itcast=="; byte[] flag = splitFlag.getBytes("UTF-8"); int lenFlag = flag.length; byte[] bFinal = new byte[len1+lenFlag+len2]; System.arraycopy(b1, 0, bFinal, 0, len1); System.arraycopy(b2, 0, bFinal, len1, lenFlag); System.arraycopy(b2, 0, bFinal, len1+lenFlag, len2); String finalStr = Base64.encodeBase64String(bFinal); System.out.println("[客户端]拼接后的加密结果:" + finalStr); // 客户端发送结束 // // 做事端解密开始 // //开始分离数据 byte[] finalBytes = Base64.decodeBase64(finalStr); byte[] sskEncryptedBytes = new byte[len1]; byte[] textEncryptedBytes = new byte[len2]; System.arraycopy(finalBytes, 0, sskEncryptedBytes, 0, len1); System.arraycopy(finalBytes, len1+lenFlag, textEncryptedBytes, 0, len2); String sskEncrypt = Base64.encodeBase64String(sskEncryptedBytes); String textEncrypted = Base64.encodeBase64String(textEncryptedBytes); //公钥密码用私钥解密会话密钥的密文得到会话密钥明文 byte[] ssKBytes = RSAUtil.decrypt(RSAUtil.getPrivateKey(), sskEncrypt); //对称密码用会话密钥的明文解密 String textPlain = AESUtil.decrypt(textEncrypted, ssKBytes, iv); System.out.println("[做事端]密文解密结果:" + textPlain); // 做事端解密结束 // }}五、结束语

在今日文章中,我们体系化的理解到了密码的含义,先容了当代密码学涉及到的编码技能和密码技能,个中最主要的便是对称密码技能和公钥密码技能,为了担保密码的安全我们还理解到了分组密码的加密模式和添补模式、及随机数和稠浊密码系统。
通过今日的学习,相信大家内心中都已经揭开了密码的神秘面纱。
当然,有关于密码干系的内容绝不仅仅只是本日这么多,还有非常多密码组合技能,比如下方这些密码技能等着我们进一步探究:

数字署名:单项散列函数和公钥密码的组合证书:公钥和数字署名的组合认证码:单项散列函数和密码组组合,或者通过对称密码来天生六、附录.密码发展历史

解释:该部分内容网络整理自网络

1. 第一阶段:远古密码

韶光范围:远古到公元前400年旁边

密码特色:

这个期间所谓“密码”实质上是古人根据物理工具特性所作出的改造和伪装,当中并没有涉及到启示式的数学思维或方法,我们称之为远古密码。

1.1 阴符

天下上最早的密码工具普遍被认为是在公元前1000年由姜子牙发明的军用“阴符”。
相传商纣王末年,姜太公辅佐周室。
有一次,姜太公带领的周军指挥大营被叛兵包围,情形危急,姜太公令信使突围,回朝搬兵,但又怕信使遗忘机密,或者周文王不认识信使,延误了军务大事。
于是其将自己保重的鱼竿折成数节,每节长短不一,各代表一件军机,令信使牢记,不得外传。
信使几经周折回到朝中,周文王令旁边将几节鱼竿合在一起,亲自考验。
周文王辨认出是姜太公的心爱之物,于是亲率大军,补救姜太公,“阴符”由此出身。

当时“阴符”的规格共有8种(即8个不同的尺寸),每种规格分别代表一种状态。
比如,长为1尺的“阴符”表示大获全胜、全歼敌军;长为4寸的“阴符”表示军队失落败,将领阵亡等。

尺寸

状态含义

1尺

大获全胜、全歼敌军

9寸

击破敌军、擒获敌将

8寸

迫使敌军屈膝降服佩服、攻占仇敌城邑

7寸

击退仇敌、通报战况

6寸

勉励军民、倔强守御

5寸

要求补给粮草、增加兵力

4寸

报告军队失落败、将领阵亡

3寸

战斗失落利、士卒伤亡

1.2 阴书

阴符虽有简便保密的特点,但却过于大略,无法表达更繁芜的含义。
为此,姜子牙又进一步发明了"阴书",即将竖写的秘密文书横截成3段,并派出3位信使各执一段,于不同韶光、不同路线分别出发,先后投递收件者。
任何人只有在收齐3段文件往后才能获悉秘密文书的全部内容。

1.3 塞塔密码

公元前400年,古希腊的斯巴达人发明了塞塔(scytale)密码,也称密码棒。
他们把长条纸螺旋地斜绕在一根多棱棒上,让纸条被多棱棒分割成一个个的类似格子一样的区域,并沿着这个区域,将笔墨沿棒的水平方向从左到右书写,写一个字旋转一下,换一个区域,写完一行再另起一行从左到右写。
这样一来,本来完全畅通的一句话,就被机器地分割开了。
将信息写完后,解下来的纸条上的笔墨凌乱无章、无法理解,这就将原来的信息明文转换成了密文。
在把展开的纸条通报出去往后,解密人只有将纸条斜绕在另一根同等尺寸的多棱棒上才能看到原始。

1.4 瘦语

《左传·宣公十二年》记载了一种用于更换信息的“瘦语”法。
所谓“瘦语”,便是电影里常见的暗语、黑话,用一个完备不干系的词来代表特定含义。

2. 第二阶段:古典密码

韶光范围:公元前400年-20世纪初 (classical cryptography),长达几千年

密码特色:

古典密码编码方法的核心是代替和置换。

代替:代替密码是将明文中的字符替代成其他字符。
代替密码是指先建立一个更换表,加密时将须要加密的明文依次通过查表,更换为相应的字符,明笔墨符被逐个更换后,天生无任何意义的字符串,即密文,替代密码的密钥便是其更换表。
置换:置换密码又称换位密码,是根据一定的规则重新排列明文,以便冲破明文的构造特性。
置换密码的特点是保持明文的所有字符不变,只是利用置换打乱了明笔墨符的位置温柔序。
也便是说,改变了明文的构造,不改变明文的内容。
2.1 恺撒密码

公元前58年旁边由凯撒大帝发明该密码运用在军事通信之中,故而得名为恺撒密码(Caesar cipher)。
恺撒密码是一种代替密码,其加密办法便是将英文中的每个字母用其余一个字母来代替。
恺撒密码是对英文26个字母进行移位代替的密码,属于“移位代替密码”,是最大略的一类代替密码。
恺撒密码的实质是构建了一张明密代替表,即密码本。
明密代替表就像一把钥匙,用这把钥匙可以方便地进行“加密”和“解密”操作。

2.2 棋盘密码

公元前两世纪,古希腊人发明了利用Polybius方阵加密的方法,即棋盘密码。
所谓棋盘密码,便是把字母按序或乱序填入表格里,并对应行和列进行加密,比如最大略的棋盘密码:

1

2

3

4

1

A

B

C

D

2

E

F

G

H

3

I

J

K

L

4

M

N

O

P

假设明文是GOD,那么加密后则为23 43 14。
棋盘密码虽然大略,但实用性非常好。

2.3 圆盘密码

15世纪末,佛罗洛萨人Alberti又发明了圆盘密码,也称密码盘。
所谓圆盘密码,便是两个同心圆盘上,内盘随机填写字符,而外盘的字符则按照一定顺序来填写。
利用者只需迁徙改变圆盘就可以找到内外盘字符间的映射办法

2.4 维吉尼亚密码

上述密码都可以统称为单表代替密码,即明文和密文之间均具有逐一对应的关系,了冲破这种对应关系,1553年,Giovan Battista Bellaso在其著作中发明了通过字母密钥来循环加密明文的“维吉尼亚”密码(也称维热纳尔密码,Vigenere密码)。
假设要加密的明文是:TO BE OR NOT TO BE THAT IS THE QUESTION,选择某一关键词并重复而得到密钥,如关键词为RELATIONS,即RE LA TI ONS RE LA TION SR ELA TIONSREL。
对付明文的第一个字母T,对应密钥的第一个字母R,于是利用表格中R行字母表进行加密,就可以在一个特定的2626表格中征采第R行、第T列所对应的字母作为T的密文。
以此类推,得到密文为:KSMEH ZBBLK SMEMP OGAJX SEJCS FLZSY。

得出对应关系如下:

明文:TO BE OR NOT TO BE THAT IS THE QUESTION

密钥:RE LA TI ONS RE LA TION SR ELA TIONSREL

密文:KS ME HZ BBL KS ME MPOG AJ XSE JCSFLZSY

解密:密钥第一个字母R对应的行中,查找密文的第一个字母K,创造K对应的是t列,以是明文是T,以此类推。

2.5 栅栏密码

古典密码中还有一类著名的密码是“置换密码”,置换密码不是用密笔墨母代替相对应的明笔墨母,而是通过打乱明笔墨母的位置,使故意义的明文信息变换为无意义的密文乱码。
栅栏密码是置换密码的范例代表。
栅栏密码涌现于1861年至1865年的美国南北战役期间。
其加密事理是:明文按列写入,密文按行输出。

加密事理:把将要通报的信息中的字母交替排成高下两行。
再将下面一行字母排在上面一行的后边,从而形成一段密码。
比如下面的示例:

明文:THE LONGEST DAY MUST HAVE AN END

加密:

1、把将要通报的信息中的字母交替排成高下两行。

T E O G S D Y U T A E N N

H L N E T A M S H V A E D

2、 密文:

将下面一行字母排在上面一行的后边。

TEOGSDYUTAENN HLNETAMSHVAED

解密:

先将密文分为两行

T E O G S D Y U T A E N N

H L N E T A M S H V A E D

再按高下高下的顺序组合成一句话

明文:THE LONGEST DAY MUST HAVE AN END

2.6 隐写术

与密码技能对应还有一种技能,目的不是为了让变得无法解读,而是想办法隐蔽本身,这种技能一样平常称为隐写术。
隐写术一样平常分为两类:

隐写药水在古代的战役中,多见利用隐蔽信息的办法保护主要的通信资料。
比如先把须要保护的信息用化学药水写到纸上,药水干后,纸上看不出任何的信息,须要利用其余的化学药水涂抹后才可以阅读纸上的信息。
藏头尾诗词比如《唐寅诗集》中“我爱秋喷鼻香”。
如下:我画兰江水悠悠爱晚亭上枫叶稠秋月融融照佛寺喷鼻香烟袅袅绕轻楼

总结:古典密码中不管是恺撒密码还是栅栏密码,都有自身的缺陷可以被破译者利用,但是如果将置换密码与代替密码二者组合起来,则可以在一定程度上使得变换更繁芜。
乘积密码便是以某种办法连续实行两个或多个密码变换技能,从而使末了加密结果更随机,从密码编码的安全性角度来看,比单一的代替密码和置换密码都更强。
古典密码中的代替密码(紧张代表为恺撒密码)与置换密码(紧张代表为栅栏密码)可以组合成多种新的密码形式,即乘积密码的详细形式,这也是分组密码的雏形。

3. 第三阶段:近代密码

韶光范围:20世纪初到20世纪50年代,包含1战和2战期间

密码特色:密码机的迅速发展,越来越多的数学家加入密码军队

在战役中,密码设计者不断地设计出新的密码,这些密码又不断地被密码剖析者破译。
设计和破译就像矛和盾,此消彼长,密码在战役中不断发展演化,越来越繁芜,越来越难以破译。
手工作业办法已难以知足繁芜密码运算的哀求,密码研究者设计出了一些繁芜的机器和电动机械设备,实现了信息的加解密操作,近代密码期间发布到来。

3.1 Playfair密码

在第一次天下大战前期,英军陆军紧张利用是英国物理学家Wheatstone在1854年发明的Playfair密码。
Playfair密码的核心是通过利用一个关键词方格来对字符对进行加密,此前曾被广泛用于克里米亚和布尔战役。
但在1915年,Playfair密码就被同盟国破解了。

3.2 一次性便笺密码

1918年,美国数学家Gillbert Vernam发明出一次性便笺密码,它是一种理论上绝对无法破译的加密系统,被誉为密码编码学的圣杯。
但由于产生和分发大量随机密钥的过程十分困难,因此这种密码的实际运用受到了很大限定。
从另一方面来说,其安全性也更加无法担保。

3.3 恩尼格玛密码

1919年,德国工程师Arthur Scherbius设计出了历史上最著名的密码机:Enigma机,恩尼格玛密码机是转子机器密码机的统称,它包括了一系列不同的型号,由德国人亚瑟·谢尔比乌斯和理查德·里特发明,在20世纪20年代开始被用于商业,后来被一些国家的军队与政府进行改造并利用,最著名的是掀起第二次天下大战的纳粹德国。

最先破解早期Enigma密码机的是波兰人,其利用德军电报中前几个字母的重复涌现,摸索出了破译方案,并将其奉告英军和法军。
英军在打算机理论之父Turing的带领下,通过探求德军在密钥选择上的失落误以及借助战役中成功攫取的德军密码本破解出主要的德军情报。

3.4 JN-25密码

第二次天下大战中,密码攻防战持续升级。
除盟军对恩尼格玛密码机破译的范例案例外,在亚洲沙场,编码与破译之间的斗争同样是触目惊心。
1943年春天,山本五十六为了掌握不断恶化的残局,亲自前往所罗门群岛基地巡视,以鼓舞士气。
1943年4月13日,日军第八舰队司令将山本一行察看的行程、韶光表,用D号密码(美军称为JN-25)加密后发给有关基地。
只管该密码的密码本在4月2日刚刚被换过,但美国破译职员根据过去网络的资料,利用多表代替的统计特性破译了这份密报。
经由周密安排,美军飞机于4月18日击落了飞往察看地途中的山本五十六乘坐的飞机。

4. 第四阶段: 当代密码

韶光范围:1949年至今

密码特色:数据的安全基于密钥而不是算法的保密

1949年信息论创始人Shannon喷鼻香农揭橥划时期论文《The Communication Theory of Secret Systems》,个中定义了理论安全性,提出扩散和稠浊原则。
奠定了当代密码学的理论根本。

1972年,IBM研制出了对称密码系统编制加密算法。
3年往后,美国国家标准局将其颁布为国家标准,即数据加密标准(DES)。
这是密码学历史上一个颇具里程碑意义的事宜。

1976年,W.Diffie和M.Hellman揭橥了《密码学的新方向》一文,文中首次提出了适应网络保密通信需求的公钥密码思想,掀起了公钥密码学的序幕。
次年,美国的Ronald Rivest、Adi Shamir和Len Adleman提出了第一个建立在大数因子分解根本上的公钥密码算法,即著名的RSA算法。

1976年,Victor Miller和Neal Koblitz分别提出了如今家喻户晓的椭圆曲线密码学(ECC)。
只管在当时而言,ECC更靠近于数学空想的范畴,不具备实用性,但ECC在安全性上的上风以及实现效率使其一贯成为密码学家们乐此不疲的研究课题——比较起其它公钥密码算法,ECC的抗攻击性具有绝对的上风。
例如,利用ECC加密的256位密钥所供应的安全性,与利用RSA或DSA加密的3072位密钥相称。
这意味着ECC算法所哀求的带宽更低、存储空间更小。
这些优点在某些对付带宽、处理器能力或存储空间有限定的运用(比如移动设备)中显得尤为主要。

90年代初,麻省理工学院教授Ronald Rivest提出了MD4信息择要算法,它是一种用来测试信息完全性的哈希函数。
MD4的实现,旋即开启了哈希函数的大门,包括后来Ronald Rivest重新提出的安全性更优的MD5,由NSA和NIST提出的SHA函数家族以及Hans Dobbertin,Antoon Bosselaers 和 Bart Prenee提出的RIPEMD。
在这一期间,密码学家来学嘉和JamesMasseey还提出了在软硬件实现上比DES更优的国际数据加密算法,即IDEA。

随着打算机能力的不断提高,不少密码体系比如主流的DES正逐步面临淘汰。
1998年,电子边疆基金会(EFF)利用耗资25万美元打造的专用打算机,仅用56个小时就成功破解了DES密钥。
随后在1999年,EFF仅用了22小时15分就完成了破解事情。
此后,美国国家安全局宣告弃用DES,转而启用由比利时密码学家Joan Daemen和Vincent Rijmen所提出的Rijndael加密算法,即高等加密标准AES。

进入千禧年往后,MD4、MD5、RIPEMD(RIPEMD-160仍旧安全)、SHA1以及RSA-768的强抗碰撞性相继被攻破,RSA-1024业已在2012年前后被停用。
随着区块链技能的兴起,ECC俨然成为密码学殿堂最亮眼的新星,但依旧难逃量子打算技能的威胁。

标签:

相关文章

php反射用法技巧_php反射机制用法详解

面向工具编程中工具被授予了自省的能力,而这个自省的过程便是反射。反射,直不雅观理解便是根据到达地找到出发地和来源。比如,一个光秃秃...

网站推广 2024-12-12 阅读0 评论0