Java 在加密数据之前添加常量前缀字符串是否安全?

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[]

我用Java编写了一个基于蛇算法的加密和解密程序,效果很好。但我想知道在数据之前添加一个固定前缀(6字节)是否安全。我想使用这个已知字符串来比较加密前的字符串和解密后的字符串。谁能解释一下这是否是一个严重的风险

谢谢

例如:

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;
    }
   }
}