2010-08-10 20 views
71

Quiero encriptar una cadena usando AES con mi propia clave. Pero estoy teniendo problemas con la longitud de bits de la clave. ¿Puedes revisar mi código y ver qué debo arreglar/cambiar?Java AES y usando mi propia clave

public static void main(String[] args) throws Exception { 
    String username = "[email protected]"; 
    String password = "Password1"; 
    String secretID = "BlahBlahBlah"; 
    String SALT2 = "deliciously salty"; 

    // Get the Key 
    byte[] key = (SALT2 + username + password).getBytes(); 
    System.out.println((SALT2 + username + password).getBytes().length); 

    // Need to pad key for AES 
    // TODO: Best way? 

    // Generate the secret key specs. 
    SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); 

    // Instantiate the cipher 
    Cipher cipher = Cipher.getInstance("AES"); 
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); 

    byte[] encrypted = cipher.doFinal((secrectID).getBytes()); 
    System.out.println("encrypted string: " + asHex(encrypted)); 

    cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); 
    byte[] original = cipher.doFinal(encrypted); 
    String originalString = new String(original); 
    System.out.println("Original string: " + originalString + "\nOriginal string (Hex): " + asHex(original)); 
} 

En este momento me sale una excepción "no válida longitud de la clave AES: 86 bytes". ¿Debo rellenar mi llave? ¿Cómo debería hacerlo?

¿También necesito configurar algo para ECB o CBC?

Gracias

+5

[Encuentro su falta de perturbar la sal al azar] (http://d37nnnqwv9amwr.cloudfront.net/photos/images/newsfeed/000/065/003/Darth-Vader-I-FIND- SU-FALTA DE FE-DISTURBING.jpg). Ahora en serio: en el contexto de la criptografía [SALT debe ser al azar] (http://en.wikipedia.org/wiki/Salt_ (criptografía)) –

+13

Jaja, gracioso. De hecho, tengo una sal al azar, pero limpié mi código para que mi pregunta fuera más clara. Es por eso que la variable se llama SALT2. Pero es una buena referencia para otros que se encuentran con este mismo problema y les gusta copiar/pegar código. –

Respuesta

109

Debe usar SHA-1 para generar un hash de su clave y recortar el resultado a 128 bits (16 bytes).

Además, no genera matrices de bytes de cadenas a través de getBytes() utiliza el Charset predeterminado de la plataforma. Por lo tanto, la contraseña "blaöä" da como resultado una matriz de bytes diferente en diferentes plataformas.

byte[] key = (SALT2 + username + password).getBytes("UTF-8"); 
MessageDigest sha = MessageDigest.getInstance("SHA-1"); 
key = sha.digest(key); 
key = Arrays.copyOf(key, 16); // use only first 128 bit 

SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); 

Editar: Si necesita 256 bits como tamaño de las claves que necesita para descargar el "archivos de Java Cryptography Extension (JCE) Ilimitado Política de Fuerza jurisdicción" Oracle download link, utilizar SHA-256 como hachís y eliminar los matrices. copyOf línea. "ECB" es el modo de cifrado predeterminado y "PKCS5Padding" el relleno predeterminado. Usted podría utilizar diferentes modos de cifrado y modos de relleno a través de la cadena deCipher.getInstance usando siguiente formato: "Cipher/Modo/Relleno"

Para AES mediante CTS y PKCS5Padding la cadena es: "AES/CTS/PKCS5Padding"

+0

Esto funcionará, pero es una contraseña de hash, y solo utiliza los primeros bits. No hay mejor manera de hacer esto? –

+4

No hay mejor forma de generar la clave, porque AES necesita una clave de 128/192/256 bits. Si no hash tu llave y solo recortas la entrada, solo usaría los primeros 16/24/32 Bytes. Entonces, generar un hash es la única forma razonable. – mknjc

+1

Impresionante, gracias por el consejo sobre getBytes() y el enlace de descarga a los archivos de políticas de jurisdicción de fuerza ilimitada. –

13

se debe utilizar un KeyGenerator para generar la clave,

AES longitudes de clave son 128, 192 y 256 bits dependiendo del cifrado que desea utilizar.

Tome un vistazo al tutorial here

Aquí está el código de contraseña de cifrado base, esto tiene la contraseña introducida a través System.in puede cambiar que para usar una contraseña almacenada si lo desea.

 PBEKeySpec pbeKeySpec; 
     PBEParameterSpec pbeParamSpec; 
     SecretKeyFactory keyFac; 

     // Salt 
     byte[] salt = { 
      (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c, 
      (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99 
     }; 

     // Iteration count 
     int count = 20; 

     // Create PBE parameter set 
     pbeParamSpec = new PBEParameterSpec(salt, count); 

     // Prompt user for encryption password. 
     // Collect user password as char array (using the 
     // "readPassword" method from above), and convert 
     // it into a SecretKey object, using a PBE key 
     // factory. 
     System.out.print("Enter encryption password: "); 
     System.out.flush(); 
     pbeKeySpec = new PBEKeySpec(readPassword(System.in)); 
     keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES"); 
     SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec); 

     // Create PBE Cipher 
     Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES"); 

     // Initialize PBE Cipher with key and parameters 
     pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec); 

     // Our cleartext 
     byte[] cleartext = "This is another example".getBytes(); 

     // Encrypt the cleartext 
     byte[] ciphertext = pbeCipher.doFinal(cleartext); 
+2

¿Cómo puedo generar mi clave con la contraseña usando KeyGenerator? Quiero generar la misma clave basada en la contraseña. Entonces puedo descifrar la cadena más tarde. –

+0

Lo que está hablando es el cifrado basado en contraseña no AES.Actualicé mi respuesta con el programa de ejemplo para PBE – Keibosh

+1

Intente utilizar el generador de claves PBEKDF2 en su lugar, usando la cadena "PBKDF2WithHmacSHA1" para 'SecretKeyFactory' para obtener un cifrado más actualizado. –

5
import java.security.Key; 
import javax.crypto.Cipher; 
import javax.crypto.spec.SecretKeySpec; 
import sun.misc.*; 
import java.io.BufferedReader; 
import java.io.FileReader; 

public class AESFile 
{ 
private static String algorithm = "AES"; 
private static byte[] keyValue=new byte[] {'0','2','3','4','5','6','7','8','9','1','2','3','4','5','6','7'};// your key 

    // Performs Encryption 
    public static String encrypt(String plainText) throws Exception 
    { 
      Key key = generateKey(); 
      Cipher chiper = Cipher.getInstance(algorithm); 
      chiper.init(Cipher.ENCRYPT_MODE, key); 
      byte[] encVal = chiper.doFinal(plainText.getBytes()); 
      String encryptedValue = new BASE64Encoder().encode(encVal); 
      return encryptedValue; 
    } 

    // Performs decryption 
    public static String decrypt(String encryptedText) throws Exception 
    { 
      // generate key 
      Key key = generateKey(); 
      Cipher chiper = Cipher.getInstance(algorithm); 
      chiper.init(Cipher.DECRYPT_MODE, key); 
      byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedText); 
      byte[] decValue = chiper.doFinal(decordedValue); 
      String decryptedValue = new String(decValue); 
      return decryptedValue; 
    } 

//generateKey() is used to generate a secret key for AES algorithm 
    private static Key generateKey() throws Exception 
    { 
      Key key = new SecretKeySpec(keyValue, algorithm); 
      return key; 
    } 

    // performs encryption & decryption 
    public static void main(String[] args) throws Exception 
    { 
     FileReader file = new FileReader("C://myprograms//plaintext.txt"); 
     BufferedReader reader = new BufferedReader(file); 
     String text = ""; 
     String line = reader.readLine(); 
    while(line!= null) 
     { 
      text += line; 
    line = reader.readLine(); 
     } 
     reader.close(); 
    System.out.println(text); 

      String plainText = text; 
      String encryptedText = AESFile.encrypt(plainText); 
      String decryptedText = AESFile.decrypt(encryptedText); 

      System.out.println("Plain Text : " + plainText); 
      System.out.println("Encrypted Text : " + encryptedText); 
      System.out.println("Decrypted Text : " + decryptedText); 
    } 
} 
+3

Quizás agregue un poco más de texto de explicación. – DaGardner

+1

No se recomienda tener una clave codificada – sashank

+0

Pregunta, ¿de qué sirve tener 'keyValue' con la matriz de bytes? Veo que se usa para hacer la llave, ¿por qué? ¿Se puede hacer algo usando como 'SecretKey' en su lugar? ¿Si es así, cómo? – Austin

2

Esto funcionará.

public class CryptoUtils { 

    private final String TRANSFORMATION = "AES"; 
    private final String encodekey = "1234543444555666"; 
    public String encrypt(String inputFile) 
      throws CryptoException { 
     return doEncrypt(encodekey, inputFile); 
    } 


    public String decrypt(String input) 
      throws CryptoException { 
    // return doCrypto(Cipher.DECRYPT_MODE, key, inputFile); 
    return doDecrypt(encodekey,input); 
    } 

    private String doEncrypt(String encodekey, String inputStr) throws CryptoException { 
     try { 

      Cipher cipher = Cipher.getInstance(TRANSFORMATION); 

      byte[] key = encodekey.getBytes("UTF-8"); 
      MessageDigest sha = MessageDigest.getInstance("SHA-1"); 
      key = sha.digest(key); 
      key = Arrays.copyOf(key, 16); // use only first 128 bit 

      SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); 

      cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); 

      byte[] inputBytes = inputStr.getBytes();  
      byte[] outputBytes = cipher.doFinal(inputBytes); 

      return Base64Utils.encodeToString(outputBytes); 

     } catch (NoSuchPaddingException | NoSuchAlgorithmException 
       | InvalidKeyException | BadPaddingException 
       | IllegalBlockSizeException | IOException ex) { 
      throw new CryptoException("Error encrypting/decrypting file", ex); 
     } 
    } 


    public String doDecrypt(String encodekey,String encrptedStr) { 
      try {  

       Cipher dcipher = Cipher.getInstance(TRANSFORMATION); 
       dcipher = Cipher.getInstance("AES"); 
       byte[] key = encodekey.getBytes("UTF-8"); 
       MessageDigest sha = MessageDigest.getInstance("SHA-1"); 
       key = sha.digest(key); 
       key = Arrays.copyOf(key, 16); // use only first 128 bit 

       SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES"); 

       dcipher.init(Cipher.DECRYPT_MODE, secretKeySpec); 
      // decode with base64 to get bytes 

       byte[] dec = Base64Utils.decode(encrptedStr.getBytes()); 
       byte[] utf8 = dcipher.doFinal(dec); 

       // create new string based on the specified charset 
       return new String(utf8, "UTF8"); 

      } catch (Exception e) { 

      e.printStackTrace(); 

      } 
     return null; 
     } 
} 
0
byte[] seed = (SALT2 + username + password).getBytes(); 
    SecureRandom random = new SecureRandom(seed); 
    KeyGenerator generator; 
    generator = KeyGenerator.getInstance("AES"); 
    generator.init(random); 
    generator.init(256); 
    Key keyObj = generator.generateKey(); 
Cuestiones relacionadas