2017-04-10 3 views
0

擬似乱数を使用してXORでテキストを暗号化し、暗号化されたテキストをファイルに書き込もうとしています。次に、ファイルを再度読み込み、ユーザーが正しいキーを入力すると、テキストを復号化します。 しかし、私が得るのは?????です。私は間違って何をしていますか?Javaフィルタストリームを使用してXORで文字列を暗号化する

import java.io.BufferedInputStream; 
import java.io.BufferedOutputStream; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.util.Random; 
import java.util.Scanner; 

public class MainTest 
{ 
    public static void main(String[] args) 
    { 
     long seed = 754; // key 
     Random random = new Random(seed); 

     String message = "hello"; 

     try 
     { 
      OutputStream os = new FileOutputStream("test.txt"); 
      OutputStream bos = new BufferedOutputStream(os); 
      EncryptOutputStream eos = new EncryptOutputStream(bos); 

      for(int i = 0; i < message.length(); i++) 
      { 
       int z = random.nextInt(); 
       eos.write(message.charAt(i), z); 
      } 

      eos.close(); 

      InputStream is = new FileInputStream("test.txt"); 
      InputStream bis = new BufferedInputStream(is); 
      DecryptInputStream dis = new DecryptInputStream(bis); 

      Scanner scanner = new Scanner(System.in); 
      System.out.print("Enter key: "); 
      long key = scanner.nextLong(); 
      scanner.close(); 

      random = new Random(key); 

      int c; 
      while((c = dis.read(random.nextInt())) != -1) 
      { 
       System.out.print((char)c); 
      } 

      dis.close(); 
     } 
     catch(Exception e) 
     { 
      e.printStackTrace(); 
     } 
    } 
} 
import java.io.FilterInputStream; 
import java.io.IOException; 
import java.io.InputStream; 

public class DecryptInputStream extends FilterInputStream 
{ 

    protected DecryptInputStream(InputStream in) 
    { 
     super(in); 
    } 

    public int read(int z) throws IOException 
    { 
     int c = super.read(); 
     if(c == -1) return -1; 
     return c^z; 
    } 
} 
import java.io.FilterOutputStream; 
import java.io.IOException; 
import java.io.OutputStream; 

public class EncryptOutputStream extends FilterOutputStream 
{ 

    public EncryptOutputStream(OutputStream o) 
    { 
     super(o); 
    } 

    public void write(int c, int z) throws IOException 
    { 
     super.write(c^z); 
    } 

} 
+0

多分 'int'ではなく' byte'を使うべきです( 'random.nextInt()'ではありません) –

+0

解読のために正しい 'seed'を入力しましたか?おそらく、暗号化に使用したのと同じ値を使用するだけです。 –

+0

私はこれが安全ではない乱数ジェネレータと低いエントロピーシードのために簡単に破壊可能であるため、これは本番ソフトウェアでは使用されないと仮定します。 – TheGreatContini

答えて

1

解読するときは、排他的論理和の後に上位ビットをマスクする必要があります。

public int read(int z) throws IOException 
{ 
    int c = super.read(); 
    if(c == -1) return -1; 
    return (c^z) & 0xFF; /* Only use lowest 8 bits */ 
} 

暗号化すると、32ビットのintが生成されます。上位16ビットは鍵ストリームの上位ビットを含み、下位16ビットは暗号文を含む。しかし、OutputStreamはバイトを書き込むため、出力ファイルには最低8ビットしか書き込まれません。メッセージ "hello"では、これらの文字はすべて下位7ビットにエンコードされているので、これは問題ありません。

ただし、暗号化を解除すると、32ビットのintが作成され、上位24ビットはキーストリームのビットで埋められます。 charにキャストすると、ビット31-16は破棄されますが、ビット15-8は迷惑メールで埋められ、最下位ビットの0-8は元の文字を含む必要があります。 charの上位ビットはガベージなので、文字化けした出力が得られます。

+0

ありがとうございます。今はうまくいく。 – WalterWhite

+0

@WalterWhiteただし、ASCII以外の文字を書くと壊れてしまいます。文字とバイトを変換するには 'InputStreamReader'と' OutputStreamWriter'を使うべきです。 – erickson

0

私はEncryptOutputStreamためのコードを持っていないが、それはOUのように見えるがそれぞれ、すべての文字のランダムな整数を取得しています。つまり、ユーザーは、各整数を同じ順序で入力して解読する必要があります。最初の実行では、1つのランダムなintを取得し、暗号化してから、単一の整数を使用して解読します。あなたは後で好きになることができます。

+1

* "EncryptOutputStreamのコードがありません" * - スクロールダウン –

+0

1つのrandomIntを取得し、書き込みメソッドに送信し続けます – Dakoda

関連する問題