2011-03-15 18 views
9

Deseo utilizar el siguiente código para una aplicación de alta concurrencia donde ciertos datos deben estar cifrados y descifrados. Por lo tanto, necesito saber qué parte de este código debe sincronizarse, si corresponde, para evitar problemas impredecibles.¿Es seguro este hilo de código de cifrado de Java?

public class DesEncrypter { 
    Cipher ecipher; 
    Cipher dcipher; 

    // 8-byte Salt 
    byte[] salt = { 
     (byte)0xA9, (byte)0x9B, (byte)0xC8, (byte)0x32, 
     (byte)0x56, (byte)0x35, (byte)0xE3, (byte)0x03 
    }; 

    int iterationCount = 19; 

    DesEncrypter(String passPhrase) { 
     try { 
      // Create the key 
      KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount); 

      SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec); 
      ecipher = Cipher.getInstance(key.getAlgorithm()); 
      dcipher = Cipher.getInstance(key.getAlgorithm()); 

      // Prepare the parameter to the ciphers 
      AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount); 

      // Create the ciphers 
      ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec); 
      dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec); 
     } catch (...) 
    } 

    public String encrypt(String str) { 
     try { 
      // Encode the string into bytes using utf-8 
      byte[] utf8 = str.getBytes("UTF8"); 
      // Encrypt 
      byte[] enc = ecipher.doFinal(utf8); 
      // Encode bytes to base64 to get a string 
      return new sun.misc.BASE64Encoder().encode(enc); 

     } catch (...) 
    } 

    public String decrypt(String str) { 
     try { 
      // Decode base64 to get bytes 
      byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str); 
      // Decrypt 
      byte[] utf8 = dcipher.doFinal(dec); 
      // Decode using utf-8 
      return new String(utf8, "UTF8"); 
     } catch (...) 
    } 
} 

Si creo un nuevo sistema de cifrado en el cifrar() y descifrar() métodos para cada invocación, entonces puedo evitar problemas de concurrencia, es que no estoy seguro de si hay un montón de gastos generales en conseguir un nuevo instancia de un cifrado para cada invocación.

public String encrypt(String str) { 
     try { 
      // Encode the string into bytes using utf-8 
      byte[] utf8 = str.getBytes("UTF8"); 
      // Encrypt 
      //new cipher instance 
      ecipher = Cipher.getInstance(key.getAlgorithm()); 

      byte[] enc = ecipher.doFinal(utf8); 
      // Encode bytes to base64 to get a string 
      return new sun.misc.BASE64Encoder().encode(enc); 

     } catch (...) 

Respuesta

3

Las cosas solo tienen que ser seguras para subprocesos si las utilizan varios subprocesos a la vez. Dado que cada instancia de esta clase presumiblemente será utilizada por un solo hilo, no hay necesidad de preocuparse de si es seguro o no.

En una nota no relacionada, tener una sal codificada, Nonce o IV es nunca una buena idea.

+0

No lo sabía, gracias. Planeo guardar la sal y la frase de paso en archivos separados bajo estrictos permisos del sistema operativo disponibles solo para la aplicación. – user646584

+0

El uso de una sal constante (incluso si está protegido) en gran medida no tiene nada que ver con el uso de una sal. –

+0

¿Estás diciendo que la sal debería obtenerse aleatoriamente en tiempo de ejecución? Estoy confundido, claramente la contraseña no puede cambiar una vez que los datos han sido encriptados con ella, entonces ¿qué necesita ser generado por adelantado y almacenado en un archivo seguro, la sal y la frase de contraseña, solo la frase de contraseña, etc.? – user646584

10

La regla estándar es - a menos que los estados Javadoc explícitamente que una clase en las bibliotecas de Java es seguro para subprocesos, que deben asumir que no lo es.

En este caso particular:

  • Las diversas clases no están documentados como hilo de seguridad.
  • Los métodos Cipher.getInstance(...) y SecretKeyFactory.getInstance(...) ESTÁN documentados como devolver objetos nuevos; es decir, no referencias a objetos existentes a los que otros hilos podrían tener referencias.

    ACTUALIZACIÓN - El javadoc dice esto:

    "Un nuevo objeto SecretKeyFactory encapsular la implementación SecretKeyFactorySpi desde el primer proveedor que soporte se devuelve el algoritmo especificado."

    Además, el source code confirma claramente que se crea un nuevo objeto y regresó.

En pocas palabras, esto significa que su clase DesEncryptor no está seguro para subprocesos, pero usted debería ser capaz de hacer que sea seguro para subprocesos mediante la sincronización de las operaciones pertinentes (por ejemplo encode y decode), y no exponer la dos objetos de Cipher. Si sincronizar los métodos es probable que cree un cuello de botella, cree una instancia separada de DesEncryptor para cada subproceso.

+0

Lo siento por publicar en un tema tan antiguo, pero dudo que SecretKeyFactory.getInstance() devuelva un nuevo objeto cada vez porque es una fábrica. Además, lo estoy probando ahora mismo y la primera llamada demora 2.5 segundos, mientras que cada llamada consecuente toma 0s. – andrewktmeikle

+0

1) Ver actualización.2) La primera llamada probablemente desencadena la carga de clase, y la inicialización que puede implicar obtener "entropía" del sistema operativo. En algunas circunstancias, eso puede tomar una cantidad * significativa * de tiempo real. –

+0

Justo lo suficiente, no tenía mucho sentido ser un singleton tbh. Sin embargo, ¿por qué solo recogería entropía la primera vez? Seguramente tendrías que hacerlo cada vez que llamaste a getInstance. – andrewktmeikle

1

El objeto Cipher no va a ser seguro para subprocesos, ya que conserva el estado interno sobre el proceso de cifrado. Esto también se aplica a su clase DesEncrypter; cada subproceso tendrá que usar su propia instancia de DesEncrypter, a menos que sincronice los métodos encode y decode.

+0

Ver mi ejemplo anterior ... ¿por qué no crear una nueva instancia de Cipher para cada invocación de encrypt()/decrypt()? – user646584

+2

Sí, pero en su ejemplo está usando las variables de instancia 'ecipher' y' dcipher' para almacenar las instancias de Cipher, así que si 2 hilos llaman encrypt() en la misma instancia 'DesEncrypter' simultáneamente, se pegarán unos a otros (a menos que sincronice la llamada 'encrypt()'). Para evitar esto, podría hacer que 'ecipher' y' dcipher' sean variables locales (dentro de la función encrypt()) en lugar de variables de instancia, de ese modo cada invocación de encrypt() tendría su propio valor. –

Cuestiones relacionadas