2015-01-10 3 views
2

Я пытаюсь зашифровать/дешифровать с помощью AES256 с использованием Java для шифрования и CryptoJS для дешифрования. Шифрование проверено в Java is Работает отлично, но метод дешифрования в JavaScript возвращает пустую строку. Обратите внимание, что для проверки JavaScript я распечатал в файле tmp значения для данных, IV и соли, а затем жестко закодировал в JS. (Примечание: формат в файле: data (byte [] base64), Iv (строка base64) и соль (строка base64)).Метод расшифровки CryptoJs возвращает пустую строку

Вот код в Java:

public byte[] encrypt(String plainText) throws Exception {   
    //get salt 
    salt = generateSalt();  
    byte[] saltBytes = salt.getBytes("UTF-8"); 

    // Derive the key 
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 
    PBEKeySpec spec = new PBEKeySpec(
      password.toCharArray(), 
      saltBytes, 
      pswdIterations, 
      keySize 
      ); 

    SecretKey secretKey = factory.generateSecret(spec); 
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES"); 

    //encrypt the message 
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
    cipher.init(Cipher.ENCRYPT_MODE, secret); 
    AlgorithmParameters params = cipher.getParameters(); 
    ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV(); 
    byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8")); 
    return Base64.encode(encryptedTextBytes); 
} 

, что не так с кодом дешифрования в JavaScript ниже?

// the password that user provides 
var userPass = document.getElementById("password").value; 
console.log("user pass : " + userPass); 
// hash contains 5 bytes 
var hashedPass = CryptoJS.SHA1(userPass); 
console.log("hashed pass : " + hashedPass.toString(CryptoJS.enc.Base64) + " | array length " + hashedPass.words.length + " | " + typeof(hashedPass)); 
// use only 4 bytes (128 bits) from the hashed pass 
// (same as used in java when encrypting) 
/////////////////////////var hashed4bytes = CryptoJS.lib.WordArray.create(hashedPass.words.slice(0,4)); 
//console.log("hashed4bytes encoded 64 = " + hashed4bytes.toString(CryptoJS.enc.Base64)); 

// get the encrypted msg 
var encMsg64 = document.getElementById("themessage").innerHTML; 
encMsg64 = encMsg64.toString(CryptoJS.enc.Base64); 
//var encMsg = CryptoJS.enc.Base64.parse(encMsg64); 
var salt =CryptoJS.enc.Base64.parse("EAWnOgxUDuvhWqrSUsugq1umMpI="); 
var iv =CryptoJS.enc.Base64.parse("xWpmXNbmbFjmWBUajuWYXQ=="); 
//var salt = "EAWnOgxUDuvhWqrSUsugq1umMpI="; 
//var iv = "xWpmXNbmbFjmWBUajuWYXQ=="; 
console.log('salt '+ salt); 
console.log('iv '+ iv); 


var key = CryptoJS.PBKDF2(hashedPass, salt, { keySize: 256/32, iterations: 1000 }); 
console.log('key '+ key); 

var decText = ''; 
var ok = true; 
try { 
    debugger; 
    var decMsg = CryptoJS.AES.decrypt(encMsg64, key, { 
     iv:iv, 
     mode: CryptoJS.mode.CBC, 
     padding: CryptoJS.pad.Pkcs7 
     }); 
    console.log("decryptedData = " + decMsg); 

    // convert to UTF8 string 
    decText = decMsg.toString(CryptoJS.enc.Utf8); 
    console.log("decryptedText = " + decText); 

    if (decText == '') { 
     ok = false; 
    } 
} 
catch (e) { 
    //console.log("Error when decrypting: " + e.message) 
    ok = false; 
} 

после Mafe измененная проблема все еще сохраняется Вот полный код после изменения

JAVA

public class AES256EncryptionServiceBean implements EncryptionService { 

    private static final Logger LOGGER = LoggerFactory 
      .getLogger(AES256EncryptionServiceBean.class); 
    private String salt = null; //get bytes out of UTF-8 for decryption 
    private static final int PSWDITERATIONS = 1000;//65536; 
    private static final int KEYSIZE = 256; 
    private static final String AES_ALGO = "AES"; 
    private static final String SHA1_ALGO = "PBKDF2WithHmacSHA1"; 
    private static final String AES_CBC_PKCS5_TRANSFORM = "AES/CBC/PKCS5Padding"; 
    private byte[] Iv; 

    /** 
    * Encrypts the data with AES-256 algorithm Encrypted data will be encoded 
    * with base64 algorithm and the returned. Initial vector is being used 
    * during encryption along with CBC encryption mode. 
    * 
    * output format: [algo indicator(1char)][Initialization vector()][salt()][encoded data(variable size)] 
    */ 
    @Override 
    public byte[] encrypt(String password, byte[] data) throws PibException { 
     byte[] encodedData = null; 
     try { 
      byte[] encryptedData = encryptCBC256Bits(password, data); 
      encodedData = Base64.encodeBase64(encryptedData); 
      /*String finalStr=null; 
      String algo256 = "2"; 
      String datastr = Base64.encodeBase64String(encryptedData); 
      String ivstr = new String(Iv); 
      finalStr = algo256 +ivstr+salt+datastr; 

      encodedData = finalStr.getBytes(); 
      */ 
     } catch (Exception e) { 
      throw ExceptionFactory.createPibException(
        MessageCodes.PIB_ENCRYPTION_FAILED, e, LOGGER); 
     } 
     return encodedData; 
    } 

    /** 
    * Encrypts the input data with AES CBC transformation using 256 bits (32 
    * bytes) Key is generated based on the provided password and random salt. 
    * Salt is the extra bits added to the password to ensure every key is 
    * unique SHA1 hashing is also participate in key generation. 
    * 
    * @throws PibException 
    * 
    */ 
    private byte[] encryptCBC256Bits(String password, byte[] data) 
      throws PibException { 

     salt = generateSalt(); 
     byte[] saltBytes = salt.getBytes(StandardCharsets.UTF_8); 
     byte[] encryptedTextBytes = null; 

     // Derive the key 

     try { 
      SecretKeyFactory factory = SecretKeyFactory.getInstance(SHA1_ALGO); 
      // Password based key specification 
      PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, 
        PSWDITERATIONS, KEYSIZE); 
      SecretKey secretKey = factory.generateSecret(spec); 
      SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), 
        AES_ALGO); 

      // encrypt the data 
      Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5_TRANSFORM); 
      // SecureRandom random = new SecureRandom(); 
      // byte[] ivTemp = new byte[16]; 
      // random.nextBytes(ivTemp); 
      cipher.init(Cipher.ENCRYPT_MODE, secret); 
      AlgorithmParameters params = cipher.getParameters(); 
      Iv = params.getParameterSpec(IvParameterSpec.class).getIV(); 
      encryptedTextBytes = cipher.doFinal(data); 

     } catch (NoSuchAlgorithmException | InvalidKeySpecException 
       | NoSuchPaddingException | InvalidKeyException 
       | InvalidParameterSpecException | IllegalBlockSizeException 
       | BadPaddingException e) { 
      throw ExceptionFactory.createPibException(
        MessageCodes.PIB_ENCRYPTION_FAILED, e, LOGGER); 
     } 

     return encryptedTextBytes; 
    } 

    private String generateSalt() { 

     SecureRandom random = new SecureRandom(); 
     byte bytes[] = new byte[20]; 
     random.nextBytes(bytes); 
     String s = new String(bytes); 
     return s; 

    } 

    public String getSalt() { 
     return salt; 
    } 

    public byte[] getIv() { 
     return Iv; 
    } 

} 

Javascript

function decryptMsg256() { 

       // the password that user provides 
       var userPass = document.getElementById("password").value; 
       console.log("user pass : " + userPass); 


       // get the encrypted msg 
       var encMsg64 = document.getElementById("themessage").innerHTML; 
       var encMsg = CryptoJS.enc.Base64.parse(encMsg64); 
       var salt =CryptoJS.enc.Utf8.parse("?E€O5?…°®I^y??O:n"); 
       var iv =CryptoJS.enc.Utf8.parse("S;Ui?¨=ENzI—$"); 

       console.log('salt '+ salt); 
       console.log('iv '+ iv); 


       var key = CryptoJS.PBKDF2("password", salt, { keySize: 256/32, iterations: 1000 }); 
       console.log('key '+ key); 

       var decText = ''; 
       var ok = true; 
       try { 
        debugger; 
        var decMsg = CryptoJS.AES.decrypt(encMsg, key, { 
         iv:iv, 
         mode: CryptoJS.mode.CBC, 
         padding: CryptoJS.pad.Pkcs7 
         }); 
        console.log("decryptedData = " + decMsg); 

        // convert to UTF8 string 
        decText = decMsg.toString(CryptoJS.enc.Utf8); 
        console.log("decryptedText = " + decText); 

        if (decText == '') { 
         ok = false; 
        } 
       } 
       catch (e) { 
        //console.log("Error when decrypting: " + e.message) 
        ok = false; 
       } 

я не могу понимает, что это не так, пожалуйста, помогите зашифрованного текста, соль и Iv извлекается следующим образом:

public void testEncryption_WriteToFile() throws Exception { 

     byte[] data = IOUtils.toByteArray(this.getClass().getClassLoader() 
       .getResourceAsStream(SOME_FILE_NAME)); 

     byte[] encryptedData = this.encryptionService.encrypt(PASSWORD, data); 
     byte[] initial_vector = ((AES256EncryptionServiceBean) encryptionService) 
     .getIv(); 
     String salt = ((AES256EncryptionServiceBean) encryptionService) 
       .getSalt(); 


     IOUtils.write(encryptedData, new FileOutputStream(
       "C:\\Temp\\data.encrypted")); 
     /*IOUtils.write(new String(encryptedData), new FileOutputStream(
       "C:\\Temp\\data[byte32string].encrypted")); 
     */ 
     IOUtils.write(Base64.encodeBase64String(salt.getBytes(StandardCharsets.UTF_8)), new FileOutputStream(
       "C:\\Temp\\salt.encrypted")); 
     /*IOUtils.write(salt.getBytes(StandardCharsets.UTF_8), new FileOutputStream(
       "C:\\Temp\\salt.encrypted")); 
     */ 
     IOUtils.write(Base64.encodeBase64String(initial_vector), new FileOutputStream(
       "C:\\Temp\\iv.encrypted")); 
     /*IOUtils.write(initial_vector, new FileOutputStream(
       "C:\\Temp\\iv.encrypted"));*/ 


    } 
+0

Большое спасибо за ответ. Я использую пароль в Js, так как я использую «PBKDF2WithHmacSHA1» для генерации ключей на Java, это неверно? Я использую toString вместо Base64.parse, поскольку сообщение уже находится в base64, поскольку оно возвращается из java (byte [] base64), это тоже не правильно? – marios390

+0

К сожалению, после того, как измененная проблема по-прежнему сохраняется (возвращает пустую строку): – marios390

+0

Вы представили новую проблему, см. Мой обновленный ответ. Вы подтвердили, что генерируете один и тот же ключ? Кроме того, это не полный код.Вы не показали, как вы получите шифрованный текст, соль и IV из кода Java. –

ответ

3

CryptoJS.PBKDF2 использует SHA1 по умолчанию. Таким образом, до тех пор, пока один и тот же пароль, соль, ключи и счетчик итераций будут поставляться, он выдаст тот же ключ. Проблема заключается в том, что в JavaScript вы дополнительно используете пароль с SHA1. Не делайте этого и передавайте пароль непосредственно в PBKDF2 так же, как это делается на Java.

Вторая проблема заключается в том, что зашифрованный текст должен быть в собственном формате CryptoJS при попытке расшифровки. Поскольку вы получаете шифрованный текст с кодировкой base 64 с Java, вы должны декодировать его как таковой. Раскомментируйте строку:

var encMsg = CryptoJS.enc.Base64.parse(encMsg64); 

и не делать encMsg64 = encMsg64.toString(CryptoJS.enc.Base64);, так как это будет кодировать уже кодированный шифротекст снова.


Для обновленного кода вы не можете печатать свой ключ и соль просто как строку и ожидать, что он будет работать в JavaScript. Это не так. byte[]. Они содержат непечатаемые символы, которые будут потеряны при попытке проанализировать его на JavaScript. Вы должны закодировать все значения byte[], которые вы хотите переместить с Java на JavaScript в качестве Base64, а затем декодировать их в JavaScript.

+0

Спасибо, очень многое, теперь все ясно. Я также использовал другой счетчик итераций в Js (1000) вместо 65000+, используемых в java. – marios390

+0

Еще один вопрос: инструкция var encMsg = CryptoJS.enc.Base64.parse (encMsg64); не должен сопровождаться toString вместе? – marios390

+0

Нет, это не так. 'parse' производит собственное двоичное представление в CryptoJS, которое представляет собой массив целых чисел (4 байтовых слова), который является представлением, которое требуется' CryptoJS.AES.decrypt'. 'toString' выведет из него строку, и если вы передадите кодировщик, он дополнительно закодирует ее с этим. –

Смежные вопросы