Java安全编程
声明:学习内容来自b站尚硅谷视频:https://www.bilibili.com/video/BV1tz4y197hm?from=search&seid=16699194548616133080&spm_id_from=333.337.0.0
一.古典密码学
1.1 替换法
-
分为单表替换和多表替换
-
单表替换:替换的规则在同一张表上。
-
多表替换:替换的规则在不同张表上。
- 例子如下:
-
表1:abcde-swtrp 表2:abcde-chfhk 表3:abcde-jftou 原文:bee 密钥:312 (密钥:指示去哪个表找,定义的是规则) 密文:fpk
-
1.2 移位法
- 按照字母在字母表上的位置,进行移动的加密方式
- 著名的加密算法:凯撒加密
- 如:abcde 往后移动两位 cdefg
1.3 破解方法
- 频率分析法:
- 通过统计密文的英文等字符出现的概率,与明文统计出的字符出现概率进行比对。应用了概率论的知识。
- 即 在密文中统计出频率最高的字符=明文中出现频率最高的字符,然后由ASCII码推出它们的密钥值(即移动了多少位),从而推导原文。
二.现代密码学
2.1 散列函数(哈希函数)
- 常见有MD5,SHA-1,SHA256
2.2 对称加密
-
用同一把密钥进行加密解密。
-
特点:
- 加密速度快
- 密文不可逆,密钥不能泄露
- 若在编码表上找不到对应的字符,则会乱码
- 常结合base64一起使用
-
Java编程(这里运用了流进行读取加密内容,可自行简化与拓展):
-
String algorithm = "DES"; // 或则“AES”算法 String transformation = "DES/ECB/PKCS5Padding" //“算法/加密模式/填充模式” //定义密钥,DES算法密钥字节数要为8 String key = "45826954"; //DES需要8个字节;换成AES则需要16个字节 //获取Cipher对象 Cipher cipher = Cipher.getInstance(transformation); //定义加密规则 SecretKeySpec spec = new SecretKeySpec(key.getBytes(),algorithm); //初始化cipher cipher.init(Cipher.ENCRYPT_MODE,spec); //解密用cipher.init(Cipher.DECRYPT_MODE,spec); FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(encFile); byte[] bytes = new byte[1024]; int len; while((len = fis.read(bytes))!=-1){ //调用加密方法 byte[] newBytes = cipher.doFinal(bytes, 0, len); //由于出现乱码,用base64加密一下 byte[] encode = Base64.getEncoder().encode(newBytes); fos.write(encode,0,encode.length); //解密用 byte[] decode = Base64.getMimeDecoder().decode(bytes); byte[] newBytes = cipher.doFinal(decode, 0, decode.length); fos.write(newBytes,0,newBytes.length); } fis.close(); fos.close();
-
2.3 非对称加密
- 有两把密钥,用公钥和私钥进行加密解密。
- 若公钥加密,必须私钥解密;私钥加密,必须公钥解密。
2.4 如何设置密码才安全
- 密码不要太常见,如 123456。
- 各个软件的账户密码不要一样,防止泄漏一个,导致全部泄漏。
- 设置密码可加特殊的标记,如京东 jd,淘宝 tb。
2.5 byte和bit
- 1byte = 8 bit
- java中:
-
中文,如String a=“我”:
- 在UTF-8编码下:1个中文 = 3个字节;在GBK下:1个中文 = 2个字节
-
英文/数字,如String a=“1”:
- 一个英文/数字 = 1个字节
-
2.6 base64和base58
- base64
- base64是可读性算法,不是加密算法
- 由64个字符组成,由大小写字母a-z,数字0-9,+,/组成。
- 原理:
- 传输3个字节,将3个字节分成4组,每组6个字节,并在每组的最高位补2个0。
- 这样每组的范围就是0~63,如111 111 ,32+16+8+4+2+1=63.然后去base64的表查对应的字符。
- 3个字节为一组,若位数不够则用=补齐。
- 例子:如传输的数据是34 00 a9,则base64编码后为 N A B P。
- base58
- 一般用是比特币里的编码方式。
- 区别:
- base58没有 数字0,字母o,I,i,字符+,/
2.7 ASCII表:
2.8 加密模式:
-
ECB(Electronic codebook电子密码本):将加密的消息按块大小分块,并对每个块独立加密。
- 优点:并行加密,速度块。
- 缺点:同样的原文生成同样的密文,不够安全。
-
CBC(Cipher-block chaining密码块链接):每个明文块要先与前一个密文快进行异或后,在进行加密。
-
优点:安全;缺点:效率低。
-
使用CBC加密模式:
-
String algorithm = "DES"; String transformation = "DES/CBC/PKCS5Padding" //“算法/加密模式/填充模式” String key = "45826954"; Cipher cipher = Cipher.getInstance(transformation); SecretKeySpec spec = new SecretKeySpec(key.getBytes(),algorithm); //这里需要定义iv向量 IvParameterSpec iv = new IvParameterSpec(key.getBytes()); cipher.init(Cipher.ENCRYPT_MODE,spec,iv);//若填充模式是NoPadding,则key需要8个字节 FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(encFile); byte[] bytes = new byte[1024]; int len; while((len = fis.read(bytes))!=-1){ //调用加密方法 byte[] newBytes = cipher.doFinal(bytes, 0, len); //由于出现乱码,用base64加密一下 byte[] encode = Base64.getEncoder().encode(newBytes); fos.write(encode,0,encode.length); //解密用 byte[] decode = Base64.getMimeDecoder().decode(bytes); byte[] newBytes = cipher.doFinal(decode, 0, decode.length); fos.write(newBytes,0,newBytes.length); } fis.close(); fos.close();
-
-
2.9 填充模式:
- NoPadding:不填充
- 不填充的话,DES算法下,原文需要8字节整数倍;
- AES算法下,原文需要16字节整数倍.
- PKCS5Padding:数据块大小为8位,不够就填充。
2.10 消息摘要(数字摘要):
-
特点:
- 是一个值,唯一对应一个消息或文本的固定长度的值。是由hash加密函数对消息作用产生的。
- 使用消息摘要生成的值不可被篡改。
-
参见算法:
-
MD5,SHA1,SHA256,SHA512
-
Java编程:
-
String algorithm = "MD5"; MessageDigest digest = MessageDigest.getInstance(algorithm); FileInputStream fis = new FileInputStream(srcFile); FileOutputStream fos = new FileOutputStream(encFile); byte[] bytes = new byte[1024]; int len; while((len = fis.read(bytes))!=-1){ byte[] newBytes = digest.digest(bytes); String str=""; //将密文转化为16进制 for (byte newByte : newBytes) { String s = Integer.toHexString(newByte&0xff); if(s.length()==1) s="0"+s; str = str+s; } System.out.println(str); fos.write(str.getBytes(),0,str.getBytes().length); } fis.close(); fos.close();
-
2.11 非对称加密:
-
特点:
- 有一对密钥对,为公钥和私钥。
- 若用公钥加密,则使用私钥解密;反之亦然。
-
常见算法:
- RSA,ECC
-
java编程:
-
//生成公钥和私钥 String algorithm = "RSA"; KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm); KeyPair keyPair = keyPairGenerator.genKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); //加密,解密类似 String algorithm = "RSA"; //获取Cipher对象 Cipher cipher = Cipher.getInstance(algorithm); //初始化cipher cipher.init(Cipher.ENCRYPT_MODE,privateKey); //调用加密方法 byte[] newBytes = cipher.doFinal(bytes, 0, len);
-
-
读取公钥:
-
读取私钥:
2.12 数字签名
-
特点:
- 公钥数字签名,只能由信息的发送者才能产生的一段数字串。
-
例子:
-
张三:对邮件进行hash生成数字摘要,在对摘要进行私钥加密,生成数字签名。发送过去。
朋友:对收到的邮件,对数字签名进行公钥解密,生成数字摘要。用hash函数对邮件内容进行计算得出数字摘要,跟另一个的数字摘要进行对比。若相同,则邮件没被修改。
-
-
Java编程:
-
//生成数字签名 private String getSignature(String input,String algorithm,PrivateKey privateKey) throws Exception { Signature signature = Signature.getInstance(algorithm); signature.initSign(privateKey); signature.update(input.getBytes()); byte[] sign = signature.sign(); return new String(Base64.getEncoder().encode(sign)); } //校验数字签名 private boolean verifySignature(String input,String algorithm,PublicKey publicKey,String signaturedDate) throws Exception { Signature signature = Signature.getInstance(algorithm); signature.initVerify(publicKey); signature.update(input.getBytes()); return signature.verify(Base64.getDecoder().decode(signaturedDate)); } String signature = getSignature("aaaaa1", "sha256withrsa", privateKey); System.out.println(signature); boolean b = verifySignature("aaaaa", "sha256withrsa", publicKey, signature); System.out.println(b);
-
2.13 数字证书
-
特点:
- 由权威的认证机构将 公钥,数字签名 打包成的东西 数字证书。
-
CA认证中心:采用公开密钥基础架构技术(PKI),负责签发和管理数字证书。