美文网首页
Java 密码学习(上)

Java 密码学习(上)

作者: CSeroad | 来源:发表于2020-11-06 15:50 被阅读0次

前言

最近在学习java编程,在学习到编码一块时,想着系统的学习并整理一下java和密码学这块的知识点。
密码学大概像中国的历史发展一样,可分为古典密码学、近代密码学、现代密码学。

古典密码学

古典密码主要是替换密码和移位密码。核心原理也就是替换法、移位法。

替换法

替换法也有两种,单表替换和多表替换。
单表替换即原文和密文用的同一张表
如表:j替换u,a替换q,v替换为f
所以明文java替换后变密文uqfq。
也有多表替换,即原文和密文用的是多张表
如:表 abcdef---swtrpv、abcdef---chfhkd、abcdef---jftoud
秘钥为 312
表示分别替换第三张表、第一张表、第二张表
则明文的abc替换后为密文sht。

移位法

移位法就是将原文所有字母在字母表上按照一个固定数组进行前后移位,得出密文。
如:明文abcde变为密文cdefg,就是在字母表里每个字母分别往后移动两位。
典型的移位法应用有"恺撒加密"。

java 代码实现"恺撒加密"

package javaweb.com.demo;

public class Encryption {
    public static void main(String[] args) throws Exception {
        String a = "cseroad";
        int key = 3;
        char[] chars = a.toCharArray();
        //字符串变成字节数组
        StringBuilder sb = new StringBuilder();
        for (char c : chars) {
            int ascii = c;
            ascii = ascii + key;
            //向右移动三位后的ascii
            char newa =  (char)ascii;
            //System.out.println(newa);
            sb.append(newa);
        }
        System.out.println("密文:"+sb.toString());
        //转化为String对象
    }
}

近代密码学

恩尼格玛机,本质上使用的还是替换和移位。后被图灵破解。

现代密码学

密码学基础

ASCII编码

我们知道在计算机中,存储数据都是用二进制表示的(即0和1)。那么像我们平时用到的字母、数字也是需要用二进制表示。于是有了ASCII编码表来统一进行换算。

java实现求字符对应的ASCII编码

package javaweb.com.demo;

public class Encryption {
    public static void main(String[] args) throws Exception {
        char a = 'a';
        int b = a;
        System.out.println(b);
    }
}

即char字符类型自动转化为int类型。
字符a的ASCII码为97,存储到计算机的二进制为0110 0001。

Unicode编码

那么汉字、日文、韩文又是怎么在计算机中存储的呢?
这就有了Unicode编码表,也被称为万国码。为每种语言每个字符设置了统一并唯一的二进制编码。包含ASCII码,从0到127的字符。如上面的a的ASCII码为97,十六进制为61,则unicode编码为0x0061。该编码一般用十六进制表示。

package javaweb.com.demo;

public class Encryption {
    public static void main(String[] args) throws Exception {
        char a = '经';
        int b = a;
        System.out.println(b);
    }
}
image.png

汉字"经"的十六进制为0x7ecf,转化十进制就是32463,即输出值。
但是char只能存储单一的字符。如果遇到字符串呢?

java实现求字符串对应的ASCII编码

package javaweb.com.demo;

public class Encryption {
    public static void main(String[] args) throws Exception {
        String a = "cseroad";
        char[] chars = a.toCharArray();
        //字符串转化为字节数组,然后遍历字符
        for (char c : chars) {
            int ascii = c;
            System.out.println(ascii);
        }
        
    }
}

需要补充的是,UTF-8是Unicode实现的方式之一。两者之间也是通过程序进行转换的。
转换规则参考 字符编码笔记:ASCII,Unicode 和 UTF-8

二进制位

不管是什么编码方式,运行在计算机里只能是二进制数。

java 实现求某字符串二进制数

package javaweb.com.demo;

public class Encryption {
    public static void main(String[] args) throws Exception {
        String a = "经";
        byte[] bytes = a.getBytes("UTF-8");
        for (byte c : bytes) {
            int ascii = c;
            String s = Integer.toBinaryString(ascii);
            System.out.println("二进制值:"+s);
        }
        
    }
}
image.png

UTF-8编码格式下,一个中文等于3个字节,一个字节等于8个二进制位。
GBK 编码格式下,一个中文等于2个字节,一个字节等于8个二进制位。

char和byte区别

char

  • 字符数据类型,占两个字节,无符号
  • 范围在0-65535之间
  • 不可以表示负数,但是可以表示中文

byte

  • 字节数据类型,有符号
  • 范围在-128-127之间
  • 可以和 ASCII 码相互转换,不可以表示中文
  • 一字节等于8个二进制位

编码方式

URL编码

url编码指的是浏览器发送到服务器时使用的编码,用来便于浏览器和服务器进行通信。
url编码就是一个字符ascii码的十六进制,每个字节前面添加%。

java 实现url编码

package javaweb.com.demo;

import java.net.URLDecoder;
import java.net.URLEncoder;

public class Encryption {

    public static void main(String[] args) throws Exception {
        String old = "url 编码";
        String encode = URLEncoder.encode(old,"UTF-8");
        System.out.println(encode);
        
        String decode = URLDecoder.decode(encode,"UTF-8");
        System.out.println(decode);
    }

}

Base64编码

base64编码是一种基于64个字符把二进制数据用文本表示的编码算法,方便传输,提高可读性。
分别是A-Z、a-z、0-9、两个字符+和/,正好64个字符。

原理
每3个8位二进制转化为4个6位二进制数,然后在每个6位二进制数都填两个高位0,得到4个8位二进制数,如果缺位则补0。再将其分别转化为十进制,最后通过base64编码表获取编码后字符。

如:
字符串"中国" 的utf-8编码对应的十六进制为e4b8ad、e59bbd
转化二进制为111001001011100010101101、111001011001101110111101
然后每6个二进制位为1组。

111001
001011
100010
101101
111001
011001
101110
111101

再分别填补两个高位0。

00111001
00001011
00100010
00101101
00111001
00011001
00101110
00111101

再转化十进制为57、11、34、45、57、25、46、61
按照base64编码表转为5Lit5Zu9

image.png

java 实现base64编码

package javaweb.com.demo;

import java.util.Base64;

public class Encryption {

    public static void main(String[] args) throws Exception {
        String old = "中国";
        //encode
        String bs64 = Base64.getEncoder().encodeToString(old.getBytes("UTF-8"));
        System.out.println(bs64);
        
        //decode
        String ori = new String(Base64.getDecoder().decode(bs64),"UTF-8");
        System.out.println(ori);
    }

}
image.png

消息摘要算法

消息摘要算法也叫散列算法、哈希函数、单向函数。是一种将任意长度输入转换为固定长度输出的算法。
主要作用不是用于加密与解密,而是用于验证信息的完整性。常用于密码加密、文件校验。
消息摘要算法主要分为三类,MD(消息摘要算法)、SHA(安全散列算法)、MAC(消息认证码算法)
常见的消息摘要算法有MD5、SHA-1、SHA-256、SHA-512等等。

MD5

md5的长度默认为128个二进制位,这样表达是很不友好的,所以将二进制转成了16进制,每4个二进制位表示一个16进制,所以就变为32位了。

package javaweb.com.demo;

import java.security.MessageDigest;

public class Encryption {

    public static void main(String[] args) throws Exception {
        String input = "cseroad";
        //明文
        String algorithm = "MD5";
        //加密类型
        MessageDigest md = MessageDigest.getInstance(algorithm);
        //初始化
        md.update(input.getBytes("UTF-8"));
        //更新摘要
        byte[]  r = md.digest();
        //获得密文完成哈希计算
        StringBuilder sb = new StringBuilder();
        for (byte b : r) {
            String s = Integer.toHexString(b & 0xff);
            //密文10进制转16进制
            if (s.length() == 1) {
                s = "0"+s;
            }
            //判断如果密文长度为1,高位需要补0
            sb.append(s);
        }
        
        System.out.println(sb.toString());
    }
}
image.png

要点
使用MessageDigest类用于为应用程序提供信息摘要算法的功能。要实现SHA-1、SHA-256、SHA-512 替换algorithm变量即可。

也可以通过BigInteger类处理任意精度的整数运算,这样代码比较简洁。
java 实现MD5加密

package javaweb.com.demo;

import java.math.BigInteger;
import java.security.MessageDigest;

public class Encryption {

    public static void main(String[] args) throws Exception {
        String input = "cseroad";
        String algorithm = "MD5";
        MessageDigest md = MessageDigest.getInstance(algorithm);
        md.update(input.getBytes("UTF-8"));
        byte[]  r = md.digest();
        BigInteger a = new BigInteger(1,r);
        //转化为16进制
        System.out.println(String.format("%032x",a));
    } 
}

SHA-1

java实现SHA-1加密

package javaweb.com.demo;

import java.math.BigInteger;
import java.security.MessageDigest;

public class Encryption {

    public static void main(String[] args) throws Exception {
        String input = "cseroad";
        String algorithm = "SHA-1";
        MessageDigest md = MessageDigest.getInstance(algorithm);
        md.update(input.getBytes("UTF-8"));
        byte[]  r = md.digest();
        BigInteger a = new BigInteger(1,r);
        //转化为16进制
        System.out.println(String.format("%040x",a));
    } 
}
image.png

SHA-1的返回值时160位二进制位,同样和MD5一样,每四个二进制位换算为一个16进制,所以结果为40位。

盐salt
在密码学中,是指通过在任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为"加盐"。
注意加盐的目的是为了增加攻击者破解的难度,所以盐值不能太短,也不能使用固定盐值。

参考资料

https://www.bilibili.com/video/BV134411T7rq
https://www.bilibili.com/video/BV1ga4y1v7jn
《java 加密与解密的艺术》

相关文章

  • Java 密码学习(上)

    前言 最近在学习java编程,在学习到编码一块时,想着系统的学习并整理一下java和密码学这块的知识点。密码学大概...

  • Java 密码学习(下)

    前言 接上文java密码学习,继续学习现代密码学 现代密码学 位运算加密 位运算指的是内存中二进制为的操作。 举个...

  • 学习Android从入门到成仙

    巧妇难为无米之炊,要学习就得先有资料:【Java基础篇】《21天学通Java》密码: n1ux 《疯狂Java讲义...

  • Java学习(上)

    前言 暑假的时候学过一段时间的Java,但只是自己买一本书来看,书中的一大段一大段文字显得十分生硬,因此学完之后感...

  • Java JCE Cipher 详解

    本文是对 Java 语言安全模块 JCE( Java Cryptography Extension,Java 密码...

  • Android开发学习——Day14(文件操作&实战:模拟手势密

    学习目的 1.文件操作 2.实战:模拟手势密码解锁 学习过程 在Java文档中查询文件操作的类及其方法,练习其使用...

  • JCA/JCE/JSSE等Java密码框架

    JCA/JCE 概念简单解析1) Java密码学架构(Java Cryptography Architectur...

  • java堆学习(上)

    这是一篇自己关于学习java堆的笔记,用来记录自己学习java堆的过程。 1、堆的核心概述 堆是jvm中运行时数据...

  • Java分组密码算法DES

    Java分组密码算法DES 1实验内容 掌握分组密码算法DES方法,能用高级语言实现分组密码算法DES。DES算法...

  • Java开发学习路线图,成都Java培训课程大纲

    Java开发学习路线图,这是大家在学习Java开发时必要的素材,现在网络上也有不少的Java学习路线图。但是从实用...

网友评论

      本文标题:Java 密码学习(上)

      本文链接:https://www.haomeiwen.com/subject/pdtuvktx.html