У меня есть веб-приложение, написанное с использованием Grails 6.1.2. Мне нужно зашифровать пару полей в базе данных, поэтому я решил использовать Grails-jasypt, основанный на знаменитой библиотеке jasypt. Отлично работает.
Теперь мне нужно написать небольшое приложение на C#, и мне нужно получить доступ к БД, чтобы прочитать некоторые из этих зашифрованных полей. Конечно, я знаю свой пароль и алгоритм, используемый веб-приложением, из имеющихся у меня свойств:
jasypt {
algorithm = "PBEWITHSHA256AND256BITAES-CBC-BC"
providerName = "BC"
password = "my-strong-pwd"
keyObtentionIterations = 1000 }
К сожалению, плагин в Grails скрывает весь код, который использовался для шифрования строки. Я просто добавляю в домен это сопоставление, чтобы наверняка зашифровать и расшифровать то, что мне нужно:
static mapping = { dbPassword type: GormEncryptedStringType }
Я написал эту статическую функцию на C# для расшифровки строки, полученной из БД:
public static string Decrypt(string toDecrypt)
{
byte[] decoded = Convert.FromBase64String(toDecrypt);
if (decoded == null || decoded.Length <= 16)
{
throw new ArgumentException("Bad input data", "toDecrypt");
}
byte[] salt = new byte[16];
byte[] wrappedKey = new byte[decoded.Length - 16];
Array.Copy(decoded, 0, salt, 0, 16);
Array.Copy(decoded, 16, wrappedKey, 0, decoded.Length - 16);
int iterationCount = 1000;
string algName = "PBEWITHSHA256AND256BITAES-CBC-BC";
PbeParametersGenerator generator = new Pkcs5S2ParametersGenerator(new Org.BouncyCastle.Crypto.Digests.Sha256Digest());
generator.Init(PbeParametersGenerator.Pkcs5PasswordToBytes(key.ToCharArray()), salt, iterationCount);
ICipherParameters parameters = generator.GenerateDerivedParameters("AES", 256);
IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CBC/NoPadding");
cipher.Init(false, new ParametersWithIV(parameters, new byte[16])); // Assuming 16-byte IV
byte[] keyText = cipher.DoFinal(wrappedKey);
return Convert.ToBase64String(keyText);
}
Это работает, но строка не расшифрована правильно, я мало что знаю о BC, возможно, мне придется изменить строку GetCipher, но я не знаю, чем именно. Я пытаюсь добавить заполнение с помощью AES/CBC/PKCS5Padding, но у меня возникает «блок заполнения поврежден».
Хотелось бы, но использование плагина в Grails скрывает всю сложность, поэтому я его не выложил и не смог найти. Я просто сообщаю об этом в домене, чтобы установить зашифрованное статическое сопоставление поля = { тип dbPassword: GormEncryptedStringType }
Без кода портирование может быть затруднено. Можете ли вы хотя бы поделиться полными данными испытаний?
Я вижу @Topaco с полными тестовыми данными, вы имеете в виду пример данных? Я зашифровал эту строку Test1234$$, и результат: Xw4VoIGs7FtD71gVwrDlCweSK7S/Z8ikg39rTxdiOcg=, пароль — dfglhkgfhljktypoio34537567--,dfd435, спасибо!





Расшифровка с помощью PBEWITHSHA256AND256BITAES-CBC-BC реализована некорректно, работает следующая реализация:
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
...
// input data
string algorithm = "PBEWITHSHA256AND256BITAES-CBC-BC";
int iterations = 1000;
string password = "dfglhkgfhljktypoio34537567--,dfd435";
string encryptedDataB64 = "Xw4VoIGs7FtD71gVwrDlCweSK7S/Z8ikg39rTxdiOcg = ";
// separate salt and ciphertext
byte[] encryptedData = Convert.FromBase64String(encryptedDataB64);
byte[] salt = encryptedData[0..16];
byte[] ciphertext = encryptedData[16..];
// decrypt with PBEWITHSHA256AND256BITAES-CBC-BC
IBufferedCipher cipher = CipherUtilities.GetCipher(algorithm);
Asn1Encodable algParams = PbeUtilities.GenerateAlgorithmParameters(algorithm, salt, iterations);
ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters(algorithm, password.ToCharArray(), algParams);
cipher.Init(false, cipherParams);
byte[] decrypted = cipher.DoFinal(ciphertext);
// UTF-8 decode and output
Console.WriteLine(Encoding.UTF8.GetString(decrypted)); // Test1234$$
Редактировать:
Приведенная выше реализация использует идентификатор PBEWITHSHA256AND256BITAES-CBC-BC и не требует каких-либо дополнительных детальных знаний алгоритма.
Альтернативный (более низкоуровневый) способ, при котором алгоритм (AES/CBC/PKCS7Padding), получение ключа (PKCS#12) и такие параметры, как размер ключа и размер IV, должны быть явно указаны:
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Generators;
...
// apply PKCS#12 key derivation and decrypt with AES/CBC/PKCS7Padding
IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CBC/PKCS7Padding");
PbeParametersGenerator generator = new Pkcs12ParametersGenerator(new Sha256Digest());
generator.Init(PbeParametersGenerator.Pkcs12PasswordToBytes(password.ToCharArray()), salt, iterations);
ICipherParameters cipherParams = generator.GenerateDerivedParameters("AES", 256, 128);
cipher.Init(false, cipherParams);
byte[] decrypted = cipher.DoFinal(ciphertext);
Сравнение второго подхода с вашим кодом показывает, что во-первых вы использовали неправильную деривацию ключа и не был указан размер IV.
работает как шарм, спасибо!! Я попытаюсь выяснить, что не так с моей реализацией, сравнив вашу
@NiBE — я добавил альтернативный подход, который упрощает сравнение с вашим кодом и устранение неполадок.
Можете ли вы сгенерировать тестовые данные с непродуктивным паролем и опубликовать их? Кроме того, вы должны опубликовать код Grails (часть, касающуюся шифрования).