java - java中的一次性加密
问题描述
我在java中创建了一次性加密,但我有两个问题是:
在加密中,我怎样才能使密钥的大小根据明文的大小灵活并随机生成,例如,明文的大小是 4 个字母,所以数组密钥的大小必须是 32 位,因为每个字母有8位。
在解密中,我如何以二进制形式读取文件和这两个文件,然后在它们之间进行异或,然后将其打印为 ASCLL 形式。
我的代码:
public class onetimepad {
public static void main(String[] args) throws Exception {
int[] key = generate8BitKey();
Scanner in = new Scanner(System.in);
System.out.println(" One Time Pad encryption and decryption ");
System.out.println(" For encryption Enter 1 ");
System.out.println(" For decryption Enter 2 ");
System.out.println(" Exit Enter 3 ");
int a = in.nextInt();
switch (a) {
case 1:
File input = new File("message.txt");
Scanner sc = new Scanner(input);
String msg = sc.nextLine();
System.out.println("Key: ");
//Write the Key in file.
PrintWriter writer2 = new PrintWriter("Output.txt", "UTF-8");
writer2.println("------ Key ------- ");
for (int i : key) {
System.out.print(key[i]);
writer2.print(key[i]);
}
writer2.close();
System.out.println();
String ciphertext = encrypt(msg, key);
System.out.println("Encrypted Message: " + ciphertext);
break;
case 2:
File input2 = new File("ciphertext.txt");
Scanner sc2 = new Scanner(input2);
String msg2 = sc2.nextLine();
File input3 = new File("Key.txt");
Scanner sc3 = new Scanner(input3);
String msg3 = sc2.nextLine();
System.out.println("Decrypted Message: " + decrypt(msg3, key));
break;
default:
}
}// End the main.
//------------------- Methods.
public static String encrypt(String msg, int[] key) {
int[] binmsg = stringToBinary(msg);
int[] result = xor(binmsg, repeatArray(key, msg.length()));
String r = "";
for (int i : result) {
r += (char) (result[i] + '0');
}
return r;
}
//---------------------
public static String decrypt(String ciphertext, int[] key) {
int[] bin = new int[ciphertext.length()];
for (int i = 0; i < ciphertext.length(); i++) {
bin[i] = ciphertext.charAt(i) - '0';
}
int[] result = xor(bin, repeatArray(key, bin.length / 8));
return binaryToString(result);
}
//---------------------
public static int[] stringToBinary(String msg) {
int[] result = new int[msg.length() * 8];
for (int i = 0; i < msg.length(); i++) {
String bin = Integer.toBinaryString((int) msg.charAt(i));
while (bin.length() < 8) {
bin = "0" + bin;
}
for (int j = 0; j < bin.length(); j++) {
result[i * 8 + j] = bin.charAt(j) - '0';
}
}
return result;
}
//---------------------
public static String binaryToString(int[] bin) {
String result = "";
for (int i = 0; i < bin.length / 8; i++) {
String c = "";
for (int j = 0; j < 8; j++) {
c += (char) (bin[i * 8 + j] + '0');
}
result += (char) Integer.parseInt(c, 2);
}
return result;
}
//---------------------
public static int[] generate8BitKey() {
int[] key = new int[8];
for (int i = 0; i < 8; i++) {
SecureRandom sr = new SecureRandom();
key[i] = sr.nextInt(2);
}
return key;
}
//---------------------
public static int[] xor(int[] a, int[] b) {
int[] result = new int[a.length];
for (int i = 0; i < a.length; i++) {
result[i] = a[i] == b[i] ? 0 : 1;
}
return result;
}
//---------------------
public static int[] repeatArray(int[] a, int n) {
int[] result = new int[a.length * n];
for (int i = 0; i < result.length; i++) {
result[i] = a[i % a.length]; // mod
}
return result;
}
}
解决方案
首先 - 尝试重写您的应用程序以使用正确的数据类型,这意味着您将byte[]
使用位作为位来处理类型。然后很容易读、写、异或、编码、解码。没有它,很少有人会尝试理解你自己的结构。所以我会进一步假设你会这样做。
接下来 - 实现自己的编码操作(例如 stringToBinary)确实没有意义,寻找将数据编码为十六进制或 base64 的简单方法。对于 Hex 你可以使用org.apache.commons.codec.binary.Hex
,对于 Base64 你已经有java.util.Base64
课了。对于您和任何愿意提供帮助的人来说,它将更具可读性
在加密中,我怎样才能使密钥的大小根据明文的大小灵活并随机生成,例如,明文的大小是 4 个字母,所以数组密钥的大小必须是 32 位,因为每个字母有8位。
假设您最终重写了您的应用程序以处理字节数组,您可以编写
SecureRandom sr = new SecureRandom();
byte[] keyBytes = new bytes[4];
sr.nextBytes (keyBytes);
这将生成 4 个具有高熵的字节。但是 - 整个方法存在问题:
要解密数据,您需要存储消息长度的密钥,并且您只能在一条消息中使用该密钥一次(这是一次性键盘的功能)。
想象一下,您有更长的消息,比如说 - 以千字节为单位。SecureRandom 生成任意(更长)长度的密钥可能非常慢,或者它可能生成的不是真正的随机数据。长话短说——这就是为什么使用 PRNG(我经常看到 ChaCha 或 Salsa20 流密码用作 PRNG)从初始密钥生成任意长度的随机数据。
在解密中,我如何以二进制形式读取文件和这两个文件,然后在它们之间进行异或,然后将其打印为 ASCLL 形式。
一旦你重写你的应用程序以使用byte[]
类型,那么(正如 Maarten 已经评论过的那样)你可以使用 FileInputStream 和 FileOutputStream (并且很容易 XOR bytes a ^ b
)
推荐阅读
- java - 当我在Java中检查一个单词是否是回文时,如何正确使用charAt()?
- typescript - 接口对象不能扩展 Record
- python - 在 seaborn displot/histplot 函数中绘制高斯拟合直方图(不是 distplot)
- sql - 获取带有父表行的最新子行
- wordpress - WordPress - 在库或页面中上传图像或媒体时出错
- python - 拆分然后删除理解中的最后一个字符
- pdf - SVG Bézier 的曲线总是关闭浏览器和 PDF 中的路径
- python - 如何将行唯一值转换为列
- c++ - C++:如何让编译器优化内存访问,以防成员变量的指针被传递到别处
- r - R - SARIMA 拟合函数返回 NULL