134 lines
3.8 KiB
Python
134 lines
3.8 KiB
Python
|
|
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} попыток."
|
||
|
|
)
|