Я пытаюсь перенести приложение 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;
}
Я уже попробовал несколько подходов , но не могу правильно реализовать эту расшифровку. Что я пытаюсь понять
- Какой пароль хранится в БД? Это authTag или фактический iv? Если это iv, то должен ли я использовать этот IV для расшифровки или globalIV?
- Чего мне не хватает в функции расшифровки? В этот момент я получаю
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