首先应当区分加密与编码并不是一回事。
加密方式主要有3种:
可逆
【对称加密】:symmetric,例如 AES、DES 等。
【非对称加密】:asymmetric,例如 RSA、DSA 等。
不可逆
加解密思想:将一种排序好的二进制,转变为另一种排序的二进制。
注意:在加密后得到的是二进制数据,一般来说我们需要将其转变为更加容易阅读的十六进制范式,两种方式
String en = Base64.getEncoder().encodeToString( endoce );
// 默认的2进制转16进制。【1】表示整数,不加可能得负值(结果出错)
String encodeHex = new BigInteger(1,msg).toString(16);
// 16进制数据转2进制
new BigInteger("1f6f", 16).toString(2)
16进制一般针对无法显示的一些二进制进行显示,常用于:
【英语翻译】:
BouncyCastle库:
一个提供了很多哈希算法和加密算法的第三方库。它包含了Java原生中所缺失的一些加密方式(如国产算法),需要时再导入。
<!-- jdk15on 代表适用于 jdk1.5 以上的版本而不是 jdk15 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
在接下来的章节中,为了达到快速开发的目的,我会结合着Java辅助开发框架【hutool】来讲解。
<!-- pom 导包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-crypto</artifactId>
<version>5.8.5</version>
</dependency>
简介
分组加密:也叫块加密(block cyphers),一次加密明文中的一个块。
序列加密:也叫流加密(stream cyphers),一次加密明文中的一个位。
加密方式:
工作模式(6种):维基百科
填充模式(9种):
FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07
FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF 3F 7A B4 09 14 36 07
FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF 80 00 00 00 00 00 00
FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00
FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 07
FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00
FF FF FF FF FF FF FF FF F0
FF FF FF FF FF FF FF FF F0 FF FF FF FF FF FF FF
密匙长度:
以AES为例,密匙长度指的就是 key 的长度,有AES128、AES192、AES256之分,密匙长度越长、保护性就越强、所需要的计算量就越大。密钥长度根据指定密钥位数分别为16、24、32个字符,IV与密钥超过长度则截取,不足则在末尾填充’\0’补足,选择了对应长度的密匙加密方式,密匙本身长度也要跟上。
AES,ECB模式加密
简介:
步骤:
【Java原生-加密】
String message = "待加密内容";
byte[] data = message.getBytes("UTF-8");
// 128位 = 16 byte 的 key 值
byte[] key = "1234567890abcdef".getBytes("UTF-8");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey keySpec = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec); // 初始化加密工具
byte[] encrypted = cipher.doFinal(data); // 加密
String en = Base64.getEncoder().encodeToString(encrypted);
byte[] key = "1234567890abcdef".getBytes("UTF-8");
byte[] decode = Base64.getDecoder()
.decode("AYpKX4YMIhmojH89B3Pd9Q==");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKey keySpec = new SecretKeySpec(key, "AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec); // 解密模式
byte[] bytes = cipher.doFinal(decode);
String msg = new String(bytes,"utf-8");
System.out.println(msg); // 输出(正确):“待加密内容”
String content = "中文";
//随机生成密钥,当然也可以自定义
byte[] key = SecureUtil
.generateKey(SymmetricAlgorithm.AES.getValue())
.getEncoded();
//构建【对称加密类(工具)】
AES aes = SecureUtil.aes(key);
// 1. 普通加密、解密
byte[] encrypt = aes.encrypt(content);
byte[] decrypt = aes.decrypt(encrypt);
// 2. 加密、解密为16进制字符。
String encryptHex = aes.encryptHex(content);
String decryptStr = aes.decryptStr(encryptHex);
AES,CBC模式加密
简介:
需要一个随机数作为IV(Initialization Vector)初始化因子,这样对于同一份明文,每次生成的密文都会不同。IV参数不需要保密,在解密的时候作入参传入。IOS等移动端对AES加密有要求,必须为PKCS7Padding模式。
【原生】简单复合案例
public class Main {
public static void main(String[] args) throws Exception {
// 原文:
String message = "Hello, world!";
System.out.println("Message: " + message);
// 256位密钥 = 32 bytes Key:
byte[] key = "1234567890abcdef1234567890abcdef".getBytes("UTF-8");
// 加密:
byte[] data = message.getBytes("UTF-8");
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, "UTF-8"));
}
// 加密:
public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
// CBC模式需要生成一个16 bytes的initialization vector:
SecureRandom sr = SecureRandom.getInstanceStrong();
byte[] iv = sr.generateSeed(16);
IvParameterSpec ivps = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivps);
byte[] data = cipher.doFinal(input);
// IV不需要保密,把IV和密文一起返回:
return join(iv, data);
}
// 解密:
public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
// 把input分割成IV和密文:
byte[] iv = new byte[16];
byte[] data = new byte[input.length - 16];
System.arraycopy(input, 0, iv, 0, 16);
System.arraycopy(input, 16, data, 0, data.length);
// 解密:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivps = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivps);
return cipher.doFinal(data);
}
public static byte[] join(byte[] bs1, byte[] bs2) {
byte[] r = new byte[bs1.length + bs2.length];
System.arraycopy(bs1, 0, r, 0, bs1.length);
System.arraycopy(bs2, 0, r, bs1.length, bs2.length);
return r;
}
}
AES aes = new AES(Mode.CBC,Padding.PKCS5Padding,
"0123456789ABHAEQ".getBytes(), // 密匙key
"DYgjCEIMVrj2W9xN".getBytes()); // iv加盐
// 加密、解密,16进制表示
String encryptHex = aes.encryptHex(content);
String decryptStr = aes.decryptStr(encryptHex);
简介
【必要性说明】
非对称加密相较于对称加密速度慢、效率低,实际开发中,非对称加密总是和对称加密一起使用。
RAS加密
public class Main {
public static void main(String[] args) throws Exception {
// 明文:
byte[] plain = "Hello, encrypt use RSA".getBytes("UTF-8");
// 创建公钥/私钥对:
Person alice = new Person("Alice");
// 用Alice的公钥加密:
byte[] pk = alice.getPublicKey();
System.out.println(String.format("public key: %x", new BigInteger(1, pk)));
byte[] encrypted = alice.encrypt(plain);
System.out.println(String.format("encrypted: %x", new BigInteger(1, encrypted)));
// 用Alice的私钥解密:
byte[] sk = alice.getPrivateKey();
System.out.println(String.format("private key: %x", new BigInteger(1, sk)));
byte[] decrypted = alice.decrypt(encrypted);
System.out.println(new String(decrypted, "UTF-8"));
}
}
class Person {
String name;
// 私钥:
PrivateKey sk;
// 公钥:
PublicKey pk;
public Person(String name) throws GeneralSecurityException {
this.name = name;
// 生成公钥/私钥对:
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
kpGen.initialize(1024);
KeyPair kp = kpGen.generateKeyPair();
this.sk = kp.getPrivate();
this.pk = kp.getPublic();
}
// 把私钥导出为字节
public byte[] getPrivateKey() {
return this.sk.getEncoded();
}
// 把公钥导出为字节
public byte[] getPublicKey() {
return this.pk.getEncoded();
}
// 用公钥加密:
public byte[] encrypt(byte[] message) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, this.pk);
return cipher.doFinal(message);
}
// 用私钥解密:
public byte[] decrypt(byte[] input) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, this.sk);
return cipher.doFinal(input);
}
}
// 构建 RSA 加密工具,可传参【公匙】与【私匙】。
AsymmetricCrypto rsa = new AsymmetricCrypto("RSA");
// 获得私钥,可存储于其他文件中
PrivateKey sk = rsa.getPrivateKey();
String sk64 = rsa.getPrivateKeyBase64();
// 获得公钥,可存储于其他文件中
PublicKey pk = rsa.getPublicKey();
String pk64 = rsa.getPublicKeyBase64();
// 公钥加密,私钥解密
String encode = rsa.encryptBase64("中文", KeyType.PublicKey);
String decode = rsa.decryptStr(encode, KeyType.PrivateKey);
RAS签名
// 生成RSA公钥、私钥
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
kpGen.initialize(1024);
KeyPair kp = kpGen.generateKeyPair();
PrivateKey sk = kp.getPrivate();
PublicKey pk = kp.getPublic();
// 待签名的消息
byte[] message = "中文".getBytes(StandardCharsets.UTF_8);
// 用私钥签名
Signature signSk = Signature.getInstance("SHA1withRSA");
signSk.initSign(sk);
signSk.update(message);
byte[] signed = signSk.sign();
System.out.println(String.format("signature: %x", new BigInteger(1, signed)));
// 用公钥验证,最后得到的是Boolean值,判断真假。
Signature signPk = Signature.getInstance("SHA1withRSA");
signPk.initVerify(pk);
signPk.update(message);
boolean valid = signPk.verify(signed);
System.out.println("valid? " + valid);
byte[] data = "中文".getBytes();
Sign sign = SecureUtil.sign(SignAlgorithm.MD5withRSA);
//签名
byte[] signed = sign.sign(data);
//验证签名
boolean verify = sign.verify(data, signed);
System.out.println(verify);
// 可以将本次生成的私匙与公匙保存到文件
PublicKey pk = sign.getPublicKey();
PrivateKey sk = sign.getPrivateKey();
简介
加盐思想:为什么加盐能够防止黑客通过彩虹表破解?
因为在没有加盐时,黑客拥有一张通过大量时间计算得出来的“彩虹表1”,可以轻易的碰撞到原始密码。当我们加盐之后,由于盐值可以是随机的(比如盐值为用户名),此时黑客就需要重新计算大量数据,这种计算是极其耗费时间的。
Java原生哈希算法:输入任意字符,输出固定4字节int型整数。
// 1. hash 后获得十进制数
Integer code = "Java".hashCode();
// 2. 将十进制数转为十六进制数
String hashString = Integer.toHexString(code);
// 3. 输出(0x)231e42,4字符 = 32位 = 长度为2+6的十六进制数。
System.out.println(hashString);
常见Hash算法
hutool提供了一些哈希算法实现
MD5加密:不加盐版
// 获取MessageDigest实例:
MessageDigest md = MessageDigest.getInstance("MD5");
// 反复调用update输入数据:
md.update("中".getBytes("UTF-8"));
md.update("文".getBytes("UTF-8"));
// a7bac2239fcdcb3a067903d8077c4a07
byte[] result = md.digest();
System.out.println(new BigInteger(1, result).toString(16));
String testStr = "中文";
Digester md5 = new Digester(DigestAlgorithm.MD5);
String digestHex = md5.digestHex(testStr);
// a7bac2239fcdcb3a067903d8077c4a07
System.out.println(digestHex);
MD5加密:加盐版。
加盐本质:拼接字符串再加密。
【原生】:直接拼接字符串,将 key 与 原文拼接一起再 encry。
【Hmac算法】:Hash-based Message Authentication Code,Java原生类,一种更安全的哈希算法,适用于任何可迭代的哈希算法,例如md5、SHA-1等。
KeyGenerator keyGen = KeyGenerator.getInstance("HmacMD5");
SecretKey key = keyGen.generateKey();
// 打印随机生成的key:
byte[] skey = key.getEncoded();
System.out.println(new BigInteger(1, skey).toString(16));
Mac mac = Mac.getInstance("HmacMD5");
mac.init(key);
mac.update("HelloWorld".getBytes("UTF-8"));
byte[] result = mac.doFinal();
System.out.println(new BigInteger(1, result).toString(16));
byte[] salt = "password".getBytes();
HMac hmac = new HMac(HmacAlgorithm.HmacMD5, salt);
// b977f4b13f93f549e06140971bded384
String hmacHex = hmac.digestHex("中文".getBytes("UTF-8"));
System.out.println(macHex);
重要章节
简介:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
国密加密主要分为:
SM1算法不公开,仅以IP核的方式存在于芯片中,例如智能门锁、智能IC卡等,成本高。
非对称加密SM2
String text = "中文";
SM2 sm2 = SmUtil.sm2();
// 随机公钥加密、私钥解密,自定义直接构造时传入或set__()即可
String enStr = sm2.encryptBcd(text, KeyType.PublicKey);
byte[] de = sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey);
String deStr = new String(decode);
【签名】
HexUtil是将字符串或byte数组与16进制表示转换的工具类,效果与使用BigInteger一样,其两者底层实现一样,可以互用。
String content = "中文";
final SM2 sm2 = SmUtil.sm2();
// 先转为十六进制数据Hex,然后再签名
String sign = sm2.signHex(HexUtil.encodeHexStr(content));
// true
boolean v = sm2.verifyHex(HexUtil.encodeHexStr(content), sign);
摘要加密SM3
String digestHex = SmUtil.sm3("中文");
对称加密SM4
String content = "test中文";
SymmetricCrypto sm4 = SmUtil.sm4();
String encryptHex = sm4.encryptHex(content);
String decryptStr = sm4.decryptStr(encryptHex);
文章浏览阅读1.2w次,点赞3次,收藏21次。变分自编码器(VAE)与生成对抗网络(GAN)是复杂分布上无监督学习最具前景的两类方法。本文中,作者在 MNIST 上对这两类生成模型的性能进行了对比测试。本项目总结了使用变分自编码器(Variational Autoencode,VAE)和生成对抗网络(GAN)对给定数据分布进行建模,并且对比了这些模型的性能。你可能会问:我们已经有了数百万张图像,为什么还要从给定数据分布中生成图像呢?正如 Ia..._对抗训练+vae
文章浏览阅读1.3w次。一.背景 事件机制作为一种编程机制,在很多开发语言中都提供了支持,同时许多开源框架的设计中都使用了事件机制,比如SpringFramework。 在 Java 语言中,Java 的事件机制参与者有3种角色: 1.Event Source:具体的事件源,比如说,你在界面点击一个 button 按钮,那么这个按钮就是事件源,要想使按钮对某些事件进行响应,你就需要注册特定的监听器 listener,事件源将事件对象传递给所有注册的监听器; 2.Event Object:事件状态对象_the typical cause is a non-static @bean method with a beandefinitionregistry
文章浏览阅读3w次,点赞6次,收藏18次。ObjectId使用12字节的存储空间,是一个由24个16进制数字组成的字符串(每个字节可以存储两个16进制数字)。说明:12字节(每个字节用2个16位的组成),因此,总共24个16位的数字。 1:如果快速的连续创建多个ObjectId,会发现每次只有最后几位数字有变化。另外,中间的几位数字也会变化(要是在创建的过程中停顿几秒)这是ObjectId的创建方式导致的。..._django mongodb '_id' expected a number but got objectid('65447178db311f5b706
文章浏览阅读1.6k次。人脸数据库汇总■Annotated Database (Hand, Meat, LV Cardiac, IMM face) (Link)■AR Face Database (Link)■BioID Face Database (Link)■Caltech Computational Vision Group Archive (Cars, Motorcycle_utf人脸数据库
文章浏览阅读4.8k次。Layui 下拉框多选 —老司机首选https://blog.csdn.net/YBaog/article/details/79933223_layui 下拉多选
文章浏览阅读626次。主要是使用阿里的druid报的错,pom如下:<dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.17</version></dependency>只要在yml配置文件中加上以下代码就ok,druid: #指明连接_validationquery = "select 1" 验证连接是否可用,使用的sql语句 testwhileidle =
文章浏览阅读9.5k次,点赞2次,收藏7次。npm引入npm install mathjs --save在main.js中引入let math = require('mathjs')Vue.prototype.$math = math创建工具类并定义方法创建utils.jslet $math = require('mathjs');export const math = { add() { return comp('add', arguments) }, subtract() { return comp_$mathjs
文章浏览阅读2k次。很多用户电脑重装系统之后,都出现一个相同的问题,常用文件没有后缀名。虽然这不影响我们文件的使用,但是出于习惯会看起来比较别扭。那么,有什么方法可以设置呢?win7显示文件后缀名怎么显示?下面,我们就一起来看看win7显示文件后缀的方法。方法一:1、其实文件后缀名未显示出来是电脑本身为设置好,只需要重新设置显示文件名即可。首先双击打开“计算机”,然后在打开的计算机上面菜单栏选择“工具-文件夹选项”。..._w7后缀名怎么显示
文章浏览阅读1w次。问题描述Missing artifact com.oracle:ojdbc6:jar:11.2.0.4 pom.xml 问题解决cmd中输入:mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.4 -Dpackaging=jar -Dfile=E:\ms\s_the archive: /grp/ui/web-inf/lib/ojdbc6-11.2.0.4.jar which is referenced by
文章浏览阅读446次。欢迎使用Markdown编辑器你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。新的改变我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:全新的界面设计 ,将会带来全新的写作体..._配置compiler:executable
文章浏览阅读3.9k次。目前定位到healthd的调用过程耗时太长,于是去看看power相关的一些东西healthd里一共调用了如下的节点获取数据openat(AT_FDCWD, "/sys/class/power_supply/battery/present", 1 *******openat(AT_FDCWD, "/sys/class/power_supply/battery/capacity",1_healthd定频唤醒
文章浏览阅读1.8k次,点赞2次,收藏6次。python运行同级目录下的文件 找不到package 显示 No module named 'xxx'_python 同目录脚本调用出现no module named