java工具类之加密相关

正文

异或(XOR)加密

原理

一个整数 a 和任意一个整数 b 异或两次,得到的结果是整数 a 本身,即: a == a ^ b ^ b
这里的 a 就是需要加密的原数据,b 则是密钥.a ^ b 就是加密过程,异或的结果就是加密后的密文
密文 (a ^ b) 再与密钥 b 异或,就是解密过程,得到的结果就是原数据 a 本身

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package com.utstar.filemonitoring.utils;

import java.io.*;
import java.nio.charset.StandardCharsets;

/**
* FileName: XORUtils
* Author: creambing
*/
public class XORUtils {

public static byte[] encrypt(byte[] data, String key) {
byte[] keyByte = key.getBytes(StandardCharsets.UTF_8);
return encrypt(data,keyByte);
}


/**
* 异或算法加密/解密
*
* @param data 数据(密文/明文)
* @param key 密钥
* @return 返回解密/加密后的数据
*/
public static byte[] encrypt(byte[] data, byte[] key) {
if (data == null || data.length == 0 || key == null || key.length == 0) {
return data;
}

byte[] result = new byte[data.length];

// 使用密钥字节数组循环加密或解密
for (int i = 0; i < data.length; i++) {
// 数据与密钥异或, 再与循环变量的低8位异或(增加复杂度)
result[i] = (byte) (data[i] ^ key[i % key.length] ^ (i & 0xFF));
}

return result;
}

/**
* 对文件异或算法加密/解密
*
* @param inFile 输入文件(密文/明文)
* @param outFile 结果输出文件
* @param key 密钥
*/
public static void encryptFile(File inFile, File outFile, byte[] key) throws Exception {
InputStream in = null;
OutputStream out = null;

try {
// 文件输入流
in = new FileInputStream(inFile);
// 结果输出流, 异或运算时, 字节是一个一个读取和写入, 这里必须使用缓冲流包装,
// 等缓冲到一定数量的字节(10240字节)后再写入磁盘(否则写磁盘次数太多, 速度会非常慢)
out = new BufferedOutputStream(new FileOutputStream(outFile), 10240);

int b;
long i = 0;

// 每次循环读取文件的一个字节, 使用密钥字节数组循环加密或解密
while ((b = in.read()) != -1) {
// 数据与密钥异或, 再与循环变量的低8位异或(增加复杂度)
b = (b ^ key[(int) (i % key.length)] ^ (int) (i & 0xFF));
// 写入一个加密/解密后的字节
out.write(b);
// 循环变量递增
i++;
}
out.flush();

} finally {
close(in);
close(out);
}
}

private static void close(Closeable c) {
if (c != null) {
try {
c.close();
} catch (IOException e) {
// nothing
}
}
}
}

调用方式

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
String s = "hello world";
String key = "key";
byte[] encrypt = XORUtils.encrypt(s.getBytes(StandardCharsets.UTF_8),key);
System.out.println("encrypt:"+new String(encrypt, StandardCharsets.UTF_8));
byte[] decrypt = XORUtils.encrypt(encrypt,key);
System.out.println("decrypt:"+new String(decrypt, StandardCharsets.UTF_8));

}
result:
口口口
decrypt:hello world

DES加密

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.creambing.utils.encrypt;


import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;

/**
* Date: 2019-7-25 14:22
* Description:
*/
@Slf4j
public class DesUtils {

/**
* DES加密
*
* @param data 加密内容的byte数组
* @param key 加密key
* @return byte[]
*/
public static byte[] encryptByKey(byte[] data, String key) {
byte[] result = null;
try {
// 可信任的随机数
SecureRandom secureRandom = new SecureRandom();
DESKeySpec keySpec = new DESKeySpec(key.getBytes(StandardCharsets.UTF_8));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, secureRandom);
result = cipher.doFinal(data);
} catch (Exception e) {
StringWriter stringWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stringWriter));
log.error("encryptByKey exception:" + stringWriter.toString());
}
return result;
}

public static byte[] decryptByKey(byte[] data, String key) {
// 可信任的随机数
SecureRandom secureRandom = new SecureRandom();
DESKeySpec keySpec;
byte[] result = null;
try {
keySpec = new DESKeySpec(key.getBytes(StandardCharsets.UTF_8));
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, secretKey, secureRandom);
result = cipher.doFinal(data);
} catch (Exception e) {
StringWriter stringWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stringWriter));
log.error("decryptByKey exception:" + stringWriter.toString());
}
return result;
}

public static void main(String[] args) {

}

}

由于上面用了lombok注解来调用日志,所以需要添加如下依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<lombock.version>1.18.8</lombock.version>
<slf4j-api.version>1.7.26</slf4j-api.version>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombock.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j-api.version}</version>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>

调用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.creambing.utils.encrypt;

import org.junit.Assert;
import org.junit.Test;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
* Created by [creambing.github.io]
* Date: 2019/10/22
* Time: 16:24
*/
public class DesUtilsTest {

private String key = "1234567890";
private String s = "hello world";
private String encryptS = "KNugLrX23UddguNoHIO7dw==";

@Test
public void encryptByKey() {
byte[] encryptByte = DesUtils.encryptByKey(s.getBytes(StandardCharsets.UTF_8), key);
String encryptStr = new String(Base64.getEncoder().encode(encryptByte), StandardCharsets.UTF_8);
Assert.assertEquals(encryptS, encryptStr);
}

@Test
public void decryptByKey() {
byte[] decryptByte = DesUtils.decryptByKey(Base64.getDecoder().decode(encryptS), key);
String decryptStr = new String(decryptByte, StandardCharsets.UTF_8);
Assert.assertEquals(s, decryptStr);
}
}

上面加密的结果于下面网站一样
https://tool.lami.fun/jiami/des

参考资料

Cream Bing wechat
subscribe to my blog by scanning my public wechat account