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 from Crypto.Util import number
24
25 from paramiko import util
26 from paramiko.ssh_exception import SSHException
27
28
30 "primtive attempt at prime generation"
31 hbyte_mask = pow(2, bits % 8) - 1
32 while True:
33
34 x = rng.read((bits+7) // 8)
35 if hbyte_mask > 0:
36 x = chr(ord(x[0]) & hbyte_mask) + x[1:]
37 n = util.inflate_long(x, 1)
38 n |= 1
39 n |= (1 << (bits - 1))
40 while not number.isPrime(n):
41 n += 2
42 if util.bit_length(n) == bits:
43 break
44 return n
45
47 "returns a random # from 0 to N-1"
48 bits = util.bit_length(n-1)
49 bytes = (bits + 7) // 8
50 hbyte_mask = pow(2, bits % 8) - 1
51
52
53
54
55
56
57
58 while True:
59 x = rng.read(bytes)
60 if hbyte_mask > 0:
61 x = chr(ord(x[0]) & hbyte_mask) + x[1:]
62 num = util.inflate_long(x, 1)
63 if num < n:
64 break
65 return num
66
67
69 """
70 convenience object for holding the contents of the /etc/ssh/moduli file,
71 on systems that have such a file.
72 """
73
75
76 self.pack = {}
77 self.discarded = []
78 self.rng = rpool
79
81 timestamp, mod_type, tests, tries, size, generator, modulus = line.split()
82 mod_type = int(mod_type)
83 tests = int(tests)
84 tries = int(tries)
85 size = int(size)
86 generator = int(generator)
87 modulus = long(modulus, 16)
88
89
90
91
92
93 if (mod_type < 2) or (tests < 4) or ((tests & 4) and (tests < 8) and (tries < 100)):
94 self.discarded.append((modulus, 'does not meet basic requirements'))
95 return
96 if generator == 0:
97 generator = 2
98
99
100
101
102 bl = util.bit_length(modulus)
103 if (bl != size) and (bl != size + 1):
104 self.discarded.append((modulus, 'incorrectly reported bit length %d' % size))
105 return
106 if bl not in self.pack:
107 self.pack[bl] = []
108 self.pack[bl].append((generator, modulus))
109
111 """
112 @raise IOError: passed from any file operations that fail.
113 """
114 self.pack = {}
115 f = open(filename, 'r')
116 for line in f:
117 line = line.strip()
118 if (len(line) == 0) or (line[0] == '#'):
119 continue
120 try:
121 self._parse_modulus(line)
122 except:
123 continue
124 f.close()
125
127 bitsizes = self.pack.keys()
128 bitsizes.sort()
129 if len(bitsizes) == 0:
130 raise SSHException('no moduli available')
131 good = -1
132
133 for b in bitsizes:
134 if (b >= prefer) and (b < max) and ((b < good) or (good == -1)):
135 good = b
136
137 if good == -1:
138 for b in bitsizes:
139 if (b >= min) and (b < max) and (b > good):
140 good = b
141 if good == -1:
142
143
144
145
146 good = bitsizes[0]
147 if min > good:
148 good = bitsizes[-1]
149
150 n = _roll_random(self.rng, len(self.pack[good]))
151 return self.pack[good][n]
152