Внедряем бэкдор в RSA ключ
Здарова и с внеплановой пятницей!
Сегодня я покажу тебе как захуячить бэкдор в RSA ключ.
С чего все началось. Да блядь хуль мусолить, даж в официальных алгоритмах возможны бэкдоры.
Короче был такой алгоритм Dual_EC_DRBG стандартизованный национальным институтом стандартов и технологий пиндостана (NIST).
Прошу отметить, что предоставленная здесь информация предназначена исключительно для образовательных и информационных целей. Я не призываю и не одобряю незаконные действия, и использование этой информации для незаконных целей запрещено. Читатели должны соблюдать законы своей страны и использовать свои навыки с уважением к этическим нормам и законам.
Алгоритм использует эллиптические кривые, и изначально был принят как безопасный криптографический генератор случайных чисел. Однако... что-то пошло по пизде.
В 2007 году, любители покопаться в кишочках обнаружили в нем бэкдор.
Теоретически, если ты знаешь определённые параметры (точку
Q
, связанную с другой точкойP
), можно предсказать выход генератора — то есть знать, какие случайные числа он генерирует.
Получается не такой уж и случайный генератор чисел. За всем, как обычно, стояли хитрожопые АНБ с целью наебать всех. А дальше вылез Сноуден и всё это заапрувил. Вот это нихуясе!
А RSA Security использовало Dual_EC_DRBG по умолчанию. Причем АНБ забашляло 10кк баксов этой самой RSA Security за такую закладочку.
По итогу:
- NIST отозвал рекомендацию по Dual_EC_DRBG
- RSA все прокляли и доверие к ним пропало
Ну дак вот. Как бы тебе не ссали в уши — никому не верь!
Таких историй было несколько, но не суть.
Если интересно можешь загуглить сам. Там чет еще про роутеры помню было, где можно было восстановить приватный ключ из публичного и расшифровывать траффик. Чето про тайваньские чипы в 2013 году. Похуй!
Внедряем бэкдор в RSA
Но вы тут не байки пришли слушать, а позырить как это на практике провернуть. Поехали.
Ниже я накидал код на python:
import hashlib
from Crypto.Util import number
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.backends import default_backend
import base64
# Хешируем строку в SHA256, интерпретируем как BigInteger
def hash_to_bigint(data: str) -> int:
if not isinstance(data, str):
raise ValueError("data must be a string")
hash_hex = hashlib.sha256(data.encode()).hexdigest()
return int('1' + hash_hex, 16)
# Следующее простое
def next_prime(n: int) -> int:
if n % 2 == 0:
n += 1
while not number.isPrime(n):
n += 2
return n
# Генерация RSA ключей с "бэкдором"
def generate_backdoored_key(secret: str):
# Увеличиваем размер числа перед поиском простого
p = next_prime(hash_to_bigint(secret + 'A') << 1024)
q = next_prime(hash_to_bigint(secret + 'B') << 1024)
n = p * q
phi = (p - 1) * (q - 1)
e = 65537
d = pow(e, -1, phi)
private_numbers = rsa.RSAPrivateNumbers(
p=p,
q=q,
d=d,
dmp1=d % (p - 1),
dmq1=d % (q - 1),
iqmp=pow(q, -1, p),
public_numbers=rsa.RSAPublicNumbers(e=e, n=n)
)
private_key = private_numbers.private_key(backend=default_backend())
public_key = private_key.public_key()
pem_private = private_key.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.TraditionalOpenSSL,
serialization.NoEncryption()
)
pem_public = public_key.public_bytes(
serialization.Encoding.PEM,
serialization.PublicFormat.SubjectPublicKeyInfo
)
return pem_public.decode(), pem_private.decode()
# Восстановление приватного ключа по секрету и открытому ключу
def restore_private_key(secret: str, pem_public: str):
public_key = serialization.load_pem_public_key(
pem_public.encode(), backend=default_backend()
)
numbers = public_key.public_numbers()
n = numbers.n
e = numbers.e
p = next_prime(hash_to_bigint(secret + 'A') << 1024)
q = next_prime(hash_to_bigint(secret + 'B') << 1024)
phi = (p - 1) * (q - 1)
d = pow(e, -1, phi)
private_numbers = rsa.RSAPrivateNumbers(
p=p,
q=q,
d=d,
dmp1=d % (p - 1),
dmq1=d % (q - 1),
iqmp=pow(q, -1, p),
public_numbers=rsa.RSAPublicNumbers(e=e, n=n)
)
private_key = private_numbers.private_key(backend=default_backend())
return private_key.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.TraditionalOpenSSL,
serialization.NoEncryption()
).decode()
# Демонстрация
secret = 'my-bashdays-secret'
pem_public, pem_private = generate_backdoored_key(secret)
print('--- PUBLIC KEY PEM ---')
print(pem_public)
# Шифрование
message = b'Hello, Bashdays world!'
public_key = serialization.load_pem_public_key(pem_public.encode(), backend=default_backend())
ciphertext = public_key.encrypt(
message,
padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None)
)
cipher_b64 = base64.b64encode(ciphertext).decode()
print('Encrypted (base64):', cipher_b64)
# Восстановление приватного ключа
pem_restored_private = restore_private_key(secret, pem_public)
print('--- RESTORED PRIVATE KEY PEM ---')
print(pem_restored_private)
# Расшифровка
private_key = serialization.load_pem_private_key(pem_restored_private.encode(), password=None, backend=default_backend())
decrypted = private_key.decrypt(
base64.b64decode(cipher_b64),
padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None)
)
print('Decrypted message:', decrypted.decode())
Если его запустить, он наглядно продемонстрирует всю подноготную.
Что делает этот скрипт
- Создаёт RSA-ключи, которые можно восстановить из секрета (это и есть бэкдор).
- Шифрует сообщение открытым ключом.
- Восстанавливает закрытый ключ без сохранения — только из секрета и публичного ключа.
- Расшифровывает сообщение этим восстановленным ключом.
Почему можно восстановить закрытый ключ, если знаешь секрет:
Если ты можешь восстановить те же p
и q
, то:
- Ты можешь пересчитать
n = p * q
— он должен совпасть сn
в публичном ключе. - Посчитать
φ(n) = (p - 1)(q - 1)
- Получить
e
из публичного ключа (он в нём явно хранится) - Вычислить
d = e⁻¹ mod φ(n)
- Собрать весь приватный ключ
Смысл бэкдора
Секрет — это не просто строка, это способ воспроизводимо получить p
и q
. Ты как будто заранее знаешь, из чего они были сгенерированы.
Вот и вся наука! Изучай!