Java 在加密数据之前添加常量前缀字符串是否安全?
我用Java编写了一个基于蛇算法的加密和解密程序,效果很好。但我想知道在数据之前添加一个固定前缀(6字节)是否安全。我想使用这个已知字符串来比较加密前的字符串和解密后的字符串。谁能解释一下这是否是一个严重的风险 谢谢 例如:Java 在加密数据之前添加常量前缀字符串是否安全?,java,security,encryption,Java,Security,Encryption,我用Java编写了一个基于蛇算法的加密和解密程序,效果很好。但我想知道在数据之前添加一个固定前缀(6字节)是否安全。我想使用这个已知字符串来比较加密前的字符串和解密后的字符串。谁能解释一下这是否是一个严重的风险 谢谢 例如: public static final String INITIAL_FLAG = "qwerty"; 加密蛇接口: public String get_api_version(); //byte - byte public byte[] encrypt(byte[]
public static final String INITIAL_FLAG = "qwerty";
加密蛇接口:
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();
蛇的实现:
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;
}
}
导入gnu.crypto.cipher.Serpent;
导入静态busslina.crypto_serpent.Utils.*;
导入java.io.File;
导入java.security.InvalidKeyException;
导入java.util.Iterator;
公共类API_impl实现API
{
私有静态最终字符串API_VERSION=“1.1”;
/**
*当前api interfaz/实施版本
*@返回
*/
@凌驾
公共字符串get_api_version()
{
返回API_版本;
}
公共静态最终字符串首字母\u FLAG=“QWERTY”;
公共静态最终整数密钥大小=16;
公共静态最终整块大小=16;
/**
*测试过了,很好用
*@param数据
*@param passwd
*@返回
*@InvalidKeyException
*/
@凌驾
公共字节[]加密(字节[]数据,字符串passwd)引发InvalidKeyException
{
if(passwd.length()>键大小)
抛出新的InvalidKeyException(“密码太长”);
蛇s=新蛇();
//passwd(我们需要密钥进行加密)
byte[]passwd\u byte=Utils.string\u to\u byt\u数组(passwd);
byte[]expanded\u passwd\u byte=Utils.expanded\u byt\u数组(passwd\u byte,KEY\u SIZE);
对象键=s.makeKey(扩展的字节、块大小);
//数据(标志+模数+原始数据+对齐空字节(零))
字节[]标志=字符串\u到\u字节\u数组(初始\u标志);
整数模=(flag.length+1+data.length)%BLOCK\u大小;
Byte mod=模数。byteValue();
字节[]数据标志扩展=concat阵列(标志,mod);
data_flag_extended=concat_数组(data_flag_extended,data);
如果(模数!=0)
data_flag_extended=用_零填充_(data_flag_extended,data_flag_extended.length+块大小-模数);
//数据加密(块大小)循环
int pos=0;
byte[]out=新字节[data_flag_extended.length];
while(true)
{
s、 加密(数据标志扩展、pos、out、pos、密钥、块大小);
pos+=块大小;
if(pos==数据\u标志\u扩展长度)
返回;
}
}
/**
*测试过了,很好用
*@param数据
*@param passwd
*@密码失败时返回NULL
*@抛出java.security.InvalidKeyException
*/
@凌驾
公共字节[]解密(字节[]数据,字符串passwd)引发InvalidKeyException
{
if(passwd.length()>键大小)
抛出新的InvalidKeyException(“密码太长”);
蛇s=新蛇();
//passwd(我们需要密钥来解密)
byte[]passwd\u byte=Utils.string\u to\u byt\u数组(passwd);
byte[]expanded\u passwd\u byte=Utils.expanded\u byt\u数组(passwd\u byte,KEY\u SIZE);
对象键=s.makeKey(扩展的字节、块大小);
//数据解密
byte[]out=新字节[data.length];
int pos=0;
while(true)
{
s、 解密(数据、pos、out、pos、密钥、块大小);
pos+=块大小;
if(pos==data.length)
打破
}
//标志检查和数据删除(标志和模数)
int flag_size=初始_flag.length();
String flag=新字符串(子数组(out,0,flag_size));
如果(!flag.equals(初始_标志))
返回null;
//旗帜检查通过
//现在,删除元数据
int模数=out[标志大小];
byte[]data\u no\u metadata=子数组(out,flag\u size+1,out.length-flag\u size-1);
//现在,删除添加的零,以便与块大小对齐
如果(模数==0)
返回数据\无\元数据;
返回子数组(data\u no\u metadata,0,data\u no\u metadata.length-块大小+模数);
}
静态无效显示\u密码\u信息()
{
蛇s=新蛇();
w(“块大小:”);
迭代器it=s.blockSizes();
while(it.hasNext())
w(it.next());
w(“关键尺寸:”);
它=s.keySizes();
while(it.hasNext())
w(it.next());
/*
块大小:
16
关键尺寸:
16
24
32
*/
}
@凌驾
公共字节[]加密(文件文件,字符串passwd)引发InvalidKeyException{
布尔检查_exists=true;
布尔值exit_on_fail=true;
检查\u文件(文件,检查\u是否存在,失败时退出);
字节[]数据=读取文件(文件);
返回加密(数据、密码);
}
@凌驾
公共字节[]解密(文件,字符串passwd)引发InvalidKeyException{
布尔检查_exists=true;
布尔值exit_on_fail=true;
检查\u文件(文件,检查\u是否存在,失败时退出);
字节[]数据=读取文件(文件);
返回解密(数据,passwd);
}
@凌驾
公共布尔加密(文件输入、文件输出、字符串密码)引发InvalidKeyException{
布尔检查_exists=true;
布尔值exit_on_fail=true;
检查文件(文件进入,检查是否存在,失败时退出);
检查_exists=false;
在失败时退出=真;
签出文件(文件签出,签出存在,失败时退出);
字节[]数据=读取文件(文件中);
写入文件(文件输出、加密(数据、密码));
返回true;
}
@凌驾
公共布尔解密(文件输入、文件输出、字符串密码)引发InvalidKeyException{
布尔检查_exists=true;
布尔值exit_on_fail=true;
检查文件(文件进入,检查是否存在,失败时退出);
检查_exists=false;
在失败时退出=真;
签出文件(文件签出,签出存在,失败时退出);
字节[]数据=读取文件(文件中);
字节[]解密=解密(数据,passwd);
if(decrypt==null)
返回false;
写入文件(文件输出、解密);
返回true;
}
@凌驾
公共布尔解密(字节[]数据、文件\u out、字符串passwd)引发InvalidKeyException{
布尔检查_exists=false;
布尔值exit_on_fail=true;
签出文件(文件签出,签出存在,失败时退出);
字节[]解密=解密(数据,passwd);
if(decrypt==null)
返回false;
写信
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;
}
}
}