Aes шифрование в NodeJS - PullRequest
0 голосов
/ 30 марта 2020

Я пытаюсь перенести приложение ruby на NodeJs и застрял с проблемой шифрования. В приложении ruby мы используем ActiveRecord , и у одной из моделей есть поле пароля. В базе данных это поле пароля сохраняется в двух столбцах - пароль и пароль_iv . Шифтору передаются простые параметры:

Encryptor.default_options.merge!(
  algorithm: 'aes-256-gcm',
  key: secretKey,
  iv: globalIV,
  salt: globalSalt
)

Теперь я пытаюсь расшифровать этот пароль в приложении Node:

  decrypt(encryptedPassword: string, passwordIv: string) {
    const salt =globalSalt;
    const iv = globalIV;
    const masterKey = secretKey;
    const defaultIterations = 2000; // default from ruby
    const key = pbkdf2Sync(masterKey, salt, defaultIterations, 32, 'sha512');

    const decipher = createDecipheriv(this.algorithm, key, iv);
    decipher.setAuthTag(Buffer.from(passwordIv, 'utf-8'));

    const decrypted =
      decipher.update(encryptedPassword, 'base64', 'utf8') +
      decipher.final('utf-8');
    return decrypted;
  }

Я уже попробовал несколько подходов , но не могу правильно реализовать эту расшифровку. Что я пытаюсь понять

  1. Какой пароль хранится в БД? Это authTag или фактический iv? Если это iv, то должен ли я использовать этот IV для расшифровки или globalIV?
  2. Чего мне не хватает в функции расшифровки? В этот момент я получаю Unsupported state or unable to authenticate data, что, как я полагаю, означает, что iv / key / tag неверен?

Заранее спасибо за любую помощь!

РЕДАКТИРОВАТЬ: Проходил через код шифратора в рельсах, так что теперь я понимаю - password_iv это iv. Тег авторизации и "password_text" извлекаются из password :

   def extract_cipher_text(value)
      value[0..-17]
    end

    def extract_auth_tag(value)
      value[-16..-1]
    end

Итак, я попробовал следующее:

  decrypt(encryptedPassword: string, iv: string) {
    const salt = globalSalt;
    const masterKey = secretKey;
    const defaultIterations = 2000; // default from ruby
    const key = pbkdf2Sync(masterKey, salt, defaultIterations, 32, 'sha512');

    const decipher = createDecipheriv(this.algorithm, key, iv);
    const bData = Buffer.from(encryptedPassword, 'base64');
    const tag = bData.slice(-16);
    const text = bData.slice(0, -17);
    decipher.setAuthTag(tag);

    return Buffer.concat([decipher.update(text), decipher.final()]).toString(
      'utf-8',
    );
  }

Это, однако, все еще не удается с та же ошибка - Unsupported state or unable to authenticate data

РЕДАКТИРОВАТЬ 2: Хорошо, теперь у меня есть этот код:

decrypt(encryptedPassword: string, iv: string) {
    const salt = globalSalt;
    const masterKey = secretKey;
    const defaultIterations = 2000; // default from ruby
    const key = pbkdf2Sync(
       Buffer.from(masterKey, 'base64'),
       Buffer.from(salt, 'base64'),
       defaultIterations,
       32,
       'sha512',
     );
    const decipher = createDecipheriv(
      this.algorithm,
      Buffer.from(key, 'base64'),
      Buffer.from(iv, 'base64'),
    );
    const bData = Buffer.from(encryptedPassword, 'base64');
    const tag = bData.slice(bData.length - 16);
    const text = bData.slice(0, bData.length - 16);

    decipher.setAuthTag(tag);

    return Buffer.concat([decipher.update(text), decipher.final()]).toString();
  }

Этот код работает правильно, ТОЛЬКО если я жестко закодировал ключ из Rails. pbkdf2Sync in Nodejs и pbkdf2_hmac_sha1 в рельсах возвращают разные значения с, по-видимому, одинаковыми входными параметрами: think: Понятия не имею, что здесь происходит ... пока!

EDIT 3 Зверь побежден! Это рабочий код:

  decrypt(encryptedPassword: string, iv: string) {
    const salt = this.configService.get('ENCRYPT_SALT');
    const masterKey = this.configService.get('ENCRYPT_SECRET_KEY');
    const defaultIterations = 2000; // default from ruby
    const key = pbkdf2Sync(
      masterKey,
      Buffer.from(salt, 'base64'),
      defaultIterations,
      32,
      'sha1',
    );
    const decipher = createDecipheriv(
      this.algorithm,
      key,
      Buffer.from(iv, 'base64'),
    );
    const bData = Buffer.from(encryptedPassword, 'base64');
    const tag = bData.slice(bData.length - 16);
    const text = bData.slice(0, bData.length - 16);

    decipher.setAuthTag(tag);

    return Buffer.concat([decipher.update(text), decipher.final()]).toString();
  }

В одном конкретном случае я заметил слишком поздно, что ruby генерирует sha1 га sh для ключа вместо sha512 . Кроме того, не забудьте правильно декодировать salt / masterKey - в моем случае они были закодированы как base64

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...