Как хранить в приложении строку, которую можно читать, но невозможно изменить без пароля?

Приложение - обычная исполняемая программа, которую пользователь запускает на своём ПК. В ней нет базы данных, но есть данные, которые пользователь не должен иметь возможности менять. Скажем, в файле models есть объект JSON, который программа считывает при старте, и использует в дальнейшей работе. Поскольку JSON - это сырой текст, пользователь сможет открыть этот файл и что-нибудь в нём изменить. Задача состоит в том, чтобы это невозможно было сделать без пароля, но при этом программа всё равно должна иметь возможность прочитать и интерпретировать этот файл. Содержание файла должно быть непонятным для пользователя, но если он станет его исследовать и восстановит хранящийся там исходный текст, ничего страшного.

plain_text = 'plain text'
def encrypt_string(plain_text: str, password: str) -> str:
    """
    Принять новый текст для записи в файл и зашифровать его
    """
    ...

def decrypt_string(encrypted_text: str) -> str:
    """
    Расшифровать содержимое файла
    """
    ...

Напрашивается асимметричное шифрование. Текст шифруется закрытым ключом, расшифровывается открытым. Оба ключа хранятся в программе, но закрытый ключ зашифрован паролем. Пытаясь реализовать подобное, я столкнулся с проблемами:

  1. Классическая концепция алгоритма RSA подразумевает шифрование открытым ключом, расшифрование закрытым. Именно так оно реализовано в библиотеке cryptography, без возможности сделать иначе.

  2. Нет возможности поменять местами открытый и закрытый ключ, хотя математически это делать можно.

  3. Нет возможности сериализации закрытого ключа без пароля, например, чтобы реализовать симметричное шифрование паролем самостоятельно.

  4. Шифрование закрытым ключом и расшифрование открытым применяется при генерации подписи, однако невозможно создать подпись без хэширования. При выполнении обратной операции, можно лишь вызвать функцию проверки подписи, которая сравнит переданную строку с зашифрованным хэшем.

Правильно ли моё видение проблемы? Какие варианты решения вы можете предложить?


Ответы (1 шт):

Автор решения: Serge3leo

Как хранить в приложении строку, которую можно читать, но невозможно изменить без пароля?

Эту часть можно реализовать более менее честно:

  1. Обеспечиваем целостность приложения;
  2. В приложении есть открытый ключ;
  3. Проверяем подпись этой строки перед использованием;
  4. Предоставляем пользователю сервис подписи изменений по предъявлению пароля.

Скажем, п. 1 реализуем в экосистеме выбранной ОС подписанным приложением (python приложение, возможно придётся откомпилировать или включить подписанный python в подписанное приложение). П. 4 реализовать WEB сервисом или Телеграмм-ботом.

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

Так же п. 3, хотя и весьма широко применяется, но имеет нарекания, ввиду множества разнообразных способов повлиять на единственный оператор if.

...при этом программа всё равно должна иметь возможность прочитать и интерпретировать этот файл. Содержание файла должно быть непонятным для пользователя, но если он станет его исследовать и восстановит хранящийся там исходный текст, ничего страшного...

Это трудноформализуемое расплывчатое условие.

Простой вариант, подписываем ещё одну строку, хэш от результата подписи этой строки используем как ключ шифрования основной строки (типа, контролируемый "одноразовый" ключ). Т.е. в приложении дополнительные шаги:

2.1 Проверяем подпись дополнительной строки;

2.2 Из этой подписи получаем ключ расшифрования основной строки;

2.3 Расшифровываем основную строку и конкатенируем её с дополнительной строкой;

Далее тот самый пресловутый п. 3 и далее.

В принципе, ваша постановка задачи достаточно близка к постановкам задач тайных голосований, например, можно глянуть: https://ru.m.wikipedia.org/wiki/Протоколы_тайного_голосования . Другое дело, что не все эти протоколы хорошие, и не все хорошие можно реализовать средствами стандартных криптографических библиотек.

→ Ссылка