常用加密算法(一)

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 实现:
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)); // 输出为:5YWU5bm06aG25ZGx5ZGx

    String asB64 = Base64.getEncoder().encodeToString("some string".getBytes("utf-8"));
    System.out.println(asB64); // 输出为: c29tZSBzdHJpbmc=

    byte[] decode = Base64.getDecoder().decode(encode);
    String s1 = new String(decode, UTF_8);
    System.out.println("decode: "+ s1);//decode: 兔年顶呱呱
}

Base64.getEncoder().encodeToString 等效于 Base64.getEncoder().encode + new String(s,“UTF_8”)

JAVA代码Apache工具包实现
   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代码实现:
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
    @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);

    }
/*
encode: %E6%A2%A6%E6%96%AD%E9%A6%99%E6%B6%88%E5%9B%9B%E5%8D%81%E5%B9%B4%EF%BC%8C%E6%B2%88%E5%9B%AD%E6%9F%B3%E8%80%81%E4%B8%8D%E5%90%B9%E7%BB%B5%E3%80%82
decode:梦断香消四十年,沈园柳老不吹绵。
*/
Python
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、经过这两步的处理,信息的位长=N*512+448+64=(N+1)*512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。

4、MD5的实现需要每512个字节进行一次处理,后一次处理的输入为前一次处理的输出,因此,在循环处理开始之前,需要拿4个标准数作为输入,它们分别是:

A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476;

5、进行N轮循环处理,将最后的结果输出

通过上面的标准128bit 输入,参与每组512bit 计算,得到一个新的128值,接着参与下一轮循环运算,最终得到一个128位的值;
具体运算:
这里用到4 个逻辑函数F,G,H,I,分别对应4 轮运算,它们将参与运算。(416步)
第一轮逻辑函数: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 位,如变量X32 位,则MOVE(X,n)= (X
<< n) | (X >> (32 - n))
JAVA代码实现

Apache.commons工具包

  @Test
    public void testMD5() {
        String poem = "宿空房,秋夜长,夜长无寐天不明。";
        // 基于apache.commons框架中的DigestUtils工具类进行密码加密
        String encode = DigestUtils.md5Hex(poem.getBytes());

        System.out.println(encode);
    }

JDK

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) {
//        897b01ff2de4733038564c342d59252d
        StringBuilder str = new StringBuilder(bytes.length * 2);
        final int fifteen = 0x0f;//十六进制中的 15
        for (byte b : bytes) {//byte 为 32 位
            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代码实现
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;//十六进制中的 15
        for (byte b : bytes) {//byte 为 32 位
            str.append(HEX_CHARS[(b >> 4) & fifteen]);//高四位
            str.append(HEX_CHARS[b & fifteen]);//低四位
        }
        return str.toString();
    }
}
//    JDK原生
    @Test
    public void sha256() throws NoSuchAlgorithmException {
//        92dd9f6a5b38c773b7b6ac894d9538917d75674d18336aba8eaaa3742ada6a46
        String poem = "当时轻别意中人,山长水远知何处";
        MessageDigest encode = MessageDigest.getInstance("SHA-256");
        byte[] digest = encode.digest(poem.getBytes(UTF_8));
        System.out.println(hashUtil.hexToStr(digest));
    }
	//apache工具包
    @Test
    public void apasha256(){
        String poem = "当时轻别意中人,山长水远知何处";
        String encode = DigestUtils.sha256Hex(poem.getBytes(UTF_8));
        System.out.println(encode);
    }
SHA512 代码实现
//    JDK原生
    @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));
    }

//    apache 工具包
//    c8da19b2c1b111952e338a73f71826ab6c759088c8e61093161d1112a632de75dc469a54ac6d98c0b84e460ed8911f5d5428d4aff812f39784b4763658efc292
    @Test
    public void apasha512(){
        String poem = "当时轻别意中人,山长水远知何处";
        String encode = DigestUtils.sha512Hex(poem.getBytes(UTF_8));
        System.out.println(encode);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值