2

Java は、このCipherクラスを特定の暗号実装への抽象化として使用します。私のプロジェクトでは、主に対称ブロック暗号 (AES、Twofish、3DES など) を使用しており、(XML 構成を使用して) 対称ブロック暗号を動的に作成/初期化する方法を探しています。暗号化を構成可能にしたい。

例: <transformer type="cipher" cipher="AES/GCM/NoPadding" keysize="256" iv="true" unlimitedstrength="true" />

に翻訳されます:

// Create secretKey using 'keysize' ...

if (encryption.isUnlimitedCrypto()) {
    Encryption.enableUnlimitedCrypto();
}

Cipher cipher = Cipher.getInstance(encryption.getCipherStr(), Encryption.PROVIDER);

if (encryption.isIvNeeded()) {
    byte[] iv = ... 
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
}
else {
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
}

私の質問は次のとおりです: Java で対称ブロック暗号をインスタンス化するために必要なパラメーターは何ですか?

パラメーター (既に特定済み):

  • 暗号文字列: Cipher.getInstance(..) の文字列、たとえば AES/CBC/PKCSPadding
  • 鍵サイズ: 鍵生成 (または PBE 鍵導出関数) の鍵のサイズ
  • IV が必要: IV が必要かどうかを示します。たとえば、CBC および GCM モードでは「true」ですが、ECB では必要ありません。
  • IVサイズ:IVのサイズを示します(今はIVサイズ=キーサイズだと思いますよね?)
  • 無制限の強度が必要: 無制限の強度ポリシー ファイルを有効にする必要があるかどうかを示します。
  • その他?

元のソース/プロジェクト:

4

1 に答える 1

2

ECBIV を必要とする以外のすべてのモード。IV は常に暗号のブロック サイズ (AES の場合は 16 バイト、3DES の場合は 8 バイト) と等しくなります。ECBモードは、同じキーで複数の平文ブロックを暗号化する場合は安全ではないため、機密性を確保したい場合は許可しないでください。

使用されるアルゴリズムによって、必要な鍵のサイズが決まります。たとえば、AES には 128、192、または 256 が必要です。Java の標準暗号 API を使用する場合は、192 および 256 に対して無制限強度ポリシーをインストールする必要があります。無制限強度ポリシーは、コードで切り替えることができるものではなく、エンド ユーザーの JRE にインストールする必要があります。

転送中のデータを保護することに関心がある場合 (そしてこのプロジェクトには真のセキュリティ ニーズがある場合)、代わりに SSL/TLS を使用することを強くお勧めすることはできません。安全な暗号システムを作成することは困難であり、一括暗号化 (つまり、AES や 3DES などの対称暗号) だけではセキュリティを確保するのに十分ではありません。また、ランダム データの暗号学的に強力なソース、安全な鍵交換プロセス、および完全性検証も必要です。一般に MAC 機能を使用して提供される完全性を確保することなく、機密性を提供することは困難です。安全な暗号化システムを実装する際には、避けるべき落とし穴がすべてあります。たとえば、暗号化と MAC に異なるキーを使用していることを確認する、MAC を正しく検証してタイミング攻撃ベクトルを作成しないようにする、適切なランダム ジェネレーターを使用する、作成しないように整合性を確保するなどです。パディングオラクルなど

ご覧のとおり、送信データの保護には多くの可動部分があり、最初から行うと、暗号プリミティブの選択や構成が不適切なために脆弱性が生じる可能性があります。これが、TLS が推奨されることが多い理由です。

以下は、2 つのソケットによって確立された匿名 (認証なし) TLS セッションの例です。どちらの当事者も他方を認証しないため、この例は安全ではありませんが、機密性と完全性は確立されています。この例でこの安全でない暗号スイートを使用している理由は、キーストアとトラストストア (認証部分に使用) にアクセスせずに TLS の使用法を簡単に実証できるためです。

使用されている暗号スイートは ですTLS_ECDH_anon_WITH_AES_128_CBC_SHA。これは、前述の認証がないため、通常、デフォルトでは有効になっていません。以下では、この暗号スイートを分解します

  • TLS - この暗号スイートは、TLS 標準によって導入されました。
  • ECDH_anon - Eliptic Cuve Diffie-Hellman アルゴリズムが鍵合意に使用されますが、鍵合意は認証されません。
  • AES_128_CBC - 暗号ブロック チェーン モードでキー長が 128 ビットの Advanced Encryption Standard が一括暗号化に使用されます。
  • SHA - セキュア ハッシュ アルゴリズムを使用して、暗号化されたデータの整合性を確保します。

例を次に示します。

package com.stackoverflow._19505091;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;

public class AnonTLSExample {

    public static void main(String[] args) throws Exception {

        /* No certs for this example so we are using ECDH_anon exchange. */
        String[] cipherSuites = {"TLS_ECDH_anon_WITH_AES_128_CBC_SHA"};
        SSLContext sslContext = SSLContext.getInstance("TLSv1.2");

        /* No certificates, use default secure random source.
         * If we were using authentication (and you should in a real
         * system), this is where we would load 
         * keystores and truststores. */
        sslContext.init(null, null, null);

        /* Create server socket. */
        SSLServerSocket ss = (SSLServerSocket) sslContext.getServerSocketFactory().createServerSocket(12345);
        ss.setEnabledCipherSuites(cipherSuites);

        /*
         * Normally when authentication is used only the client authenticates
         * the server. If you want the server to also authenticate the client
         * set this to true. This will establish bidirectional trust in the session.
         */
        ss.setWantClientAuth(false);

        /* Start server thread. */
        new Thread(new Server(ss), "ServerThread").start();

        /* Create client socket. */
        SSLSocket s = (SSLSocket) sslContext.getSocketFactory().createSocket();
        s.setEnabledCipherSuites(cipherSuites);

        /* Connect to server. */
        System.out.println("Client: Connecting...");
        s.connect(new InetSocketAddress("127.0.0.1", 12345));
        System.out.println("Client: Connected");

        /* Print out some TLS info for this connection. */
        SSLSession session = s.getSession();
        System.out.println("Client: Session secured with P: " + session.getProtocol() + " CS: " + session.getCipherSuite());

        /* Send the secret message. */
        DataOutputStream dos = new DataOutputStream(s.getOutputStream());
        String message = "Secret Message.";
        System.out.println("Client: Sending: " + message);
        dos.writeUTF(message);

        /* Wait for server to close stream. */
        System.out.println("Client: Waiting for server to close...");
        s.getInputStream().read();

        /* Close client socket. */
        s.close();
        System.out.println("Client: Done.");
    }


}

class Server implements Runnable {

    private final ServerSocket ss;

    public Server(ServerSocket ss){
        this.ss = ss;
    }

    @Override
    public void run() {
        try{
         /* Wait for client to connect. */
         System.out.println("Server: Waiting for connection...");
         Socket s = ss.accept();
         System.out.println("Server: Connected.");

         /* Read secret message. */
         DataInputStream dis = new DataInputStream(s.getInputStream());
         String message = dis.readUTF();
         System.out.println("Server: Received Message: " + message);

         /* Close our sockets. */
         s.close();
         ss.close();
         System.out.println("Server: Done.");
        }catch(Exception e){
            e.printStackTrace();
        }

    }
}
于 2013-10-22T03:00:15.727 に答える