Почему decipherIv.final () не работает в node.js при расшифровке значения, зашифрованного с помощью PHP? - PullRequest
2 голосов
/ 17 апреля 2019

Версия PHP: 5.6.39

Версия Node.js: 10.9.0

Цель: Шифрованиеиспользуя PHP и расшифровывая с помощью Node.js

Точка застревания: В настоящее время я предполагаю, что привязки PHP и Node.js к OpenSSL используют заполнение PKCS7. Используют ли PHP и Node.js несовместимые привязки к OpenSSL?

Пример кода шифрования / дешифрования PHP:

class SymmetricEncryption {

   public static function simpleEncrypt($key, $plaintext) {
      $iv = openssl_random_pseudo_bytes(16);
      $ciphertext = openssl_encrypt($plaintext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv)

      return base64_encode($iv) . "." . base64_encode($ciphertext);
   }

   public static function simpleDecrypt($key, $token) {
       list($iv, $ciphertext) = explode(".", $token);

        return openssl_decrypt(
           base64_decode($ciphertext),
           "aes-256-cbc",
           $key,
           OPENSSL_RAW_DATA,
           base64_decode($iv)
        );
   }
}

Пример кода шифрования / дешифрования Node.js:

class SymmetricEncryption {

    static simpleEncrypt(key: Buffer, plaintext: string): string {
        const iv = randomBytes(16)
        const cipher = createCipheriv('aes-256-cbc', key, iv)
        const encrypted = cipher.update(plaintext)
        const token = Buffer.concat([encrypted, cipher.final()])

        return iv.toString('base64') + "." + token.toString('base64')
    }

    static simpleDecrypt(key: Buffer, token: string): string {
        const [iv, ciphertext] = token.split(".").map(piece => Buffer.from(piece, 'base64'))
        const decipher = createDecipheriv('aes-256-cbc', key, iv)
        const output = decipher.update(ciphertext)
        return Buffer.concat([output, decipher.final()]).toString('utf8')
    }
}

Я успешно протестировал каждую реализацию независимо друг от друга, но при шифровании в PHP и дешифровании в файле node.js я получаю следующую ошибку:

Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt

Точки трассировки стекаменя к ошибочной строке, которая decipher.final() в методе simpleDecrypt.

Я использую следующий (неудачный) модульный тест для проверки моей реализации

it('should be able to decrypt values from php', () => {
    const testAesKey = Buffer.from('9E9CEB8356ED0212C37B4D8CEA7C04B6239175420203AF7A345527AF9ADB0EB8', 'hex')
    const phpToken = 'oMhL/oIPAGQdMvphMyWdJw==.bELyRSIwy+nQGIyLj+aN8A=='
    const decrypted = SymmetricEncryption.simpleDecrypt(testAesKey, phpToken)
    expect(decrypted).toBe('hello world')
})

The *Используемая здесь переменная 1035 * была создана с использованием следующего кода:

$testAesKey = "9E9CEB8356ED0212C37B4D8CEA7C04B6239175420203AF7A345527AF9ADB0EB8";

echo SymmetricEncryption::simpleEncrypt($testAesKey, "hello world");

1 Ответ

1 голос
/ 17 апреля 2019

Я подозреваю, что ваша проблема вызвана тем, как вы передаете свой ключ в PHP. Документация для openssl_encrypt нигде не указывает, что он интерпретирует ключ как шестнадцатеричный. Он делает , однако обрезает слишком длинные ключи.

Вероятно, здесь происходит то, что PHP усекает вашу шестнадцатеричную строку из 64 символов до 32 байтов и использует их для ключа. Попробуйте использовать hex2bin на своем ключе PHP перед его использованием - это должно исправить вашу проблему!

$testAesKey = hex2bin("9E9CEB8356ED0212C37B4D8CEA7C04B6239175420203AF7A345527AF9ADB0EB8");
...