使用配置动态创建密码:需要哪些参数?

时间:2013-10-21 21:28:42

标签: java encryption cryptoapi

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 String:Cipher.getInstance(..)的字符串,例如AES / CBC / PKCSPadding
  • 密钥大小:密钥生成密钥的大小(或PBE密钥派生函数)
  • 需要IV:表示是否需要IV,例如CBC和GCM模式的“真实”,但不适用于ECB
  • IV大小:表示IV的大小(现在我假设IV大小=密钥大小,对吗?)
  • 需要无限强度:表示是否需要启用无限强度策略文件
  • 其他

原始资源/项目:

1 个答案:

答案 0 :(得分:2)

ECB以外的所有模式都需要IV。 IV将始终等于密码的块大小(AES为16字节,3DES为8字节)。使用相同的密钥加密超过1个明文块时,ECB模式是不安全的,如果要确保机密性,则不应该允许这种模式。

使用的算法将决定所需的密钥大小。例如,如果使用Java的标准加密API,则需要为192和256安装128,192或256个无限强度策略。无限强度策略不是您可以使用代码切换的,它必须安装在最终用户JRE中。

如果你关心保护传输中的数据(这个项目有真正的安全需求),我不能强烈要求你使用SSL / TLS。创建安全的加密系统很难做到,并且批量加密(即AES,3DES等对称密码)本身不足以确保安全性。您还需要一个加密强大的随机数据源,一个安全的密钥交换过程和完整性验证。在没有确保通常通过使用MAC功能提供的完整性的情况下难以提供保密。在实施安全加密系统时要避免所有陷阱,例如确保使用不同密钥进行密码和MAC,正确验证MAC以便不使用适当的随机生成器创建定时攻击向量,确保完整性以便不创建填充oracle等

正如您所看到的,保护传输数据有很多可移动的部分,从头开始执行此操作可能会导致错误选择或配置错误的加密原语引入漏洞。这就是为什么经常推荐TLS的原因。

以下是由两个套接字建立的匿名(无身份验证)TLS会话的示例。此示例不安全,因为双方都没有对另一方进行身份验证,但是建立了机密性和完整性。我在示例中使用这个不安全的密码套件的原因是很容易证明TLS的使用而无需进入密钥库和信任库(用于身份验证部分)

正在使用的密码套件是TLS_ECDH_anon_WITH_AES_128_CBC_SHA,由于上述缺少身份验证,因此默认情况下通常不会启用密码套件。下面我分解了这个密码套件

  • TLS - 这个密码套件是由TLS标准引入的。
  • ECDH_anon - Eliptic Cuve Diffie-Hellman算法用于密钥协商,但密钥协议未经过身份验证。
  • AES_128_CBC - 在密码块链接模式下具有128位密钥长度的高级加密标准用于批量加密。
  • 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();
        }

    }
}