Initial commit

This commit is contained in:
user
2026-07-12 14:06:45 +04:00
commit a75028d68f
148 changed files with 3275 additions and 0 deletions
+68
View File
@@ -0,0 +1,68 @@
from __future__ import annotations
from typing import Dict, Any
from modes.keygen import KeygenMode
from modes.encrypt import EncryptMode
from modes.decrypt import DecryptMode
class AutoMode:
"""
Автоматический режим:
1. Генерация ключей (p, q, n, e, d, phi).
2. Шифрование текста или числа.
3. Расшифрование результата обратно.
"""
def run(
self,
*,
text: str | None,
m: int | None,
p: int | None = None,
q: int | None = None,
min: int | None = None,
max: int | None = None,
bits: int | None = None,
seed: int | None = None,
) -> Dict[str, Any]:
# 1. Генерация ключей
keygen = KeygenMode()
keys = keygen.run(
p=p,
q=q,
min=min,
max=max,
bits=bits,
seed=seed,
)
n = keys["n"]["dec"]
e = keys["e"]["dec"]
d = keys["d"]["dec"]
# 2. Шифрование
encrypt = EncryptMode()
encrypted = encrypt.run(
text=text,
m=m,
n=n,
e=e,
)
# 3. Расшифрование
decrypt = DecryptMode()
# В зависимости от формата encrypted["output"]
if encrypted["mode"] == "text":
ciphers = [item["cipher"] for item in encrypted["output"]]
decrypted = decrypt.run(c=ciphers, n=n, d=d)
else:
cipher = encrypted["output"]["cipher"]
decrypted = decrypt.run(c=cipher, n=n, d=d)
return {
"keys": keys,
"encrypted": encrypted,
"decrypted": decrypted,
}
@@ -0,0 +1,55 @@
# modes/decrypt.py
from __future__ import annotations
from typing import Dict, Any, List
class DecryptMode:
def run(
self,
*,
c: int | List[int],
n: int,
d: int,
) -> Dict[str, Any]:
# Один блок
if isinstance(c, int):
plain = pow(c, d, n) # Дешифратор
char = chr(plain) if 0 <= plain < 128 else None
return {
"mode": "int",
"input": {
"cipher": c,
"hex_in": hex(c),
},
"output": {
"ascii": plain,
"char": char,
"hex_out": hex(plain),
},
}
# Несколько блоков (список чисел)
if isinstance(c, list):
result: List[Dict[str, Any]] = []
text = ""
for block in c:
plain = pow(block, d, n) # Дешифратор
char = chr(plain) if 0 <= plain < 128 else None
if char:
text += char
result.append({
"cipher": block,
"hex_in": hex(block),
"ascii": plain,
"char": char,
"hex_out": hex(plain),
})
return {
"mode": "list",
"input": c,
"output": result,
"text": text,
}
raise ValueError("c должен быть числом или списком чисел")
@@ -0,0 +1,57 @@
from __future__ import annotations
from typing import Dict, Any, List
from core.public_key import PublicKey
from core.prime_number import PrimeNumber
class EncryptMode:
def run(
self,
*,
text: str | None,
m: int | None,
n: int,
e: int,
) -> Dict[str, Any]:
pub = PublicKey(n=n, e=PrimeNumber(e))
if text is not None:
result: List[Dict[str, Any]] = []
for ch in text:
code = ord(ch)
cipher = pub.encrypt(code)
result.append({
"char": ch,
"ascii": code,
"hex_in": hex(code),
"cipher": cipher,
"hex_out": hex(cipher),
})
return {
"mode": "text",
"input": text,
"output": result,
}
if m is not None:
cipher = pub.encrypt(m)
char = chr(m) if 0 <= m < 128 else None
return {
"mode": "int",
"input": {
"char": char,
"ascii": m,
"hex_in": hex(m),
},
"output": {
"char": char,
"ascii": m,
"cipher": cipher,
"hex_out": hex(cipher),
},
}
raise ValueError("Необходимо указать либо text, либо m")
+133
View File
@@ -0,0 +1,133 @@
from __future__ import annotations
from typing import Dict, Any
from core.prime_number import PrimeNumber
from core.private_key import PrivateKey
class KeygenMode:
MAX_BITS: int = 2**5
MIN_VALUE: int = 2
MAX_VALUE: int = (1 << MAX_BITS) - 1
MAX_ATTEMPTS: int = 1000
def run(
self,
*,
p: int | None,
q: int | None,
min: int | None = None,
max: int | None = None,
bits: int | None = None,
seed: int | None = None,
) -> Dict[str, Any]:
if min is None:
min = self.MIN_VALUE
if max is None:
max = self.MAX_VALUE
self._validate_inputs(p, q, min, max, bits)
P = self._generate_prime(p, min, max, bits, seed)
Q = self._generate_distinct_prime(P, q, min, max, bits, seed)
priv = PrivateKey(P, Q)
pub = priv.make_public_key()
return {
"p": {
"dec": P.value,
"hex": hex(P.value),
},
"q": {
"dec": Q.value,
"hex": hex(Q.value),
},
"n": {
"dec": priv.n,
"hex": hex(priv.n),
},
"phi": {
"dec": priv.phi,
"hex": hex(priv.phi),
},
"e": {
"dec": pub.e.value,
"hex": hex(pub.e.value),
},
"d": {
"dec": priv.d,
"hex": hex(priv.d),
},
}
# ----------------- helpers -----------------
def _validate_inputs(
self,
p: int | None,
q: int | None,
min: int,
max: int,
bits: int | None,
) -> None:
if p is not None and q is not None and p == q:
raise ValueError("p и q должны быть разными простыми числами.")
if bits is not None and bits > self.MAX_BITS:
raise ValueError(f"Максимальная длина простого: {
self.MAX_BITS} бит.")
if min > max:
raise ValueError("min не может быть больше max.")
if max > self.MAX_VALUE:
raise ValueError(
f"max не может превышать {self.MAX_VALUE} (ограничение {
self.MAX_BITS} бит)."
)
if min == max:
raise ValueError("min и max не должны совпадать.")
def _generate_prime(
self,
value: int | None,
min: int,
max: int,
bits: int | None,
seed: int | None,
) -> PrimeNumber:
if value is not None:
return PrimeNumber.from_value(value)
if bits is not None:
return PrimeNumber.random_bits(bits=bits, seed=seed)
else:
return PrimeNumber.random(min_value=min, max_value=max, seed=seed)
return PrimeNumber.random_bits(bits=self.MAX_BITS, seed=seed)
def _generate_distinct_prime(
self,
other: PrimeNumber,
value: int | None,
min: int,
max: int,
bits: int | None,
seed: int | None,
) -> PrimeNumber:
attempts = 0
while True:
effective_seed = None if seed is None else seed + attempts
candidate = self._generate_prime(
value, min, max, bits, effective_seed)
if candidate.value != other.value:
return candidate
attempts += 1
if attempts >= self.MAX_ATTEMPTS:
raise RuntimeError(
f"Не удалось сгенерировать q, отличное от p, за {
self.MAX_ATTEMPTS} попыток."
)