1

だから..ここにクラスがあります:(私はAES256暗号化のために使用して作成しました)

public class AES256
{
private String charSet = "UTF-8";
private String algo = "AES/CBC/PKCS5Padding";
private String baseAlgo = "AES";
private String hashAlgo = "PBKDF2WithHmacSHA1";

private String key = null;
private String salt = "defaultsaltsalt";
private String iv = "a1bC@6jZ!#sL1z0y";

private Cipher cipher;
private BufferedInputStream bIs;
private BufferedOutputStream bOs;

public AES256()
{

}

public AES256(String pass)
{
    this.key = pass;
}

public AES256(String pass, String salty)
{
    this.key = pass;
    this.salt = salty;
}

public AES256(String pass, String salty, String ivs)
{
    this.key = pass;
    this.salt = salty;
    this.iv = ivs;
}

public void setKey(String key)
{
    this.key = key;
}

public void setSalt(String salt)
{
    this.salt = salt;
}

public void setIV(String ivs)
{
    this.iv = ivs;
}

/**
 * @Method Pads and constructs the SecretKey (Padding @ 32)
 * @return Returns the padded key.
 * @throws Exception Exception is thrown if the key is null or something else wrong..
 */
public SecretKeySpec getKey() throws Exception
{
     byte[] saltBytes = salt.getBytes(charSet);

     SecretKeyFactory factory = SecretKeyFactory.getInstance(hashAlgo);
     PBEKeySpec spec = new PBEKeySpec(
             this.key.toCharArray(), 
             saltBytes, 
             300000, //make variable
             263 //default 32 bytes
     );

     SecretKey secretKey = factory.generateSecret(spec);
     SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), baseAlgo);

     return secret;
}

/**
 * @Method Pads and returns the IV (Padding @ 16)
 * @return
 * @throws Exception
 */
public byte[] getIV() throws Exception
{
    byte[] byteKey = iv.getBytes(charSet);
    MessageDigest sha = MessageDigest.getInstance("SHA-512");
    byteKey = sha.digest(byteKey);
    byteKey = Arrays.copyOf(byteKey, 16);
    return byteKey;
}

public byte[] encrypt(byte[] plainText) throws Exception
{
    cipher = Cipher.getInstance(algo);
    cipher.init(Cipher.ENCRYPT_MODE, getKey(), new IvParameterSpec(getIV()));

    System.out.println("Plain text length: "+plainText.length);
    byte[] enc = Base64.encodeBase64(cipher.doFinal(plainText));
    System.out.println("Encrypted text length "+enc.length);

    return  enc;
}

public byte[] decrypt(byte[] encryptedText) throws Exception
{
    cipher = Cipher.getInstance(algo);
    cipher.init(Cipher.DECRYPT_MODE, getKey(), new IvParameterSpec(getIV()));

    System.out.println("Encrypted Decrypted Text length: "+encryptedText.length);
    byte[] de = cipher.doFinal(Base64.decodeBase64(encryptedText));
    System.out.println("Decrypted Text length: "+de.length);

    return de;
}

public void encrypt(File fileToEncrypt) throws FileNotFoundException, IOException, Exception
{
    if(fileToEncrypt == null)
        throw new FileNotFoundException("File given to encrypt was not found!");
    File encrypted = new File(cutPath(fileToEncrypt.getPath()), "ENCRYPTED "+fileToEncrypt.getName());
    if(!encrypted.exists())
        encrypted.createNewFile();
    bIs = new BufferedInputStream(new FileInputStream(fileToEncrypt));
    bOs = new BufferedOutputStream(new FileOutputStream(encrypted));

    @SuppressWarnings("unused")
    int read = 0;
    byte[] buff = new byte[1024];
    while((read = bIs.read(buff)) != -1)
    {
        byte[] enc = encrypt(buff);
        bOs.write(enc, 0, enc.length);
    }
    bIs.close();
    bOs.close();
}

public void decrypt(File fileToDecrypt) throws FileNotFoundException, IOException, Exception
{
    if(fileToDecrypt == null)
        throw new FileNotFoundException("File given to decrypt was not found!");
    File decrypted = new File(cutPath(fileToDecrypt.getPath()), "DECRYPTED "+fileToDecrypt.getName().replace("ENCRYPTED ", ""));
    if(!decrypted.exists())
        decrypted.createNewFile();
    bIs = new BufferedInputStream(new FileInputStream(fileToDecrypt));
    bOs = new BufferedOutputStream(new FileOutputStream(decrypted));

    @SuppressWarnings("unused")
    int read = 0;
    byte[] buff = new byte[1388];
    while((read = bIs.read(buff)) != -1)
    {
        byte[] de = decrypt(buff);
        bOs.write(de, 0, de.length);
    }
    bIs.close();
    bOs.close();
}

private String cutPath(String path)
{
    String temp = "";
    String[] parts = path.split(Pattern.quote(File.separator));
    for(int i = 0; i < parts.length-1; i++)
        temp+=parts[i]+"/";
    return temp;
}

}

CBC/PKCS5PADDING を使用して Java で情報を暗号化および復号化するために作成したこのクラスを使用しています。パスワードをハッシュするためにハッシュ アルゴも使用しています。

注:このプログラムには、ファイルから取得したブロックごとにキーを計算し続ける理由など、いくつかの効率上の問題があることを知っています..後で修正します..いくつかのことをテストするためにそこにありました.

とにかく、私はencrypt(File)メソッドを使用しています。ファイルを渡すと、一度に1024バイトの情報を取得し、その情報を暗号化してから、エンコードの問題を回避するためにBASE64に変換します..次に、別のファイルに書き戻します同じ名前ですが、その前に ENCRYPTED または DECRYPTED という単語があり、親ファイルと同じディレクトリにあります..

今私の問題は、情報を暗号化して処理するために1024バイトの情報を送信し、次にBASE64を使用してUTFなどのエンコーディングの問題を回避するときです..しかし、結局のところ、私が何らかの方法で暗号化している1024バイト1388バイトのデータになり、それが返されます...なぜですか?

2番目の問題:上記の問題以外に多少機能しますが、問題ではないかもしれませんが、理由を知りたい.ファイルに余分な長さを追加します(上記の問題に直接関連している可能性があります...)。そのため、ファイルを復号化すると、ファイルのテキストは完全に復号化されますが、下部に余分な繰り返しテキストが表示されます理由...ファイルがいくつかの繰り返し情報で最後まで順番になるように..したがって、これらのランダムなバイトがどこから来ているのかわかりませんが、知りたいです..

とにかく、私の暗号化方法に他の問題が見つかった場合は、ここで教えてください。暗号化の選択が弱い可能性がありますか? ひょっとしたら簡単に強引になれるのでしょうか?非効率的な方法を使用していますか? 私が達成しようとしていることを理解していませんか? おそらく同じ名前と同じディレクトリでファイルを保存するのと同じように..もっと簡単な方法はありますか?

4

1 に答える 1

1

文字列を Base-64 でエンコードすると、最初よりも長い文字列になります。

このように考えてください。各バイトに 8 ビットの有効ビットを持つ配列がありました。重要なビットが 6 つだけの文字列 (つまり、2^6 = 64 であるため、名前の 64、base-64) になるため、約 1/3 長くする必要があります。

逆方向に作業すると、使用しているモードを使用した AES 暗号化は 16 バイトのパディングを追加するため、結果は供給したものより 16 バイト長くなります。つまり、1024 を指定すると、暗号化 (base-64 エンコーディングの前) により、長さが 1040 バイトになります。

演算は次のように機能します。

1024 bytes + 16 padding = 1040 bytes
1040 bytes is not divisible by 3 (as required by base-64) so add 1 byte
1041 bytes * 8 = 8328 bits / 6 = 1388
1388 base-64 characters

パート2

最後に余分なバイトがある理由は、次のコードにあります。

byte[] buff = new byte[1024];
while((read = bIs.read(buff)) != -1)
{
    byte[] enc = encrypt(buff);
    bOs.write(enc, 0, enc.length);
}

最後の読み取りでは、1024 バイト全体をバッファーに読み取りません。前の読み取りからのバイトはまだそこにあります。

変数「read」は、実際に読み取られたバイト数を保持します。その変数が使用されていないことに注意してください。ただし、最初の「読み取り」バイト数だけでなく、バ​​ッファー全体を暗号化しています。

これを修正するには、'read' の値を 'encrypt' メソッドに渡し、別の形式のメソッドを使用して、doFinal(buff, 0, read)読み取ったものだけを暗号化します。

この行を変更します。

    byte[] enc = encrypt(buff, read);

そしてこれ:

public byte[] encrypt(byte[] plainText, int len) throws Exception

そしてこれ:

byte[] enc = Base64.encodeBase64(cipher.doFinal(plainText, 0, len));

前回の読み取りに 1388 バイトがなく、古いバイトがバッファにある可能性があるため、復号化と同様のことを行う必要があります。(常に 1024 バイトを暗号化するため、現在この問題はありません。ファイルの最後のブロックで読み取りが短い場合、それらの一部が間違っているだけです。)

于 2013-09-20T16:41:57.693 に答える