🍓
一.AES算法的CBC和ECB两种工作模式
AES是一种对称加密算法(加密和解密是同一把key)
应用场景:加密过程:使用密码对压缩包进行加密
解密过程:加密后的压缩包和原始密码进行解密
AES算法,传统的DES太过于简短,很容易暴力破解。所以有了AES算法。
AES每个分组数据的长度为128位16个字节,密钥长度可以是128位16个字节、192位或256位
本文主要介绍AES有两种模式:CBC和ECB
AES-128-ECB为指令长度。也是分组加密算法。对于长的明文,需要按照算法约定的块大小进行分组,AES每一组为16B,不同组之间使用相同的密钥进行计算的话,会产生一些安全问题,所以为了将分组密码应用到不同的实际应用。
1.1ECB实现
package ciper;
import java.security.GeneralSecurityException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
// AES + ECB
public class Work01 {
public static void main(String[] args) throws GeneralSecurityException {
// 原文:
String message = "天生我材必有用飞流直下三千尺";
System.out.println("Message(原始信息): " + message);
// 128位密钥 = 16 bytes Key:
byte[] key = "1234567890abcdef".getBytes();
// 加密:
byte[] data = message.getBytes();
byte[] encrypted = encrypt(key, data);
System.out.println("Encrypted(加密内容): " + Base64.getEncoder().encodeToString(encrypted));
// 解密:
byte[] decrypted = decrypt(key, encrypted);
System.out.println("Decrypted(解密内容): " + new String(decrypted));
}
// 加密:
public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 创建密码对象,需要传入算法/工作模式/填充模式
Cipher ciper=Cipher.getInstance("AES/ECS/PKCS5Padding");
// 根据key的字节内容,"恢复"秘钥对象
SecretKey sk=new SecretKeySpec(key,"AES");
// 初始化秘钥:设置加密模式ENCRYPT_
ciper.init(Cipher.ENCRYPT_MODE, sk);
// 根据原始内容(字节),进行加密
return ciper.doFinal(input);
}
// 解密:
public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 创建密码对象,需要传入算法/工作模式/填充模式
Cipher ciper =Cipher.getInstance("AES/ECS/PAS5padding");
// 根据key的字节内容,"恢复"秘钥对象
SecretKey keySpec =new SecretKeySpec(key,"AES");
// 初始化秘钥:设置解密模式DECRYPT_MODE
ciper.init(Cipher.DECRYPT_MODE, keySpec);
// 根据原始内容(字节),进行解密
return ciper.doFinal(input);
}
}
ECB模式很简单可能从性能角度讲非常占优,因为分组之间没有关联,可以独立并行计算。但从安全角度来看这种直接将密文分组进行拼接的方式,很可能会被攻击者猜解出明文特征或替换丢弃部分密文块达到明文的替换与截取效果。
AES-128-CBC模式就提出将明文分组先于一个随机值分组IV进行异或且本组的密文又与下一组的明文进行异或的方式,这种方式增加了密文的随机性。
算法原理:第一个明文分组在加密前明文a需要和一个初始分组IV进行异或运算 即 a^IV,然后再用密钥K进行标准的AES加密
1.2CBC实现
package ciper;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class work02 {
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
byte[] content= "奈何明月赵高去".getBytes();
byte[] key="2334344324324343".getBytes();
String x=entry(key,content);
System.out.println(x);
}
public static String entry(byte[] key,byte[] content) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException
{
Cipher cipher=Cipher.getInstance("CBC");
SecureRandom sr=new SecureRandom();
byte[] bytes=sr.generateSeed(16);
IvParameterSpec iv=new IvParameterSpec(bytes);
SecretKey key1=new SecretKeySpec(key,"CBC");
cipher.init(Cipher.ENCRYPT_MODE, key1,iv);
cipher.doFinal(content);
return join(iv,content);
}
public static String join(IvParameterSpec iv,byte[] content)
{
byte[] iv1=iv.getIV();
// byte[] newByte= new byte[iv1.length+content.length];
StringBuilder sx=new StringBuilder();
for(byte x:iv1)
{
sx.append(x);
}
for(byte x:content)
{
sx.append(x);
}
return sx.toString();
}
}
二,线程的实现方式
四种实现方式:继承Thread类,实现Runnable,Callable接口,线程池实现方式
package Thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
public class test {
public static void main(String[] args) {
Thread t1=new Thread() {
public void run()
{
System.out.println("线程1");
}
};
Thread t2=new Thread(new Runnable() {
public void run()
{
System.out.println("线程2");
}
}) ;
Thread t3=new Thread(new FutureTask<Integer>(new Callable() {
public Integer call()
{
System.out.println("线程3");
return 3;
}
}));
ExecutorService executorservice =Executors.newFixedThreadPool(1);
executorservice.execute(new Thread() {
public void run() {
System.out.println("线程4");
}
});
t1.start();
t2.start();
t3.start();
executorservice.shutdown();
}
}
三,线程池的执行流程
线程池的执行流程:
提交一个新线程任务,线程池会寻找空闲线程,通过可回收线程数是否小于核心线程数,来决定是否创建新线程。再判断线程池中的核心任务数是否超出,如果超出,将任务放进阻塞队列,如果阻塞队列已满,则将创建线程,如果创建线程数大于线程最大数,执行拒绝策略。
拒绝策略包括:
线程池的状态:running,shutdown,stop,tidying,terminated
线程池的优点:
- 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
- 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
- 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
线程池的定义:线程池就是事先创建若干个可执行的线程放入一个池中,需要的时候从池中取线程而不用自行创建,使用完毕后不用销毁线程而是返回池中,从而减少线程对象创建和销毁的开销。
线程池总结:
根据线程池的特点,包括,核心线程数的数量,最大线程数的个数,非核心线程的存留时间,工作队列的选择,可以在线程工厂创建具有一定特点的线程池。
fixed,cashed,signal,定时,周期性任务的scheduled线程池
四,ReentrantLock与synchronized
处理情景:在处理线程并发和维护指令原子性的过程中,用到了锁.
二者区别:
synchronized,使用对象:对象,实例方法,静态方法
- 用一个对象锁一个类两个方法。
- 当前对象当锁
- 锁两个Thread实现类,各自定义一个对象,修改构造方法,方便main函数传入相同对象锁,实现控制。
虽然synchronized可以实现锁控制,但是术业有专攻,可以使用ReentrantLock来实现锁。
在必要情况下,将synchronized控制到合理的范围,可以有效的提高服务器的效率。
synchronized锁可以分为
①内核态
CPU可以访问内存所有数据,包括外围设备,例如硬盘,网卡。CPU也可以将自己从一个程序切换到另一个程序。
②用户态
只能受限的访问内存,且不允许访问外围设备,占用CPU的能力被剥夺,CPU资源可以被其他程序获取。
锁的实现依靠于操作系统,内核态和用户态的切换是非常耗费资源的,用户态不允许访问内核态。
synchronized是关键字,ReentrantLock属于类,只能用于代码块
synchronized是可重入锁,ReentrantLock是可重入锁
synchronized非公平,ReentrantLock公平和非公平。
synchronized更灵活,可以以类的方式,也可以以方法的形式,也可以以对象的方式
ReentrantLock只能以对象的形式
获取锁的方式:ReentrantLock通过tryLock()方式获取,synchronized通过线程抢占模型获取锁。
释放锁的方式:ReentrantLock必须unlock(),synchronized自动释放锁。
1、 sleep 来自 Thread 类,和 wait 来自 Object 类。
2、最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
3、wait,notify和 notifyAll 只能在同步控制方法或者同步控制块里面使用,而 sleep 可以在任何地方使用(使用范围)。
4、 sleep 必须捕获异常,而 wait , notify 和 notifyAll 不需要捕获异常。
结束之前,我想说的是,学无止尽,积极讨论是高效的一种学习方式💚❤️💙
😘 感谢大佬们的支持,欢迎各位前来不吝赐教。每篇文章都会积极更新。