第一次写博客,以前一直看别人的博客,今天也试着写一下,希望自己也能帮助到别人,也希望会有点赞和评论。
每天都要过得开心 ( ゜- ゜)つロ乾杯 !
对称加密
DES加密
1.生成随机秘钥(应用场景:可以将随机秘钥保存成文件储存)
private static final String DES = "DES";
public static void generateKey() throws NoSuchAlgorithmException, IOException {
//生成随机秘钥
SecretKey secretKey = KeyGenerator.getInstance(DES).generateKey();
SerializableUtil.saveObject(secretKey, "test.key");
}
public static SecretKey readKey() throws ClassNotFoundException, IOException {
return (SecretKey) SerializableUtil.readObject("test.key");
}
2.使用随机秘钥加解密
SecretKey secretKey = readKey();
//Cipher叫做加密器或者加密系统
Cipher cipher = Cipher.getInstance(DES);
//加密模式
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] result = cipher.doFinal(input.getBytes());
//解密模式
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] deResult = cipher.doFinal(result);
3.使用秘钥工厂加密后,使用base64编码成安全字符传输,解密时使用base64解码后再用秘钥解密
注意:DES加密的秘钥不能小于64位(16个字节),最后8位是校验码(就是例子里的8),大于64位都会无效,但不报错。
private static final String DES = "DES";
//将Key写在c代码中能提高安全性(jni)
private static final String KEY = "12345678";//56位,64位(有8位是校验码)
//加密->base64编码
private static String encrypt(String input, String key) throws Exception{
//秘钥规范
DESKeySpec keySpec = new DESKeySpec(key.getBytes());
//通过秘钥工厂生成秘钥
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(DES);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance(DES);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] result = cipher.doFinal(input.getBytes());
//return new String(result);危险操作,码表里招不到对应字符,会生成乱码
return Base64.encode(result);
}
//base64解码->解密
private static String decrypt(String input, String key) throws Exception {
//秘钥规范
DESKeySpec keySpec = new DESKeySpec(key.getBytes());
//通过秘钥工厂生成秘钥
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(DES);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance(DES);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] base64 = Base64.decode(input);
byte[] result = cipher.doFinal(base64);
return new String(result);
}
AES加密
注意 :AES算法比DES更安全,秘钥128位,不能多也不能少生成秘钥的algorithm参数与加密时的algorithm其实不是一个东西,加密时的参数包含(算法/工作模式/填充模式)三个信息。可以进行配置,加解密时必须要统一。
1.指定算法/工作模式/填充模式
private static final String KEY_ALGORITHM = "AES";
//加密算法:"algorithm/mode/padding" "算法/工作模式/填充模式" 默认:"DES/ECB/PKCS5Padding"
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";//CBC模式下必须加iv参数,能加强安全性
private static final String KEY = "1234567890123456";//AES秘钥,128位
2.生成秘钥
new SecretKeySpec是另一种秘钥创建方法,AES必须使用这种方式,DES则两种都可以CBC工作模式要比ECB更为安全,但需要多一个参数IvParameterSpec(参数可以用另一个key,也可用同一个)
//加密->base64编码
private static String encrypt(String input, String key) throws Exception{
//方式一:只能DES用(通过秘钥工厂生成秘钥)
//DESKeySpec keySpec = new DESKeySpec(key.getBytes());
//SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
//SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
//方式二:AES、DES都可用
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), KEY_ALGORITHM);
//CBC工作模式下必须加iv参数,能加强安全性
IvParameterSpec iv = new IvParameterSpec(key.getBytes());
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
//cipher.init(Cipher.ENCRYPT_MODE, secretKey);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
byte[] result = cipher.doFinal(input.getBytes());
return Base64.encode(result);
}
//base64解码->解密
private static String decrypt(String input, String key) throws Exception {
//方式一:只能DES用(通过秘钥工厂生成秘钥)
//DESKeySpec keySpec = new DESKeySpec(key.getBytes());
//SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
//SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
//方式二:AES、DES都可用
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), KEY_ALGORITHM);
//CBC模式下必须加iv参数,能加强安全性
IvParameterSpec iv = new IvParameterSpec(key.getBytes());
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
//cipher.init(Cipher.DECRYPT_MODE, secretKey);
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
byte[] base64 = Base64.decode(input);
byte[] result = cipher.doFinal(base64);
return new String(result);
}
非对称加密
注意:公钥、私钥都可以加密,也都可以解密。其中:用公钥加密需要私钥解密,称为“加密”。由于私钥是不公开的,确保了内容的保密,没有私钥无法获得内容;用私钥加密需要公钥解密,称为“签名”。由于公钥是公开的,任何人都可以解密内容,但只能用发布者的公钥解密,验证了内容是该发布者发出的。
用法一:加密
用法二:签名
RSA加解密
注意:RSA加密一次性操作不能超过117字节,解密时一次性操作不能超过128字节。
public class AsymmetricalEncrypt {
private static final String ALGORITHM = "RSA";
//原文一次性操作不能超过117字节
private static final int ENCRYPT_MAX_BLOCK = 117;
//解密时一次性操作不能超过128字节
private static final int DECRYPT_MAX_BLOCK = 128;
public static void main(String[] args) throws Exception {
String input = "阿斯顿发阿斯顿发阿斯顿发阿斯顿发阿斯顿发阿斯顿发阿斯顿发阿斯顿发阿斯顿发阿斯顿发";
System.out.println(input.getBytes().length);
//生成密钥对
KeyPair keyPair = KeyPairGenerator.getInstance(ALGORITHM).generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
Cipher cipher = Cipher.getInstance(ALGORITHM);
//加密
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
//一次性处理大数据会报错
//byte[] result = cipher.doFinal(input.getBytes());
//需要分批处理
byte[] result = doFinalWithBatch(cipher, input.getBytes(), ENCRYPT_MAX_BLOCK);
System.out.println(Base64.encode(result));
//解密
cipher.init(Cipher.DECRYPT_MODE, privateKey);
//byte[] deResult = cipher.doFinal(result);
byte[] deResult = doFinalWithBatch(cipher, result, DECRYPT_MAX_BLOCK);
System.out.println(new String(deResult));
}
/**
* 分批处理
* @param cipher
* @param bytes
* @param blockSize 块大小
*/
private static byte[] doFinalWithBatch(Cipher cipher, byte[] bytes, int blockSize)
throws Exception, BadPaddingException {
int offeset = 0;
byte[] tmp;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while (bytes.length - offeset > 0) {
if (bytes.length - offeset >= blockSize) {
tmp = cipher.doFinal(bytes, offeset, blockSize);
offeset = offeset + blockSize;
}else{
tmp = cipher.doFinal(bytes, offeset, bytes.length - offeset);
offeset = offeset + (bytes.length - offeset);
}
baos.write(tmp);
}
baos.close();
return baos.toByteArray();
}
}
消息摘要
public class MessageDigestDemo {
public static void main(String[] args) throws Exception {
String input = "1qwerwqerwqreqwerqwerqwerqwer123";
//MD5/SHA
MessageDigest md5 = MessageDigest.getInstance("MD5");//SHA
byte[] result = md5.digest(input.getBytes());
//md5后的长度16个字节(128个比特位)、16进制字符串为32个字符
//SHA后的长度20个字节(160个比特位)、16进制字符串为40个字符
System.out.println(Hex.encode(result));//常用16进制字符串来展示
}
}
数字签名
/**
* 数字签名演示
*/
public class SignatureDemo {
public static void main(String[] args) throws Exception {
String input = "贷款100万";
// MD2withRSA, MD5withRSA, or SHA1withRSA
Signature signature = Signature.getInstance("MD5withRSA");
//SerializableUtil.readObject("");
KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
//初始化签名
signature.initSign(privateKey);
signature.update(input.getBytes());
byte[] sign = signature.sign();
//初始化校验
signature.initVerify(publicKey);
signature.update(input.getBytes());
//是否通过
boolean verify = signature.verify(sign);
System.out.println(verify);
}
}