2014-12-01 2 views
2

Фон: Приложение, над которым я работаю, должно работать в автономном режиме. Я должен зашифровать некоторые текстовые данные, используя пароль в качестве ключа на стороне сервера java. Зашифрованные данные передаются на страницу HTML5 и на стороне клиента, используя библиотеку crypto-js, зашифрованные данные сервера должны быть дешифрованы.Каковы используемые параметры AES и шаги, выполняемые внутри crypto-js при шифровании сообщения паролем?

Мой вопрос: Для того, чтобы зашифровать свое сообщение таким образом, что клиент может расшифровать его с крипт-JS (с помощью пользователь ввел пароль), мне нужно знать точные шаги, которые крипто-JS ожидает при шифровании сообщения.

Что мне нужно знать: У меня есть следующий код шифрования, который делает шифрование сообщения на стороне клиента с помощью крипто-JS.

var message = "my message text"; 
var password = "user password"; 
var encrypted = CryptoJS.AES.encrypt(message ,password); 
console.log(encrypted.toString()); 

мне нужно знать параметры AES, используемые CryptoJS время шифрования сообщения (Не уверен, что они есть, но это звучит как: размер ключа (256), утеплитель (pkcs5), режим (CBC), PBE (PBKDF2), соль (случайный), счетчик итераций (100)). Было бы очень полезно, если бы кто-нибудь смог это подтвердить ... Я пытался решить эту тайну в течение последних нескольких дней ?.

мне нужно знать различные шаги, выполняемые CryptoJS в то время как AES шифрования сообщения

+0

сэр, у меня есть переместил изменения отсюда к отдельному вопросу. http://stackoverflow.com/questions/27248644/how-to-decrypt-a-cryptojs-aes-encrypted-message-at-the-java-server-side – user1455719

ответ

7

CryptoJS uses не-стандартизированное OpenSSL KDF для ключа вывода (EvpKDF) с MD5 как алгоритм хэширования и итерации. IV также получен из пароля, что означает, что для расшифровки этого на стороне Java необходимы только фактический зашифрованный текст, пароль и соль.

Другими словами, PBKDF2 не используется для деривации ключей в режиме пароля CryptoJS. По умолчанию AES-256 используется в режиме CBC с дополнением PKCS5 (это same as PKCS7 padding). Имейте в виду, что вам может понадобиться JCE Unlimited Strength Jurisdiction Policy Files. См. Также Why there are limitations on using encryption with keys beyond certain length?

Следующий код воссоздает KDF в Java (keySize и ivSize 8 соответственно 4 для AES-256 и исходят).

public static byte[] evpKDF(byte[] password, int keySize, int ivSize, byte[] salt, int iterations, String hashAlgorithm, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException { 
    int targetKeySize = keySize + ivSize; 
    byte[] derivedBytes = new byte[targetKeySize * 4]; 
    int numberOfDerivedWords = 0; 
    byte[] block = null; 
    MessageDigest hasher = MessageDigest.getInstance(hashAlgorithm); 
    while (numberOfDerivedWords < targetKeySize) { 
     if (block != null) { 
      hasher.update(block); 
     } 
     hasher.update(password); 
     block = hasher.digest(salt); 
     hasher.reset(); 

     // Iterations 
     for (int i = 1; i < iterations; i++) { 
      block = hasher.digest(block); 
      hasher.reset(); 
     } 

     System.arraycopy(block, 0, derivedBytes, numberOfDerivedWords * 4, 
       Math.min(block.length, (targetKeySize - numberOfDerivedWords) * 4)); 

     numberOfDerivedWords += block.length/4; 
    } 

    System.arraycopy(derivedBytes, 0, resultKey, 0, keySize * 4); 
    System.arraycopy(derivedBytes, keySize * 4, resultIv, 0, ivSize * 4); 

    return derivedBytes; // key + iv 
} 

Вот полный класс для справки:

public class RecreateEVPkdfFromCryptoJS { 
    public static void main(String[] args) throws UnsupportedEncodingException, GeneralSecurityException { 
     String msg = "hello"; 
     String password = "mypassword"; 
     String ivHex = "aab7d6aca0cc6ffc18f9f5909753aa5f"; 
     int keySize = 8; // 8 words = 256-bit 
     int ivSize = 4; // 4 words = 128-bit 
     String keyHex = "844a86d27d96acf3147aa460f535e20e989d1f8b5d79c0403b4a0f34cebb093b"; 
     String saltHex = "ca35168ed6b82778"; 
     String openSslFormattedCipherTextString = "U2FsdGVkX1/KNRaO1rgneK9S3zuYaYZcdXmVKJGqVqk="; 
     String cipherTextHex = "af52df3b9869865c7579952891aa56a9"; 
     String padding = "PKCS5Padding"; 

     byte[] key = hexStringToByteArray(keyHex); 
     byte[] iv = hexStringToByteArray(ivHex); 
     byte[] salt = hexStringToByteArray(saltHex); 
     byte[] cipherText = hexStringToByteArray(cipherTextHex); 

     byte[] javaKey = new byte[keySize * 4]; 
     byte[] javaIv = new byte[ivSize * 4]; 
     evpKDF(password.getBytes("UTF-8"), keySize, ivSize, salt, javaKey, javaIv); 
     System.out.println(Arrays.equals(key, javaKey) + " " + Arrays.equals(iv, javaIv)); 

     Cipher aesCipherForEncryption = Cipher.getInstance("AES/CBC/PKCS5Padding"); // Must specify the mode explicitly as most JCE providers default to ECB mode!! 

     IvParameterSpec ivSpec = new IvParameterSpec(javaIv); 
     aesCipherForEncryption.init(Cipher.DECRYPT_MODE, new SecretKeySpec(javaKey, "AES"), ivSpec); 

     byte[] byteMsg = aesCipherForEncryption.doFinal(cipherText); 
     System.out.println(Arrays.equals(byteMsg, msg.getBytes("UTF-8"))); 
    } 

    public static byte[] evpKDF(byte[] password, int keySize, int ivSize, byte[] salt, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException { 
     return evpKDF(password, keySize, ivSize, salt, 1, "MD5", resultKey, resultIv); 
    } 

    public static byte[] evpKDF(byte[] password, int keySize, int ivSize, byte[] salt, int iterations, String hashAlgorithm, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException { 
     int targetKeySize = keySize + ivSize; 
     byte[] derivedBytes = new byte[targetKeySize * 4]; 
     int numberOfDerivedWords = 0; 
     byte[] block = null; 
     MessageDigest hasher = MessageDigest.getInstance(hashAlgorithm); 
     while (numberOfDerivedWords < targetKeySize) { 
      if (block != null) { 
       hasher.update(block); 
      } 
      hasher.update(password); 
      block = hasher.digest(salt); 
      hasher.reset(); 

      // Iterations 
      for (int i = 1; i < iterations; i++) { 
       block = hasher.digest(block); 
       hasher.reset(); 
      } 

      System.arraycopy(block, 0, derivedBytes, numberOfDerivedWords * 4, 
        Math.min(block.length, (targetKeySize - numberOfDerivedWords) * 4)); 

      numberOfDerivedWords += block.length/4; 
     } 

     System.arraycopy(derivedBytes, 0, resultKey, 0, keySize * 4); 
     System.arraycopy(derivedBytes, keySize * 4, resultIv, 0, ivSize * 4); 

     return derivedBytes; // key + iv 
    } 

    /** 
    * Copied from http://stackoverflow.com/a/140861 
    * */ 
    public static byte[] hexStringToByteArray(String s) { 
     int len = s.length(); 
     byte[] data = new byte[len/2]; 
     for (int i = 0; i < len; i += 2) { 
      data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) 
        + Character.digit(s.charAt(i+1), 16)); 
     } 
     return data; 
    } 
} 

и код JavaScript, который был использован для генерации значений в коде Java:

var msg = "hello"; 
var password = "mypassword"; // must be present on the server 
var encrypted = CryptoJS.AES.encrypt(msg, password); 
var ivHex = encrypted.iv.toString(); 
var ivSize = encrypted.algorithm.ivSize; // same as the blockSize 
var keySize = encrypted.algorithm.keySize; 
var keyHex = encrypted.key.toString(); 
var saltHex = encrypted.salt.toString(); // must be sent as well 
var openSslFormattedCipherTextString = encrypted.toString(); // not used 
var cipherTextHex = encrypted.ciphertext.toString(); // must be sent 
+0

Аналогичный код можно найти в моих ответах для [PHP] (https://stackoverflow.com/a/27678978/1816580) и [ Python] (https://stackoverflow.com/a/36780727/1816580). –

0

Я ищу at the documentation здесь:

  • размер ключа: «Если вы используете кодовую фразу, то он будет генерировать 256-битный ключ ».
  • обивка: PKCS7 (по умолчанию)
  • режим: КРК (по умолчанию)
  • IV: сгенерированы и сохранены в шифрованный текст объекта: использовать с «encrypted.iv»

материал для генерации ключ:

  • соли: сгенерированы и сохранены в шифровки текстового объекта: использовать с «encrypted.salt» (хотя на самом деле не сказать, что, таким образом, я предполагаю здесь)
  • РВЕ Алгоритм: Непонятно. Это не задокументировано.
  • счетчик итераций: я не могу найти это документально нигде. Примеры в коде, как представляется, используют 1000.

Вы можете установить параметры вручную, что, возможно, безопаснее, чем полагаться на значения по умолчанию, например. некоторый псевдокод на основе примеров в документации:

var salt = CryptoJS.lib.WordArray.random(128/8); 
var iv = CryptoJS.lib.WordArray.random(128); 
var key256Bits10000Iterations = CryptoJS.PBKDF2("Secret Passphrase", salt, { keySize: 256/32, iterations: 10000 }); //I don't know this is dividing by 32 
var encrypted = CryptoJS.AES.encrypt("Message", key, { mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7, iv:iv }); 

Возможно, вам придется экспериментировать. Я бы сделал это шаг за шагом. Получите ключи, основанные на пароле, чтобы соответствовать, перепутывая эти параметры, а затем закрепите зашифрованный текст, затем определите расшифровку. Избегайте стремления упростить такие вещи, как пропустить IV или использовать ЕЦБ.

+1

PBKDF2 фактически не используется во время шифрования в режиме пароля –

+0

Weird. Я догадывался, потому что это единственное, что указано в другом месте. Вы знаете, как он генерирует ключ в режиме пароля? Если это так, еще больше причин сделать это вручную. –

+0

Artjom B, это было бы очень полезно, если бы вы могли написать ответ. Я как бы застрял и смущен. – user1455719

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