#! /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 is based on the paper "Mining your Ps and Qs: Detection
of Widespread Weak Keys in Network Devices"
(https://factorable.net/paper.html). It is *really* slow. You should
probably consider to use the tool getmoduli to extract the moduli from
the databases and then use the tool fastgcd (available here:
https://factorable.net/resources.html).

"""

import ivre.keys
import ivre.db
from Crypto.Util.number import GCD
import datetime
import sys


def check_keys(k, keys):
    """Checks whether the modulus of the new RSA key k has a one common
factor with one of the other keys.
"""
    res = False
    for kk in keys:
        g = GCD(k, kk)
        if g != 1 and g != k:
            print g, k, kk
            sys.stdout.flush()
            res = True
    if (len(keys) + 1) % 100 == 0:
        print "%d unique keys handled in %d seconds" % (
            len(keys) + 1,
            int(datetime.datetime.now().strftime('%s')) - starttime,
        )
        sys.stdout.flush()
    return res


def init():
    "Initialize global variables."
    global starttime
    starttime = int(datetime.datetime.now().strftime('%s'))


def test_keys():
    "Run the test with all the SSH and SSL keys we have in our database."
    keys = {}
    allkeys = [ivre.keys.SSHRSAKey(), ivre.keys.SSLRSAKey(),
               ivre.keys.PassiveSSLRSAKey()]
    for a in allkeys:
        for k in a.get_keys():
            if 'modulus' in k:
                kk = k['modulus']
                if kk in keys:
                    kkk = keys[kk]
                    if (k['host'], k['port']) not in kkk:
                        asnum = ivre.db.db.data.get(k['host'])
                        if asnum is not None and 'as_num' in asnum:
                            asnum = asnum['as_num']
                        else:
                            asnum = -1
                        kkk.add((asnum, k['host'], k['port']))
                        keys[kk] = kkk
                    continue
                if check_keys(kk, keys):
                    print k
                    sys.stdout.flush()
                keys[kk] = set([(k['host'], k['port'])])
            else:
                print "BUG ?", k
    print "%d unique keys handled in %d seconds" % (
        len(keys),
        int(datetime.datetime.now().strftime('%s')) - starttime,
    )
    for k in keys:
        if len(keys[k]) != 1:
            print hex(k), len(keys[k]), keys[k]

if __name__ == '__main__':
    init()
    test_keys()
