常用加密算法
Base64
Base64编码简介
Base64是一种编码方式,这个术语最初是在“MIME内容传输编码规范”中提出的。Base64不是一种加密算法,它实际上是一种“二进制转换到文本”的编码方式,它能够将任意二进制数据转换为ASCII字符串的形式,以便在只支持文本的环境中也能够顺利地传输二进制数据。
- base64编码:把二进制数据转换为字符
- base64接码:把字符转为二进制数据
这看起来可能有些奇怪,因为大多数的编码都是由字符转化成二进制的过程,而从二进制转成字符的过程称为解码。而Base64的概念就恰好反了,由二进制转到字符称为编码,由字符到二进制称为解码。
Base64编码由来
因为有些网络传输渠道并不支持所有字节,例如传统的邮件只支持可见字符的传输,像ASCII码的控制字符(ASCII包含了 128 个字符。其中前 32 个, 0-31 ,即 0x00-0x1F ,都是不可见字符。这些字符,就叫做控制字符。)就不能通过邮件传输。另外,例如图片二进制流的每个字节不可能全部都是可见字符,所以就传送不了。
最好的方法就是在不改变传统协议的情况下,做一种扩展方案来支持二进制文件的传送,把不可能打印的字符用可打印的字符标识,问题就解决了。Base64编码就应运而生,Base64就是一种基于64个可打印字符来表示二进制数据的表示方法
Base64编码原理
Base64编码索引表,字符选用了“A-Z 、 a-z 、 0-9、+、 / ”64个可打印字符。数字代表字符索引,这个是标准Base64标准协议规定的,不能更改。64个字节用6个bit位就可以全部表示(32+16+8+4+2+1)就可以全部表示。这里注意一个Base64字符是8个bit,但有效部分只有右边6个bit,左边两个永远是0。
***PS:***Base64编码有效位为6bit,左边两个为0,也就是00xxxxxx形式,而一个字符表示8bit,所以Base64在编码时可能会遇到bit位不足得情况,这种情况下会在字符后补充=
JAVA代码 JDK8 实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import java.util.Base64;
public void jdk(){ String s = "兔年顶呱呱"; byte[] encode = Base64.getEncoder().encode(s.getBytes(UTF_8)); System.out.println("encode: "+ new String(encode,UTF_8));
String asB64 = Base64.getEncoder().encodeToString("some string".getBytes("utf-8")); System.out.println(asB64);
byte[] decode = Base64.getDecoder().decode(encode); String s1 = new String(decode, UTF_8); System.out.println("decode: "+ s1); }
|
Base64.getEncoder().encodeToString
等效于 Base64.getEncoder().encode + new String(s,”UTF_8”)
JAVA代码Apache工具包实现
1 2 3 4 5 6 7 8 9
| public void base64(){ String s="2023兔年大吉"; byte[] bytes = Base64.encodeBase64(StringUtils.getBytesUtf8(s)); System.out.println("encode: " + StringUtils.newStringUtf8(bytes));
byte[] bytes1 = Base64.decodeBase64(StringUtils.newStringUtf8(bytes)); System.out.println("decode:" +StringUtils.newStringUtf8(bytes1));
}
|
Python代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import base64
s = "hello world".encode() encode = base64.b64encode(s) print(encode.decode()) decode = base64.b64decode(encode) print(decode.decode())
""" 输出: aGVsbG8gd29ybGQ= hello world """
|
URLEncode
简介
- 当字符串数据以
url
的形式传递给web服务器时,字符串中是不允许出现空格和特殊字符
- 因为
url
对字符有限制,比如把一个邮箱放入 url
,就需要使用 urlencode
函数,因为 url
中不能包含 @
字符。
url
转义其实也只是为了符合url
的规范而已。因为在标准的url
规范中中文和很多的字符是不允许出现在url
中
URLEncode原理
取出字符的ASCII码,转成16进制,然后前面加上百分号即可。如果是多字节的字符,则取出每一字节,按照同样的规则进行转换
如问号?
的ASCII码为63
,转换为16进制为3F
,所以%3F
即为?
进行Urlencode
编码的结果
JAVA
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Test public void url() throws UnsupportedEncodingException { String s = "梦断香消四十年,沈园柳老不吹绵。"; String encode = URLEncoder.encode(s, UTF_8); System.out.println("encode: "+ encode);
String decode = URLDecoder.decode(encode, UTF_8); System.out.println("decode:" + decode);
}
|
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| import urllib.parse
parse = "茨菰叶烂别西湾,莲子花开犹未还。" poem = { "name": "《江南行》", "author": "张潮" } encode_poem = urllib.parse.urlencode(poem) print(f'encode_poem: {encode_poem}')
decode_poem = urllib.parse.unquote(encode_poem) print(f'decode: {decode_poem}')
encode = urllib.parse.quote(parse) print("encode: " + encode)
decode = urllib.parse.unquote(encode) print(f'decode: {decode}')
""" encode_poem: name=%E3%80%8A%E6%B1%9F%E5%8D%97%E8%A1%8C%E3%80%8B&author=%E5%BC%A0%E6%BD%AE decode: name=《江南行》&author=张潮 encode: %E8%8C%A8%E8%8F%B0%E5%8F%B6%E7%83%82%E5%88%AB%E8%A5%BF%E6%B9%BE%EF%BC%8C%E8%8E%B2%E5%AD%90%E8%8A%B1%E5%BC%80%E7%8A%B9%E6%9C%AA%E8%BF%98%E3%80%82 decode: 茨菰叶烂别西湾,莲子花开犹未还。 """
|
MD5
MD5简介
MD5加密全程是Message-Digest Algoorithm
5(信息-摘要 算法),它对信息进行摘要采集,再通过一定的位运算,最终获取加密后的MD5字符串。
特点
- 针对不同长度待加密的数据、字符串等等,其都可以返回一个固定长度的MD5加密字符串。(通常32位的16进制字符串);
- 其加密过程几乎不可逆,除非维护一个庞大的Key-Value数据库来进行碰撞破解,否则几乎无法解开。
- 运算简便,且可实现方式多样,通过一定的处理方式也可以避免碰撞算法的破解。
- 对于一个固定的字符串。数字等等,MD5加密后的字符串是固定的,也就是说不管MD5加密多少次,都是同样的结果。
md5原理
1、对编码文本bit位数对512取模,要求%512=448,不足位在原始位后先加1后补0,直到满足条件
512bit/8 = 64位,也就是最后返回得固定位数,余448是为了在后面(512-448=)64bit放入原始长度
2、在这个结果后面附加一个以64位二进制表示的填充前信息长度(单位为Bit),如果二
进制表示的填充前信息长度超过64位,则取低64位。
3、经过这两步的处理,信息的位长=N512+448+64=(N+1)512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。
4、MD5的实现需要每512个字节进行一次处理,后一次处理的输入为前一次处理的输出,因此,在循环处理开始之前,需要拿4个标准数作为输入,它们分别是:
A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476;
5、进行N轮循环处理,将最后的结果输出
1 2 3 4 5 6 7 8 9
| 通过上面的标准128bit 输入,参与每组512bit 计算,得到一个新的128值,接着参与下一轮循环运算,最终得到一个128位的值; 具体运算: 这里用到4 个逻辑函数F,G,H,I,分别对应4 轮运算,它们将参与运算。(4轮16步) 第一轮逻辑函数:F(b,c,d)=(b&c)|((~b)&d) 参与第一轮的16 步运算 (b,c,d均为32位数) 第二轮逻辑函数:G(b,c,d)=(b&d)|(c&(~d)) 参与第二轮的16 步运算 第三轮逻辑函数:H(b,c,d)= bcd 参与第三轮的16 步运算 第四轮逻辑函数:I(b,c,d)= c^(b|(~d)) 参与第四轮的16 步运算 再引入一个移位函数MOVE(X,n),它将整型变量X 左循环移n 位,如变量X 为32 位,则MOVE(X,n)= (X << n) | (X >> (32 - n))。
|
JAVA代码实现
Apache.commons
工具包
1 2 3 4 5 6 7 8
| @Test public void testMD5() { String poem = "宿空房,秋夜长,夜长无寐天不明。"; String encode = DigestUtils.md5Hex(poem.getBytes());
System.out.println(encode); }
|
JDK
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
@Test public void test01() throws NoSuchAlgorithmException { String poem = "习习谷风,维山崔嵬"; MessageDigest md5 = MessageDigest.getInstance("MD5"); byte[] digest = md5.digest(poem.getBytes(UTF_8)); System.out.println(hexToStr(digest)); }
private String hexToStr(byte[] bytes) {
StringBuilder str = new StringBuilder(bytes.length * 2); final int fifteen = 0x0f; for (byte b : bytes) { str.append(HEX_CHARS[(b >> 4) & fifteen]); str.append(HEX_CHARS[b & fifteen]); } return str.toString(); }
|
SHA256和SHA512
SHA-256信息摘要算法,也是一种密码散列函数对于任意长度的消息,SHA256都会产生一个256bit长的散列值(哈希值)用于确保信息传输完整一致,称作消息摘要。这个摘要相当于是个长度为32个字节的数组,通常用一个长度为64的十六进制字符串来表示
SHA-512同理
原理同md5相似
SHA256代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class hashUtil {
private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
public static String hexToStr(byte[] bytes) { StringBuilder str = new StringBuilder(bytes.length * 2); final int fifteen = 0x0f; for (byte b : bytes) { str.append(HEX_CHARS[(b >> 4) & fifteen]); str.append(HEX_CHARS[b & fifteen]); } return str.toString(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Test public void sha256() throws NoSuchAlgorithmException {
String poem = "当时轻别意中人,山长水远知何处"; MessageDigest encode = MessageDigest.getInstance("SHA-256"); byte[] digest = encode.digest(poem.getBytes(UTF_8)); System.out.println(hashUtil.hexToStr(digest)); } @Test public void apasha256(){ String poem = "当时轻别意中人,山长水远知何处"; String encode = DigestUtils.sha256Hex(poem.getBytes(UTF_8)); System.out.println(encode); }
|
SHA512 代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Test public void sha512() throws NoSuchAlgorithmException { String poem = "当时轻别意中人,山长水远知何处"; MessageDigest encode = MessageDigest.getInstance("SHA-512"); byte[] digest = encode.digest(poem.getBytes(UTF_8)); System.out.println(hashUtil.hexToStr(digest)); }
@Test public void apasha512(){ String poem = "当时轻别意中人,山长水远知何处"; String encode = DigestUtils.sha512Hex(poem.getBytes(UTF_8)); System.out.println(encode); }
|