java - 如何在 Java 中使用 XOR 开发一个OTPInputStream
问题描述
我想用Java开发一个<code>OTPInputStream,它扩展<code>InputStream并接受另一个关键数据的输入流,并提供一个流加密/解密输入流。我需要开发一个测试程序来显示使用使用 XOR 和任意数据的<code>OTPInputStream</code>。
我尝试使用此代码,但我遇到的问题是
java.io.FileInputStream
不能转换为java.lang.CharSequence
我应该在这里做什么?
public class Bitwise_Encryption {
static String file = "" ;
static String key = "VFGHTrbg";
private static int[] encrypt(FileInputStream file, String key) {
int[] output = new int[((CharSequence) file).length()];
for(int i = 0; i < ((CharSequence) file).length(); i++) {
int o = (Integer.valueOf(((CharSequence) file).charAt(i)) ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
output[i] = o;
}
return output;
}
private static String decrypt(int[] input, String key) {
String output = "";
for(int i = 0; i < input.length; i++) {
output += (char) ((input[i] - 48) ^ (int) key.charAt(i % (key.length() - 1)));
}
return output;
}
public static void main(String args[]) throws FileNotFoundException {
FileInputStream file = new FileInputStream("directory");
encrypt(file,key);
//decrypt();
int[] encrypted = encrypt(file,key);
System.out.println("Encrypted Data is :");
for(int i = 0; i < encrypted.length; i++)
System.out.printf("%d,", encrypted[i]);
System.out.println("");
System.out.println("---------------------------------------------------");
System.out.println("Decrypted Data is :");
System.out.println(decrypt(encrypted,key));
}
}
解决方案
想想你想要的只是一次读取一个字符file.read()
并file.getChannel().size()
获取文件的大小
尝试这样的事情:
private static int[] encrypt(FileInputStream file, String key) {
int fileSize = file.getChannel().size();
int[] output = new int[fileSize];
for(int i = 0; i < output.length; i++) {
char char1 = (char) file.read();
int o = (char1 ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
output[i] = o;
}
return output;
}
必须进行一些错误处理,因为如果文件已到达文件末尾,file.read() 将返回 -1,并且指出一次读取一个字节是大量 IO 操作并且会降低性能。您可以将数据保存在缓冲区中并以另一种方式读取它,如下所示:
private static int[] encrypt(FileInputStream file, String key) {
int fileSize = file.getChannel().size();
int[] output = new int[fileSize];
int read = 0;
int offset = 0;
byte[] buffer = new byte[1024];
while((read = file.read(buffer)) > 0) {
for(int i = 0; i < read; i++) {
char char1 = (char) buffer[i];
int o = (char1 ^ Integer.valueOf(key.charAt(i % (key.length() - 1)))) + '0';
output[i + offset] = o;
}
offset += read;
}
return output;
}
这将从文件中一次读取 1024 个字节并将其存储在您的缓冲区中,然后您可以循环通过缓冲区来执行您的逻辑。偏移值用于存储当前点在我们的输出中的位置。此外,您必须确保i + offset
不超过您的数组大小。
更新
使用它之后;我决定切换到 Base64 编码/解码以删除不可打印的字符:
private static String encrypt(InputStream file, String key) throws Exception {
int read = 0;
byte[] buffer = new byte[1024];
try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
while((read = file.read(buffer)) > 0) {
baos.write(buffer, 0, read);
}
return base64Encode(xorWithKey(baos.toByteArray(), key.getBytes()));
}
}
private static String decrypt(String input, String key) {
byte[] decoded = base64Decode(input);
return new String(xorWithKey(decoded, key.getBytes()));
}
private static byte[] xorWithKey(byte[] a, byte[] key) {
byte[] out = new byte[a.length];
for (int i = 0; i < a.length; i++) {
out[i] = (byte) (a[i] ^ key[i%key.length]);
}
return out;
}
private static byte[] base64Decode(String s) {
return Base64.getDecoder().decode(s.trim());
}
private static String base64Encode(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
这种方法更简洁,不需要知道您的大小InputStream
或进行任何字符转换。它会将您读InputStream
入 OutputStream 以执行 Base64 编码以及删除不可打印的字符。
我已经对此进行了测试,它适用于加密和解密。
我从这个答案中得到了想法:
推荐阅读
- asp.net-core-mvc - 视图上的数据与传入的控制器不匹配
- javascript - React JS - Material UI ListItem (with Collapse API) onClick 一次只展开一个关闭其他
- xamarin - 升级到最新的 Google AdMob SDK 会导致奇怪的错误
- javascript - spreadsheets.values.append 正在替换前一行而不是附加它
- parallel-processing - 什么是 CUDA 11 中引入的 L2 缓存 accessPolicyWindow
- reactjs - 使用 React Context 的循环应用程序上下文依赖
- javascript - 如何对 React Table 中的复选框列进行排序?
- javascript - Javascript Date 构造函数从传递的值中删除一天并生成前一天的日期
- visual-studio-2019 - 使用 VS 2019 在 MS SQL 2019 上进行远程调试的设置
- c++ - 在开关情况下避免默认的优雅方式(使用枚举类)