签名和加密
加密:是指对某个内容加密,加密后的内容还可以通过解密进行还原。 比如我们把一封邮件进行加密,加密后的内容在网络上进行传输,接收者在收到后,通过解密可以还原邮件的真实内容。
签名:在信息的后面再加上一段内容,可以证明信息没有被修改过,怎么样可以达到这个效果呢?一般是对信息做一个hash计算得到一个hash值,注意,这个过程是不可逆的,也就是说无法通过hash值得出原来的信息内容。在把信息发送出去时,把这个hash值加密后做为一个签名和信息一起发出去。 接收方在收到信息后,会重新计算信息的hash值,并和信息所附带的hash值(解密后)进行对比,如果一致,就说明信息的内容没有被修改过,因为这里hash计算可以保证不同的内容一定会得到不同的hash值,所以只要内容一被修改,根据信息内容计算的hash值就会变化。当然,不怀好意的人也可以修改信息内容的同时也修改hash值,从而让它们可以相匹配,为了防止这种情况,hash值一般都会加密后(也就是签名)再和信息一起发送,以保证这个hash值不被修改。至于如何让别人可以解密这个签名,这个过程涉及到数字证书等概念。
对称加密算法、非对称加密算法(公钥加密算法),加(解)密规则称为密钥。 http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html
公钥加密算法RSA原理:https://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.htm [好文推荐]
对称加密
对称加密算法是指加密和解密使用相同密钥的加密算法,加密密钥能够从解密密钥中推算出来,同时解密密钥也可以从加密密钥中推算出来。对称加密算法的特点是算法公开、计算量小、加密速度快、加密效率高。
对称加密算法是应用较早的加密算法,技术成熟。在对称加密算法中,数据发信方将明文(原始数据)和加密密钥(mi yao)一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文,则需要使用加密用过的密钥及相同算法的逆算法对密文进行解密,才能使其恢复成可读明文。在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。 对称加密(也叫私钥加密)指加密和解密使用相同密钥的加密算法。有时又叫传统密码算法,就是加密密钥能够从解密密钥中推算出来,同时解密密钥也可以从加密密钥中推算出来。而在大多数的对称算法中,加密密钥和解密密钥是相同的,所以也称这种加密算法为秘密密钥算法或单密钥算法。它要求发送方和接收方在安全通信之前,商定一个密钥。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何人都可以对他们发送或接收的消息解密,所以密钥的保密性对通信的安全性至关重要。 对称加密算法的特点是算法公开、计算量小、加密速度快、加密效率高。 具体算法 主要有DES算法,3DES算法,TDEA算法,Blowfish算法,RC5算法,IDEA算法。 这里进行简单介绍一下基于“对称密钥”的加密算法。 基于“对称密钥”的加密算法主要有DES、TripleDES、RC2、RC4、RC5和Blowfish等。 1、对称密钥:DES TripleDES算法 DES算法把64位的明文输入块变为数据长度为64位的密文输出块,其中8位为奇偶校验位,另外56位作为密码的长度。首先,DES把输入的64位数据块按位重新组合,并把输出分为L0、R0两部分,每部分各长32位,并进行前后置换,最终由L0输出左32位,R0输出右32位,根据这个法则经过16次迭代运算后,得到L16、R16,将此作为输入,进行与初始置换相反的逆置换,即得到密文输出。 DES算法具有极高的安全性,到目前为止,除了用穷举搜索法对DES算法进行攻击外,还没有发现更有效的办法,而56位长密钥的穷举空间为2^56,这意味着如果一台计算机的速度是每秒种检测100万个密钥,那么它搜索完全部密钥就需要将近2285年的时间,因此DES算法是一种很可靠的加密方法。 2、对称密钥:RC算法 RC4算法的原理是“搅乱”,它包括初始化算法和伪随机子密码生成算法两大部分,在初始化的过程中,密钥的主要功能是将一个256字节的初始数簇进行随机搅乱,不同的数簇在经过伪随机子密码生成算法的处理后可以得到不同的子密钥序列,将得到的子密钥序列和明文进行异或运算(XOR)后,得到密文。 由于RC4算法加密采用的是异或方式,所以,一旦子密钥序列出现了重复,密文就有可能被破解,但是目前还没有发现密钥长度达到128位的RC4有重复的可能性,所以,RC4也是目前最安全的加密算法之一。 3、对称密钥:BlowFish算法 BlowFish算法是一个64位分组及可变密钥长度的分组密码算法,该算法是非专利的。 BlowFish算法使用两个“盒”:pbox[18]和sbox[4256],BlowFish算法有一个核心加密函数。该函数输入64位信息,运算后以64位密文的形式输出。用BlowFish算法加密信息,需要密钥预处理和信息加密两个过程。BlowFish算法的原密钥pbox和sbox是固定的,要加密一个信息,需要选择一个key,用这个key对pbox和sbox进行变换,得到下一步信息加密所用到的key_pbox和key_sbox。 BlowFish算法解密,同样也需要密钥预处理和信息解密两个过程。密钥预处理的过程和加密时完全相同。信息解密的过程就是把信息加密过程的key_pbox逆序使用即可。
非对称加密
非对称加密需要两个密钥:公钥 (publickey) 和私钥 (privatekey)。公钥和私钥是一对,如果用公钥对数据加密,那么只能用对应的私钥解密。如果用私钥对数据加密,只能用对应的公钥进行解密。因为加密和解密用的是不同的密钥,所以称为非对称加密。
非对称加密算法的保密性好,它消除了最终用户交换密钥的需要。但是加解密速度要远远慢于对称加密,在某些极端情况下,甚至能比对称加密慢上1000倍。 【特点】 算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快。对称密码体制中只有一种密钥,并且是非公开的,如果要解密就得让对方知道密钥。所以保证其安全性就是保证密钥的安全,而非对称密钥体制有两种密钥,其中一个是公开的,这样就可以不需要像对称密码那样传输对方的密钥了。这样安全性就大了很多。 【主要算法】 RSA、Elgamal、背包算法、Rabin、D-H、ECC (椭圆曲线加密算法)。使用最广泛的是 RSA 算法,Elgamal 是另一种常用的非对称加密算法。 【应用场景】 (1) 信息加密 收信者是唯一能够解开加密信息的人,因此收信者手里的必须是私钥。发信者手里的是公钥,其它人知道公钥没有关系,因为其它人发来的信息对收信者没有意义。 (2) 登录认证 客户端需要将认证标识传送给服务器,此认证标识 (可能是一个随机数) 其它客户端可以知道,因此需要用私钥加密,客户端保存的是私钥。服务器端保存的是公钥,其它服务器知道公钥没有关系,因为客户端不需要登录其它服务器。 (3) 数字签名 数字签名是为了表明信息没有受到伪造,确实是信息拥有者发出来的,附在信息原文的后面。就像手写的签名一样,具有不可抵赖性和简洁性。 简洁性:对信息原文做哈希运算,得到消息摘要,信息越短加密的耗时越少。 不可抵赖性:信息拥有者要保证签名的唯一性,必须是唯一能够加密消息摘要的人,因此必须用私钥加密 (就像字迹他人无法学会一样),得到签名。如果用公钥,那每个人都可以伪造签名了。 (4) 数字证书 问题起源:对1和3,发信者怎么知道从网上获取的公钥就是真的?没有遭受中间人攻击? 这样就需要第三方机构来保证公钥的合法性,这个第三方机构就是 CA (Certificate Authority),证书中心。 CA 用自己的私钥对信息原文所有者发布的公钥和相关信息进行加密,得出的内容就是数字证书。 信息原文的所有者以后发布信息时,除了带上自己的签名,还带上数字证书,就可以保证信息不被篡改了。信息的接收者先用 CA给的公钥解出信息所有者的公钥,这样可以保证信息所有者的公钥是真正的公钥,然后就能通过该公钥证明数字签名是否真实了。 这个的实际应用可以看看我之前的文章:网络篇 - https协议中的数据是否需要二次加密,里面讲的比较详细。 【更多】 https://blog.csdn.net/u014294681/article/details/86705999
加密代码如下,支持MD5、SHA、SHA256、SHA512
其中,
MD5生成128位长度的密文
SHA生成160位长度的密文
SHA256生成256位长度的密文
SHA512生成512位长度的密文
网上有很多例子说明了MD5不可避免碰撞,以及"撞库"等原因,导致MD5不太安全,在安全要求高的加密操作中,不适合用MD5进行加密,本文在MD5、SHA、SHA256、SHA512等的加密算法之上,增加了散列函数BASE_S,进一步提高加密安全性。
备注:本文中散列函数BASE_S为256长度,因为经MD5、SHA、SHA256、SHA512等算法加密后生成的密文为byte[](byte范围-128~127,经过处理可映射范围到0~255),并且BASE_S是由70个不同字符(a-zA-Z0-9!@#$%&*-)均衡随机分布得到,对提升加密安全性有很好的保证。
本文示例代码支持字符串、文件的加密操作,支持四种加密算法MD5、SHA、SHA256、SHA512。以及自定义散列函数
package com.cheng2839.md5; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.security.MessageDigest; /** * MD5信息摘要算法 * 安全散列算法SHA * https://www.cnblogs.com/cheng2839/ */ public class MD5Utils { private static final int BASE_NUM = 0x80; private static final String BASE_S = "iIHlFP4nxs&gM#J0jeSkhN6LXZQyC*qvrGAfzTK!29Uo-ORm8pWEDa$%tu3bYBVd15w7c@iwhY2@R4F-6WK$xTN1XqAMZJQU97vcsalVIrkf3pj!CHneE5*&got8D#0Odm%uBPyLGzbSj6sDCnvEuqXgZJ@M%kcp2!o1z5FfYy*GOhSIRt$8L0PQ-bax7VBreTlWHAK93&U4imwd#NOqS8kElMRNBIaLs3QnJ7&do4-fF2#P91mwr!pcbZGHU%06"; private static final int BASE_LEN = BASE_S.length(); private static final String MD5 = "MD5"; private static final String SHA_1 = "SHA"; private static final String SHA_256 = "SHA-256"; private static final String SHA_512 = "SHA-512"; public static String encodeMD5(String password) { return encodeMD5(password.getBytes()); } public static String encodeSHA(String password) { return encodeSHA(password.getBytes()); } public static String encodeSHA256(String password) { return encodeSHA256(password.getBytes()); } public static String encodeSHA512(String password) { return encodeSHA512(password.getBytes()); } public static String encodeMD5(File file) { FileInputStream fis = null; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); fis = new FileInputStream(file); byte[] buffer = new byte[512]; int len; while ((len=fis.read(buffer, 0, buffer.length)) > 0) { baos.write(buffer, 0, len); } fis.close(); baos.close(); return encodeMD5(baos.toByteArray()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (fis != null) { try { fis.close(); } catch (IOException e) {} } } return null; } public static String encodeMD5(byte[] bytes) { return encode(bytes, MD5); } public static String encodeSHA(byte[] bytes) { return encode(bytes, SHA_1); } public static String encodeSHA256(byte[] bytes) { return encode(bytes, SHA_256); } public static String encodeSHA512(byte[] bytes) { return encode(bytes, SHA_512); } private static String encode(byte[] bytes, String algorithm) { try { MessageDigest md5 = MessageDigest.getInstance(algorithm); md5.update(bytes); return toStr(md5.digest()); }catch (Exception e){ e.printStackTrace(); return null; } } private static String toStr(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) sb.append(BASE_S.charAt((b+BASE_NUM)%BASE_LEN)); return sb.toString(); } public static void main(String[] args) { System.out.println(encodeMD5("https://www.cnblogs.com/cheng2839/")); System.out.println(encodeSHA("https://www.cnblogs.com/cheng2839/")); System.out.println(encodeSHA256("https://www.cnblogs.com/cheng2839/")); System.out.println(encodeSHA512("https://www.cnblogs.com/cheng2839/")); } }
打印输出结果如下:
PqkDLmvrvJ$SgMlr L10-dkkm#5qY88-PnNTp -zZ!hX-dZcr%ZYkkZsnL1df!dwqVQxM# GoqdJa*rS!q1rXeS-8E5@B1!--rQOcZIssckMGB1Un90F*s9JG1NRBstbBmWdMm&
扩展:
为了提高安全性,实际企业中多使用加权加密的方法,能够有效防止撞库,即使相同的原密码通过不同的权得到的密文是不一样的。
由于不可逆算法的思想是在计算过程中丢掉部分数据(通过位移),所以导致无法解密。
如下例子,权值可以通过uuid得到,密文=f(sha(f(md5(f(原密文,权值))))),其中f一般为企业自定义散列函数。
从表格例子中可以观察出来以下几点:
- 即使很简单的原密码,可以得到很复杂的密文。
- 原密码即使相同,通过不同权值的渲染,也可以得到大不相同的密文。
- 原密码的长度,复杂度无论如何,都可以计算得到相同长度的密文。
序号 | 原密码 | 权值 | 加密后的密文 |
1 | 123456 | 4b0f45ef3a4540aea38002af14157355 | 1e6325cc0bb84aecae6c9605d6895b96a5f7a48 |
2 | 123456 | p3daa2f277464d58b921d097698a19a | d429e8645baa4d0794084730f4146f1e78ac32e |
3 | 654321 | b3cd482d12a945409198eded3b659db | 57ce915f612e4ef284ce21b58c68292c92e1e12f |
4 | abcdefg654321mnpq | r9d46ca1ab8647e7bcd806a0b03517d | ce8baf843c994d02a47dfa131006d9d78f87d4f3 |
如何在网络中传输安全性高的内容,