mirror of
https://gitlab.sectorq.eu/jaydee/omv_backup.git
synced 2025-07-03 00:23:06 +02:00
added v3
This commit is contained in:
148
venv/lib/python3.11/site-packages/paramiko/primes.py
Normal file
148
venv/lib/python3.11/site-packages/paramiko/primes.py
Normal file
@ -0,0 +1,148 @@
|
||||
# Copyright (C) 2003-2007 Robey Pointer <robeypointer@gmail.com>
|
||||
#
|
||||
# This file is part of paramiko.
|
||||
#
|
||||
# Paramiko is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
"""
|
||||
Utility functions for dealing with primes.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from paramiko import util
|
||||
from paramiko.common import byte_mask
|
||||
from paramiko.ssh_exception import SSHException
|
||||
|
||||
|
||||
def _roll_random(n):
|
||||
"""returns a random # from 0 to N-1"""
|
||||
bits = util.bit_length(n - 1)
|
||||
byte_count = (bits + 7) // 8
|
||||
hbyte_mask = pow(2, bits % 8) - 1
|
||||
|
||||
# so here's the plan:
|
||||
# we fetch as many random bits as we'd need to fit N-1, and if the
|
||||
# generated number is >= N, we try again. in the worst case (N-1 is a
|
||||
# power of 2), we have slightly better than 50% odds of getting one that
|
||||
# fits, so i can't guarantee that this loop will ever finish, but the odds
|
||||
# of it looping forever should be infinitesimal.
|
||||
while True:
|
||||
x = os.urandom(byte_count)
|
||||
if hbyte_mask > 0:
|
||||
x = byte_mask(x[0], hbyte_mask) + x[1:]
|
||||
num = util.inflate_long(x, 1)
|
||||
if num < n:
|
||||
break
|
||||
return num
|
||||
|
||||
|
||||
class ModulusPack:
|
||||
"""
|
||||
convenience object for holding the contents of the /etc/ssh/moduli file,
|
||||
on systems that have such a file.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# pack is a hash of: bits -> [ (generator, modulus) ... ]
|
||||
self.pack = {}
|
||||
self.discarded = []
|
||||
|
||||
def _parse_modulus(self, line):
|
||||
(
|
||||
timestamp,
|
||||
mod_type,
|
||||
tests,
|
||||
tries,
|
||||
size,
|
||||
generator,
|
||||
modulus,
|
||||
) = line.split()
|
||||
mod_type = int(mod_type)
|
||||
tests = int(tests)
|
||||
tries = int(tries)
|
||||
size = int(size)
|
||||
generator = int(generator)
|
||||
modulus = int(modulus, 16)
|
||||
|
||||
# weed out primes that aren't at least:
|
||||
# type 2 (meets basic structural requirements)
|
||||
# test 4 (more than just a small-prime sieve)
|
||||
# tries < 100 if test & 4 (at least 100 tries of miller-rabin)
|
||||
if (
|
||||
mod_type < 2
|
||||
or tests < 4
|
||||
or (tests & 4 and tests < 8 and tries < 100)
|
||||
):
|
||||
self.discarded.append(
|
||||
(modulus, "does not meet basic requirements")
|
||||
)
|
||||
return
|
||||
if generator == 0:
|
||||
generator = 2
|
||||
|
||||
# there's a bug in the ssh "moduli" file (yeah, i know: shock! dismay!
|
||||
# call cnn!) where it understates the bit lengths of these primes by 1.
|
||||
# this is okay.
|
||||
bl = util.bit_length(modulus)
|
||||
if (bl != size) and (bl != size + 1):
|
||||
self.discarded.append(
|
||||
(modulus, "incorrectly reported bit length {}".format(size))
|
||||
)
|
||||
return
|
||||
if bl not in self.pack:
|
||||
self.pack[bl] = []
|
||||
self.pack[bl].append((generator, modulus))
|
||||
|
||||
def read_file(self, filename):
|
||||
"""
|
||||
:raises IOError: passed from any file operations that fail.
|
||||
"""
|
||||
self.pack = {}
|
||||
with open(filename, "r") as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if (len(line) == 0) or (line[0] == "#"):
|
||||
continue
|
||||
try:
|
||||
self._parse_modulus(line)
|
||||
except:
|
||||
continue
|
||||
|
||||
def get_modulus(self, min, prefer, max):
|
||||
bitsizes = sorted(self.pack.keys())
|
||||
if len(bitsizes) == 0:
|
||||
raise SSHException("no moduli available")
|
||||
good = -1
|
||||
# find nearest bitsize >= preferred
|
||||
for b in bitsizes:
|
||||
if (b >= prefer) and (b <= max) and (b < good or good == -1):
|
||||
good = b
|
||||
# if that failed, find greatest bitsize >= min
|
||||
if good == -1:
|
||||
for b in bitsizes:
|
||||
if (b >= min) and (b <= max) and (b > good):
|
||||
good = b
|
||||
if good == -1:
|
||||
# their entire (min, max) range has no intersection with our range.
|
||||
# if their range is below ours, pick the smallest. otherwise pick
|
||||
# the largest. it'll be out of their range requirement either way,
|
||||
# but we'll be sending them the closest one we have.
|
||||
good = bitsizes[0]
|
||||
if min > good:
|
||||
good = bitsizes[-1]
|
||||
# now pick a random modulus of this bitsize
|
||||
n = _roll_random(len(self.pack[good]))
|
||||
return self.pack[good][n]
|
Reference in New Issue
Block a user