【发布时间】:2017-10-25 12:07:56
【问题描述】:
我用Java写了一个基于Serpent算法的加解密程序,效果很好。但我想知道在数据(6 个字节)之前添加固定前缀是否安全。我想使用这个已知字符串将加密前的字符串与解密后的字符串进行比较。任何人都可以解释一下是否存在严重风险?
谢谢
例如:
public static final String INITIAL_FLAG = "qwerty";
crypto_serpent 接口:
public String get_api_version();
//byte - byte
public byte[] encrypt(byte[] data, String passwd) throws InvalidKeyException;
public byte[] decrypt(byte[] data, String passwd) throws InvalidKeyException;
//file - byte
public byte[] encrypt(File file, String passwd) throws InvalidKeyException;
public byte[] decrypt(File file, String passwd) throws InvalidKeyException;
//file - file
public boolean encrypt(File file_in, File file_out, String passwd) throws InvalidKeyException;
public boolean decrypt(File file_in, File file_out, String passwd) throws InvalidKeyException;
//byte - file
public boolean decrypt(byte[] data, File file_out, String passwd) throws InvalidKeyException;
public boolean encrypt(byte[] data, File file_out, String passwd) throws InvalidKeyException;
public int get_block_size();
Serpent 实现:
import gnu.crypto.cipher.Serpent;
import static busslina.crypto_serpent.Utils.*;
import java.io.File;
import java.security.InvalidKeyException;
import java.util.Iterator;
public class API_impl implements API
{
private static final String API_VERSION = "1.1";
/**
* Current api interfaz/implementation version
* @return
*/
@Override
public String get_api_version()
{
return API_VERSION;
}
public static final String INITIAL_FLAG = "QWERTY";
public static final int KEY_SIZE = 16;
public static final int BLOCK_SIZE = 16;
/**
* TESTED. WORKS FINE
* @param data
* @param passwd
* @return
* @throws InvalidKeyException
*/
@Override
public byte[] encrypt(byte[] data, String passwd) throws InvalidKeyException
{
if(passwd.length() > KEY_SIZE)
throw new InvalidKeyException("Password too long");
Serpent s = new Serpent();
//passwd (we need key to encrypt)
byte[] passwd_byte = Utils.string_to_byt_array(passwd);
byte[] expanded_passwd_byte = Utils.expand_byt_array(passwd_byte, KEY_SIZE);
Object key = s.makeKey(expanded_passwd_byte, BLOCK_SIZE);
//data (flag + modulus + original data + alignment empty bytes (zeros))
byte[] flag = string_to_byt_array(INITIAL_FLAG);
Integer modulus = (flag.length + 1 + data.length) % BLOCK_SIZE;
Byte mod = modulus.byteValue();
byte[] data_flag_extended = concat_array(flag, mod);
data_flag_extended = concat_array(data_flag_extended, data);
if(modulus != 0)
data_flag_extended = fill_with_zeros(data_flag_extended, data_flag_extended.length + BLOCK_SIZE - modulus);
//data encrypt (block size) loop
int pos = 0;
byte[] out = new byte[data_flag_extended.length];
while(true)
{
s.encrypt(data_flag_extended, pos, out, pos, key, BLOCK_SIZE);
pos += BLOCK_SIZE;
if(pos == data_flag_extended.length)
return out;
}
}
/**
* TESTED. WORKS FINE
* @param data
* @param passwd
* @return NULL on password fail
* @throws java.security.InvalidKeyException
*/
@Override
public byte[] decrypt(byte[] data, String passwd) throws InvalidKeyException
{
if(passwd.length() > KEY_SIZE)
throw new InvalidKeyException("Password too long");
Serpent s = new Serpent();
//passwd (we need key to decrypt)
byte[] passwd_byte = Utils.string_to_byt_array(passwd);
byte[] expanded_passwd_byte = Utils.expand_byt_array(passwd_byte, KEY_SIZE);
Object key = s.makeKey(expanded_passwd_byte, BLOCK_SIZE);
//data decrypt
byte[] out = new byte[data.length];
int pos = 0;
while(true)
{
s.decrypt(data, pos, out, pos, key, BLOCK_SIZE);
pos += BLOCK_SIZE;
if(pos == data.length)
break;
}
//flag check & metedata delete (flag and modulus)
int flag_size = INITIAL_FLAG.length();
String flag = new String(subarray(out, 0, flag_size));
if(!flag.equals(INITIAL_FLAG))
return null;
//flag check passed
//now, deletion of metadata
int modulus = out[flag_size];
byte[] data_no_metadata = subarray(out, flag_size + 1, out.length - flag_size - 1);
//now, deletion of zeroes added in order to align with BLOCK_SIZE
if(modulus == 0)
return data_no_metadata;
return subarray(data_no_metadata, 0, data_no_metadata.length - BLOCK_SIZE + modulus);
}
static void show_cipher_info()
{
Serpent s = new Serpent();
w("block sizes:");
Iterator<Integer> it = s.blockSizes();
while(it.hasNext())
w(it.next());
w("key sizes:");
it = s.keySizes();
while(it.hasNext())
w(it.next());
/*
block sizes:
16
key sizes:
16
24
32
*/
}
@Override
public byte[] encrypt(File file, String passwd) throws InvalidKeyException {
boolean check_exists = true;
boolean exit_on_fail = true;
check_file(file, check_exists, exit_on_fail);
byte[] data = read_file(file);
return encrypt(data, passwd);
}
@Override
public byte[] decrypt(File file, String passwd) throws InvalidKeyException {
boolean check_exists = true;
boolean exit_on_fail = true;
check_file(file, check_exists, exit_on_fail);
byte[] data = read_file(file);
return decrypt(data, passwd);
}
@Override
public boolean encrypt(File file_in, File file_out, String passwd) throws InvalidKeyException {
boolean check_exists = true;
boolean exit_on_fail = true;
check_file(file_in, check_exists, exit_on_fail);
check_exists = false;
exit_on_fail = true;
check_file(file_out, check_exists, exit_on_fail);
byte[] data = read_file(file_in);
write_file(file_out, encrypt(data, passwd));
return true;
}
@Override
public boolean decrypt(File file_in, File file_out, String passwd) throws InvalidKeyException {
boolean check_exists = true;
boolean exit_on_fail = true;
check_file(file_in, check_exists, exit_on_fail);
check_exists = false;
exit_on_fail = true;
check_file(file_out, check_exists, exit_on_fail);
byte[] data = read_file(file_in);
byte[] decrypt = decrypt(data, passwd);
if(decrypt == null)
return false;
write_file(file_out, decrypt);
return true;
}
@Override
public boolean decrypt(byte[] data, File file_out, String passwd) throws InvalidKeyException {
boolean check_exists = false;
boolean exit_on_fail = true;
check_file(file_out, check_exists, exit_on_fail);
byte[] decrypt = decrypt(data, passwd);
if(decrypt == null)
return false;
write_file(file_out, decrypt);
return true;
}
@Override
public boolean encrypt(byte[] data, File file_out, String passwd) throws InvalidKeyException {
boolean check_exists = false;
boolean exit_on_fail = true;
check_file(file_out, check_exists, exit_on_fail);
write_file(file_out, encrypt(data, passwd));
return true;
}
@Override
public int get_block_size() {
return BLOCK_SIZE;
}
}
Utils.java:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Utils {
public static void w(Object msg)
{
System.out.println(msg);
}
public static byte[] string_to_byt_array(String txt)
{
char[] toCharArray = txt.toCharArray();
byte[] ret = new byte[toCharArray.length];
for(int i = 0; i < toCharArray.length; i++)
ret[i] = (byte)toCharArray[i];
return ret;
}
public static Byte[] string_to_byte_array(String txt)
{
char[] toCharArray = txt.toCharArray();
Byte[] ret = new Byte[toCharArray.length];
for(int i = 0; i < toCharArray.length; i++)
ret[i] = (byte)toCharArray[i];
return ret;
}
public static byte[] expand_byt_array(byte[] array, int size)
{
if(array.length == size)
return array;
else if(array.length > size)
return null;
byte[] ret = new byte[size];
System.arraycopy(array, 0, ret, 0, array.length);
return ret;
}
public static byte[] concat_array(byte[] array_a, byte[] array_b)
{
return concat_array(array_a, array_b, -1, -1, -1, -1);
}
public static byte[] concat_array(byte[] array_a, byte[] array_b,
int init_a, int length_a, int init_b, int length_b)
{
if(init_a == -1)
init_a = 0;
if(length_a == -1)
length_a = array_a.length;
if(init_b == -1)
init_b = 0;
if(length_b == -1)
length_b = array_b.length;
byte[] ret = new byte[length_a - init_a + length_b - init_b];
int cont = 0;
//array a
for(int i = init_a; i < length_a + init_a; cont++, i++)
ret[cont] = array_a[i];
//array b
for(int i = init_b; i < length_b + init_b; cont++, i++)
ret[cont] = array_b[i];
return ret;
}
public static byte[] concat_array(byte[] array_a, byte b)
{
byte[] array_b = new byte[]{b};
return concat_array(array_a, array_b);
}
public static <T> T[] concat_array(T[] array_a, T[] array_b)
{
T[] ret = (T[])new Object[array_a.length + array_b.length];
//array a
System.arraycopy(array_a, 0, ret, 0, array_a.length);
//array b
for(int index_x = 0, index_y = array_a.length; index_x < array_b.length; index_x++, index_y++)
ret[index_y] = array_b[index_x];
return ret;
}
public static <T> T[] concat_array(T[] array_a, T b)
{
T[] array_b = (T[])new Object[]{b};
return concat_array(array_a, array_b);
}
public static Byte[] array_byte_conversion(byte[] array)
{
Byte[] ret = new Byte[array.length];
for(int i = 0; i < array.length; i++)
ret[i] = array[i];
return ret;
}
public static byte[] array_byt_conversion(Byte[] array)
{
byte[] ret = new byte[array.length];
for(int i = 0; i < array.length; i++)
ret[i] = array[i];
return ret;
}
/**
* NOT TESTED
* @param <T>
* @param array
* @param pos
* @param length
* @return
*/
public static <T> T[] subarray(T[] array, int pos, int length)
{
if(pos + length > array.length)
length = pos + length - array.length;
T[] ret = (T[])new Object[length];
for(int i = 0; i < length; i++)
ret[i] = array[i + pos];
return ret;
}
/**
* NOT TESTED
* @param array
* @param pos
* @param length
* @return
*/
public static byte[] subarray(byte[] array, int pos, int length)
{
//check overflow on right
if(pos + length > array.length)
length = pos + length - array.length;
byte[] ret = new byte[length];
for(int i = 0; i < length; i++)
ret[i] = array[i + pos];
return ret;
}
public static byte[] fill_with_zeros(byte[] array, int desired_size)
{
if(array.length >= desired_size)
return array;
byte[] ret = new byte[desired_size];
System.arraycopy(array, 0, ret, 0, array.length);
return ret;
}
public static boolean compare_byt_array(byte[] a, byte[] b)
{
if(a.length != b.length)
return false;
for(int i = 0; i < a.length; i++)
{
if(a[i] != b[i])
return false;
}
return true;
}
public static boolean check_file(File file, boolean check_exists, boolean exit_on_fail)
{
boolean ret = file.exists();
if(ret != check_exists && exit_on_fail)
{
if(ret)
w("Error. File already exists");
else
w("Error. File not found");
System.exit(0);
}
if(check_exists)
return ret;
else
return !ret;
}
public static byte[] read_file(File file)
{
byte[] ret = new byte[0];
try
{
FileInputStream fis = new FileInputStream(file);
byte[] read = new byte[1024];
int cont;
while((cont = fis.read(read)) != -1)
ret = concat_array(ret, read, -1, -1, 0, cont);
}
catch(FileNotFoundException e)
{
return null;
}
catch(IOException e)
{
return null;
}
return ret;
}
public static boolean write_file(File file, byte[] data)
{
try
{
FileOutputStream fos = new FileOutputStream(file);
fos.write(data);
return true;
}
catch(IOException e)
{
return false;
}
}
}
【问题讨论】:
-
那么,基本上,您发送的是一些未加密的元数据?
-
安全在什么意义上,来自谁?你爱管闲事的 8 岁妹妹?地痞子?主要有组织犯罪集团?
-
元数据是什么?
-
加密时添加此标志,解密时我会查找此标志,如果我不匹配,则密码错误。我的问题是这种方法是否有风险,因为如果有人知道固定标志(源代码)并且有两个或更多加密文件,那么破解密码可能会更容易。
-
并将标志与数据一起插入,然后一起加密
标签: java security encryption