1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 """
20 Utility functions for dealing with primes.
21 """
22
23 import os
24
25 from paramiko import util
26 from paramiko.py3compat import byte_mask, long
27 from paramiko.ssh_exception import SSHException
28
29
31 """returns a random # from 0 to N-1"""
32 bits = util.bit_length(n - 1)
33 byte_count = (bits + 7) // 8
34 hbyte_mask = pow(2, bits % 8) - 1
35
36
37
38
39
40
41
42 while True:
43 x = os.urandom(byte_count)
44 if hbyte_mask > 0:
45 x = byte_mask(x[0], hbyte_mask) + x[1:]
46 num = util.inflate_long(x, 1)
47 if num < n:
48 break
49 return num
50
51
53 """
54 convenience object for holding the contents of the /etc/ssh/moduli file,
55 on systems that have such a file.
56 """
57
59
60 self.pack = {}
61 self.discarded = []
62
64 timestamp, mod_type, tests, tries, size, generator, modulus = line.split()
65 mod_type = int(mod_type)
66 tests = int(tests)
67 tries = int(tries)
68 size = int(size)
69 generator = int(generator)
70 modulus = long(modulus, 16)
71
72
73
74
75
76 if (mod_type < 2) or (tests < 4) or ((tests & 4) and (tests < 8) and (tries < 100)):
77 self.discarded.append((modulus, 'does not meet basic requirements'))
78 return
79 if generator == 0:
80 generator = 2
81
82
83
84
85 bl = util.bit_length(modulus)
86 if (bl != size) and (bl != size + 1):
87 self.discarded.append((modulus, 'incorrectly reported bit length %d' % size))
88 return
89 if bl not in self.pack:
90 self.pack[bl] = []
91 self.pack[bl].append((generator, modulus))
92
94 """
95 :raises IOError: passed from any file operations that fail.
96 """
97 self.pack = {}
98 with open(filename, 'r') as f:
99 for line in f:
100 line = line.strip()
101 if (len(line) == 0) or (line[0] == '#'):
102 continue
103 try:
104 self._parse_modulus(line)
105 except:
106 continue
107
109 bitsizes = sorted(self.pack.keys())
110 if len(bitsizes) == 0:
111 raise SSHException('no moduli available')
112 good = -1
113
114 for b in bitsizes:
115 if (b >= prefer) and (b < max) and (b < good or good == -1):
116 good = b
117
118 if good == -1:
119 for b in bitsizes:
120 if (b >= min) and (b < max) and (b > good):
121 good = b
122 if good == -1:
123
124
125
126
127 good = bitsizes[0]
128 if min > good:
129 good = bitsizes[-1]
130
131 n = _roll_random(len(self.pack[good]))
132 return self.pack[good][n]
133