#! /usr/bin/env python

# This file is part of IVRE.
# Copyright 2011 - 2014 Pierre LALET <pierre.lalet@cea.fr>
#
# IVRE is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# IVRE 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 General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License
# along with IVRE. If not, see <http://www.gnu.org/licenses/>.

"""This tool's output can be used with the tool fastgcd (available
here: https://factorable.net/resources.html) to efficiently perform
the attack described in the paper "Mining your Ps and Qs: Detection of
Widespread Weak Keys in Network Devices"
(https://factorable.net/paper.html). This option will really be faster
than the standalone tool attackkeys.

To do so, you need to strip the output from the information after the
moduli. A simple sed with 's# .*##' will do the trick.

"""

import ivre.keys
import ivre.db

if __name__ == '__main__':
    import sys
    import getopt
    # FIXME: this will not work if .nmap and .passive have different
    # backends
    flt = ivre.db.db.nmap.flt_empty
    bases = set()
    progress = None
    try:
        opts, args = getopt.getopt(sys.argv[1:],
                                   "p:f:",
                                   ['passive-ssl', 'active-ssl',
                                    'active-ssh',
                                    'filter='])
    except getopt.GetoptError, err:
        sys.stderr.write(str(err) + '\n')
        sys.exit(-1)
    for o, a in opts:
        if o in ['-f', '--filter']:
            # FIXME: this will not work if .nmap and .passive have
            # different backends
            flt = ivre.db.db.nmap.str2flt(a)
        elif o == '--passive-ssl':
            bases.add(ivre.keys.PassiveSSLRSAKey)
        elif o == '--active-ssl':
            bases.add(ivre.keys.SSLRSAKey)
        elif o == '--active-ssh':
            bases.add(ivre.keys.SSHRSAKey)
        elif o in ['-p', '--progress']:
            progress = int(a)
            if progress == 0:
                progress = 1
        else:
            sys.stderr.write(
                '%r %r not undestood (this is probably a bug).\n' % (o, a))
            sys.exit(-1)
    moduli = {}
    i = 0
    if not bases:
        bases = set([ivre.keys.PassiveSSLRSAKey,
                     ivre.keys.SSLRSAKey,
                     ivre.keys.SSHRSAKey])
    for a in bases:
        for k in a(cond=flt).get_keys():
            if 'modulus' in k:
                m = k['modulus']
                h = (ivre.utils.int2ip(k['host']), k['port'])
                # if 'subject' in k and 'issuer' in k:
                #    h = (k['subject'], k['issuer'])
                if m not in moduli:
                    moduli[m] = set([h])
                    i += 1
                    if progress is not None and i % progress == 0:
                        sys.stderr.write("Got %d moduli.\r" % i)
                elif h not in moduli[m]:
                    moduli[m].add(h)
    sys.stderr.write("Got %d moduli. Completed !\n" % i)
    for m in moduli:
        sys.stdout.write('%x %d %r\n' % (m, len(moduli[m]), moduli[m]))
