3

暗号化されたバイト ストリーム (おそらく非常に大きなもの)を入力として受け取り、多かれ少なかれ同じ形式の出力を生成するインターフェイスを開発しています。

入力形式は次のとおりです。

{N byte envelope}
    - encryption key IDs &c.
{X byte encrypted body}

出力形式は同じです。

これが通常のユースケースです(もちろん、かなり擬似コード化されています):

Message incomingMessage = new Message (inputStream);

ProcessingResults results = process (incomingMessage);

MessageEnvelope messageEnvelope = new MessageEnvelope ();
// set message encryption options &c. ...

Message outgoingMessage = new Message ();
outgoingMessage.setEnvelope (messageEnvelope);

writeProcessingResults (results, message);

message.writeToOutput (outputStream);

私には、同じオブジェクトを使用してこの動作をカプセル化することは理にかなっているように思えますが、これをどのように行うべきかについて少し途方に暮れています。一度にすべての暗号化された本文を読み込むのは現実的ではありません。それをストリーミングできるようにする必要があります (そのため、ある種の入力ストリーム フィルターを使用して暗号化を解除します) と同時に、このオブジェクトの新しいインスタンスを書き出すことができる必要があります。この作業を行うための良いアプローチは何ですか? Message内部的にはどのように見えるべきですか?

4

6 に答える 6

1

入力と出力を処理するためのクラスを1つ作成することはしません。1つのクラス、1つの責任です。2つのフィルターストリームが必要です。1つは入力/復号化用、もう1つは出力/暗号化用です。

InputStream decrypted = new DecryptingStream(inputStream, decryptionParameters);
...
OutputStream encrypted = new EncryptingStream(outputSream, encryptionOptions);

read()彼らは、最初の呼び出しの前にエンベロープを読み取る/最初の呼び出しの前にエンベロープを書き込む怠惰な初期化メカニズムのようなものを持っているかもしれませんwrite()。フィルタの実装ではMessageやMessageEnvelopeなどのクラスも使用しますが、APIクラス以外のパッケージで保護されたままになる場合があります。

処理は、ストリームで動作しているだけの復号化/暗号化については何も知りません。処理入力と出力のストリーミングの処理中に、入力と出力の両方のストリームを同時に使用することもできます。

于 2009-01-20T20:42:46.833 に答える
0

ストリームの暗号化をサポートするさまざまなブロック暗号モードに関するウィキペディアの記事を確認する必要があります。さまざまな暗号化アルゴリズムがこれらのサブセットをサポートする場合があります。

バッファリングされたストリームを使用すると、ループで読み取り、暗号化/復号化、および書き込みを行うことができます。

ZipInputStreamとZipOutputStreamを示す例は、これを解決する方法についてのガイダンスを提供する可能性があります。を参照してください。

于 2009-01-07T22:31:58.463 に答える
0

Arneに同意します。データ プロセッサは暗号化について認識すべきではありません。メッセージの復号化された本文を読み取り、結果を書き出すだけでよく、ストリーム フィルタが暗号化を処理する必要があります。ただし、これは同じ情報 (メッセージ) に対して論理的に動作しているため、暗号化/復号化ストリームは実際にはこれから独立していますが、メッセージ形式を処理する 1 つのクラス内にパッケージ化する必要があると思います。

アーキテクチャを多少反転させ、メッセージ クラスを暗号化ストリームの外に移動するという、構造に関する私の考えは次のとおりです。

class Message {
  InputStream input;
  Envelope envelope;

  public Message(InputStream input) {
    assert input != null;
    this.input = input;
  }

  public Message(Envelope envelope) {
    assert envelope != null;
    this.envelope = envelope;
  }

  public Envelope getEnvelope() {
    if (envelope == null && input != null) {
      // Read envelope from beginning of stream
      envelope = new Envelope(input);
    }
    return envelope
  }

  public InputStream read() {
    assert input != null

    // Initialise the decryption stream
    return new DecryptingStream(input, getEnvelope().getEncryptionParameters());
  }

  public OutputStream write(OutputStream output) {
    // Write envelope header to output stream
    getEnvelope().write(output);

    // Initialise the encryption
    return new EncryptingStream(output, getEnvelope().getEncryptionParameters());
  }
}

これで、入力用に新しいメッセージを作成し、出力用に 1 つ作成して、これを使用できます。// これは、メッセージを送信するためのストリームです。 inputMessage = new Message(input); メッセージ outputMessage = new Message(inputMessage.getEnvelope()); process(inputMessage.read(), outputMessage.write(output));

process メソッドは、必要に応じて入力からデータのチャンクを読み取り、結果を出力に書き込む必要があります。

public void process(InputStream input, OutputStream output) {
  byte[] buffer = new byte[1024];
  int read;
  while ((read = input.read(buffer) > 0) {
    // Process buffer, writing to output as you go.
  }
}

これはすべてロックステップで機能するようになり、余分なスレッドは必要ありません。メッセージ全体を処理せずに早期に中止することもできます (たとえば、出力ストリームが閉じている場合)。

于 2009-01-21T19:33:25.803 に答える
0

必要なのは、暗号ストリーム ( CipherInputStream ) を使用することです。使用方法のを次に示します。

于 2009-01-18T21:35:45.043 に答える
0

読み取りと書き込みを同時に行う必要がある場合は、スレッド (異なるスレッドの読み取りと書き込み) または非同期 I/O (java.nio パッケージ) を使用する必要があります。異なるスレッドからの入力ストリームと出力ストリームを使用しても問題ありません。

Java でストリーミング API を作成する場合は、通常、読み取り用に InputStream を、書き込み用に OutputStream を提供する必要があります。このようにして、それらを他の API に渡すことができるため、物事を連鎖させて、ストリームをストリームとして取得できます。

入力例:

Message message = new Message(inputStream);
results = process(message.getInputStream());

出力例:

Message message = new Message(outputStream);
writeContent(message.getOutputStream());

メッセージは、必要な暗号化と復号化を行うクラスで指定されたストリームをラップする必要があります。

同時に複数のメッセージを読み取るか、同時に複数のメッセージを書き込むには、プロトコルからのサポートも必要になることに注意してください。同期を正しく行う必要があります。

于 2009-01-02T17:19:24.057 に答える
0

ボディを任意の位置で分割できますか?

その場合、入力スレッドと出力スレッドの 2 つのスレッドがあり、出力スレッドが監視する文字列の同時キューがあります。何かのようなもの:

ConcurrentLinkedQueue<String> outputQueue = new ConcurrentLinkedQueue<String>();
...

private void readInput(Stream stream) {
    String str;
    while ((str = stream.readLine()) != null) {
       outputQueue.put(processStream(str));
    }
}

private String processStream(String input) {
    // do something
    return output;
}

private void writeOutput(Stream out) {
    while (true) {
        while (outputQueue.peek() == null) {
            sleep(100);
        }

        String msg = outputQueue.poll();
        out.write(msg);
    }
}

注: このままでは確実に機能しません。あくまでもデザインのご提案です。誰かがこれを編集することを歓迎します。

于 2008-12-12T13:49:33.670 に答える