Beispiel #1
0
def sync_token(token, secret, session=requests, timestamp=None):
    '''Sync the generated token. This will fail for a TOTP token if performed less than 2 periods after the last sync or check.'''
    secret_hex = binascii.b2a_hex(secret).decode('ascii')
    if timestamp is None:
        timestamp = int(time.time())
    if token.get('counter') is not None:  # HOTP
        # This reliably fails with -1, 0
        otp1 = hotp(secret_hex, counter=token['counter'])
        otp2 = hotp(secret_hex, counter=token['counter'] + 1)
    elif token.get('period'):  # TOTP
        otp1 = totp(secret_hex,
                    period=token['period'],
                    t=timestamp - token['period'])
        otp2 = totp(secret_hex, period=token['period'], t=timestamp)
    else:  # Assume TOTP with default period 30 (FIXME)
        otp1 = totp(secret_hex, t=timestamp - 30)
        otp2 = totp(secret_hex, t=timestamp)

    data = {'cr%s' % d: c for d, c in enumerate(otp1, 1)}
    data.update({'ncr%s' % d: c for d, c in enumerate(otp2, 1)})
    data['cred'] = token['id']
    data['continue'] = 'otp_sync'
    token_check = session.post(SYNC_URL, data=data)
    if "Your VIP Credential is successfully synced" in token_check.text:
        if token.get('counter') is not None:
            token['counter'] += 2
        return True
    elif "Your VIP credential needs to be sync" in token_check.text:
        return False
    else:
        return None
def check_token(token_id, secret):
    '''Check the validity of the generated token.'''
    if token_id.startswith('VSMB'):
        otp = hotp(binascii.b2a_hex(secret),1).encode('utf-8')
    else:
        otp = totp(binascii.b2a_hex(secret)).encode('utf-8')
    test_url = 'https://idprotect.vip.symantec.com/otpCheck'
    token_check = requests.post(
        test_url,
        data=dict(
            cred=token_id,
            cr1=otp[0],
            cr2=otp[1],
            cr3=otp[2],
            cr4=otp[3],
            cr5=otp[4],
            cr6=otp[5],
            cr7="",
            count="1",
            )
        )
    if token_check.status_code != 200:
        sys.stderr.write("Bad token check url, " + token_check.status_code + "\n")
        return True

    if "Your VIP Credential is working correctly" in token_check.text:
        return True
    else:
        sys.stderr.write("bad otp \"" + otp + "\" : " + token_check.text + "\n")
        return False
def check_token(token_id, secret, session=requests):
    '''Check the validity of the generated token.'''
    test_url = 'https://vip.symantec.com/otpCheck'
    if token_id.startswith('VSMB'):
        print('Checking HOTP token with Counter=1')
        otp = hotp(binascii.b2a_hex(secret), 1).decode('utf-8')
    else:
        print('Checking TOTP token with Current Time')
        otp = totp(binascii.b2a_hex(secret).decode('utf-8'))
    token_check = session.post(test_url,
                               data={
                                   'cr1': otp[0],
                                   'cr2': otp[1],
                                   'cr3': otp[2],
                                   'cr4': otp[3],
                                   'cr5': otp[4],
                                   'cr6': otp[5],
                                   'cred': token_id,
                                   'count': '1',
                                   'continue': 'otp_check'
                               })
    if "Your VIP Credential is working correctly" in token_check.text:
        return True
    elif "Your VIP credential needs to be sync" in token_check.text:
        return False
    else:
        return None
Beispiel #4
0
def get_hotp(raw_seed, counter, token_type=None):
    """
    Checks whether `auth_code` is a valid authentication code for `counter`
    based on the `raw_seed` (raw byte string representation of `seed`).
    """
    if not token_type:
        token_type = DEFAULT_TOKEN_TYPE
    return hotp(
        hexlify(raw_seed),
        counter,
        token_type,
    )
Beispiel #5
0
    def test_accept_hotp(self):
        tvector2 = [
            (0, '4c93cf18', '1284755224', '755224',),
            (1, '41397eea', '1094287082', '287082',),
            (2, '82fef30',  '137359152',  '359152',),
            (3, '66ef7655', '1726969429', '969429',),
            (4, '61c5938a', '1640338314', '338314',),
            (5, '33c083d4', '868254676',  '254676',),
            (6, '7256c032', '1918287922', '287922',),
            (7, '4e5b397',  '82162583',   '162583',),
            (8, '2823443f', '673399871',  '399871',),
            (9, '2679dc69',  '645520489', '520489',),]

        for counter, hexa, deci, trunc in tvector2:
            h = hotp(self.secret, counter, format='hex')
            d = hotp(self.secret, counter, format='dec')
            d6 = hotp(self.secret, counter, format='dec6')
            self.assertEqual(d, deci)
            self.assertEqual(h,  hexa)
            self.assertEqual(d6, trunc)
            self.assertTrue(accept_hotp(self.secret, trunc, counter))
Beispiel #6
0
def get_hotp(raw_seed, counter, token_type=None):
    """
    Checks whether `auth_code` is a valid authentication code for `counter`
    based on the `raw_seed` (raw byte string representation of `seed`).
    """
    if not token_type:
        token_type = DEFAULT_TOKEN_TYPE
    return hotp(
        hexlify(raw_seed),
        counter,
        token_type,
    )
Beispiel #7
0
 def on_message(self,message):
     try:
         data = json.loads(message)
     except json.JSONDecodeError as e:
         tornado.log.gen_log.info("error loading json data " + str(e))
         self.close(code=1003,reason=str(e))
     tornado.log.gen_log.info(" message " + str(data))
     sess = self.get_secure_cookie('sess')
     if 'type' not in data or data['type'] not in known_types or not sess:
         self.close(code=1003,reason='invalid message type')
     sess = sess.decode()
     res = {}
     if data['type'] == 'email':
         res['innermodal'] = "<div class='w3-input-group'><input id='content' class='w3-input' type='text' name='eotp' required><label class='w3-label w3-validate'>OTP</label></div><button onclick='submitcontent()' class='w3-btn w3-indigo w3-card-4'>Submit</button>"
         res['modalhead'] = "<h5>Enter OTP received in confirmation Email</h5>"
         res['type'] = "eotp"
         self.eotp = oath.hotp(sess,1)
         # TBD: send confirmation email with eotp
         tornado.log.gen_log.info('eotp ' + self.eotp)
         session = {'actual': data['email']}
         self.settings['redis'].set(sess,pickle.dumps(session))
         self.write_message(json.dumps(res))
         return
     elif data['type'] == "eotp":
         session = self.settings['redis'].get(sess)
         if not session or not hasattr(self,"eotp"):
             self.close(code=1003,reason='Invalid Session')
         session = pickle.loads(session)
         if self.eotp == data['eotp']:
             imgdata = yield self.settings['tpool'].submit(gen_data,self.eotp)
             res['innermodal'] = "<h5 class='w3-center'>SMS READDR " + self.eotp + "<br>to 9988776655</h5><div class='w3-container w3-hide-small w3-center'><h5>OR<br>Scan the below QRCODE</h5><img class='w3-image' style='max-height: 150px;' src='" + imgdata + "'/></div><h5 class='w3-center'>The page will auto-update as soon as we receive your SMS</h5>"
             res['modalhead'] = "<h5>Send SMS to Add Phone Number</h5>"
             res['type'] = "ssms"
             sockmap[self.eotp] = {'websock': self, 'sess': sess}
             self.write_message(json.dumps(res))
         else:
             self.close(code=1003,reason='Wrong OTP')
         return
     elif data['type'] == "addr":
         session = self.settings['redis'].get(sess)
         if not session:
             self.close(code=1003,reason='Invalid Session')
         session = pickle.loads(session)
         session['address'] = data['addr']
         session['mapped'] = session['mobile'] + '@readdess.io'
         yield self.settings['db'].users.save(session)
         self.settings['redis'].delete(sess)
         self.close(code=1000)
         return
Beispiel #8
0
    def test_hotp(self):
        tvector = [
            (0, 'cc93cf18508d94934c64b65d8ba7667fb7cde4b0'),
            (1, '75a48a19d4cbe100644e8ac1397eea747a2d33ab'),
            (2, '0bacb7fa082fef30782211938bc1c5e70416ff44'),
            (3, '66c28227d03a2d5529262ff016a1e6ef76557ece'),
            (4, 'a904c900a64b35909874b33e61c5938a8e15ed1c'),
            (5, 'a37e783d7b7233c083d4f62926c7a25f238d0316'),
            (6, 'bc9cd28561042c83f219324d3c607256c03272ae'),
            (7, 'a4fb960c0bc06e1eabb804e5b397cdc4b45596fa'),
            (8, '1b3c89f65e6c9e883012052823443f048b4332db'),
            (9, '1637409809a679dc698207310c8c7fc07290d9e5'), ]

        for counter, value in tvector:
            h = hotp(self.secret, counter, format='hex-notrunc')
            self.assertEqual(h, value.encode('ascii'))
Beispiel #9
0
    def test_hotp(self):
        tvector = [
            (0, 'cc93cf18508d94934c64b65d8ba7667fb7cde4b0'),
            (1, '75a48a19d4cbe100644e8ac1397eea747a2d33ab'),
            (2, '0bacb7fa082fef30782211938bc1c5e70416ff44'),
            (3, '66c28227d03a2d5529262ff016a1e6ef76557ece'),
            (4, 'a904c900a64b35909874b33e61c5938a8e15ed1c'),
            (5, 'a37e783d7b7233c083d4f62926c7a25f238d0316'),
            (6, 'bc9cd28561042c83f219324d3c607256c03272ae'),
            (7, 'a4fb960c0bc06e1eabb804e5b397cdc4b45596fa'),
            (8, '1b3c89f65e6c9e883012052823443f048b4332db'),
            (9, '1637409809a679dc698207310c8c7fc07290d9e5'),
        ]

        for counter, value in tvector:
            h = hotp(self.secret, counter, format='hex-notrunc')
            self.assertEqual(h, value)
Beispiel #10
0
def check_token(token, secret, session=requests):
    '''Check the validity of the generated token.'''
    secret_b32 = binascii.b2a_hex(secret).decode('ascii')
    if token.get('counter') is not None: # HOTP
        otp = hotp(secret_b32, counter=token['counter'])
    elif token.get('period'): # TOTP
        otp = totp(secret_b32, period=token['period'])
    else: # Assume TOTP with default period 30 (FIXME)
        otp = totp(secret_b32)
    data = {'cr%s'%d:c for d,c in enumerate(otp, 1)}
    data['cred'] = token['id']
    data['continue'] = 'otp_check'
    token_check = session.post(TEST_URL, data=data)
    if "Your VIP Credential is working correctly" in token_check.text:
        if token.get('counter') is not None:
            token['counter'] += 1
        return True
    elif "Your VIP credential needs to be sync" in token_check.text:
        return False
    else:
        return None
Beispiel #11
0
def totp(key, format='dec6', period=30, t=None, hash=hashlib.sha1):
    '''
       Compute a TOTP value as prescribed by OATH specifications.

       :param key:
           the TOTP key given as an hexadecimal string
       :param format:
           the output format, can be:
              - hex40, for a 40 characters hexadecimal format,
              - dec4, for a 4 characters decimal format,
              - dec6,
              - dec7, or
              - dec8
           it default to dec6.
       :param period:
           a positive integer giving the period between changes of the OTP
           value, as seconds, it defaults to 30.
       :param t:
           a positive integer giving the current time as seconds since EPOCH
           (1st January 1970 at 00:00 GMT), if None we use time.time(); it
           defaults to None;
       :param hash:
           the hash module (usually from the hashlib package) to use,
           it defaults to hashlib.sha1.

       :returns:
           a string representation of the OTP value (as instructed by the format parameter).
       :type: str
    '''
    if t is None:
        t = int(time.time())
    else:
        if isinstance(t, datetime.datetime):
            t = calendar.timegm(t.utctimetuple())
        else:
            t = int(t)
    T = int(t/period)
    return hotp(key, T, format=format, hash=hash)
Beispiel #12
0
db = conn.redrdb
tokens = set()
counter = 0

while len(tokens) < ((26**4)*0.9):
  token = newtempname()
  if token not in tokens:
    tokens.add(token)
    seed = random.randint(0,(10**6)*0.9)
    tdata = {'token': token, "tokenid": counter, "usecount": seed, 'seed': seed}
    db.tokens.insert(tdata)
    print(str(tdata))
    counter = counter + 1

key = uuid.uuid4().hex
pins = set()
attempts = 1
counter = 0
while len(pins) < ((10**6)*0.9):
    pin = oath.hotp(key,attempts)
    if pin not in pins:
        pins.add(pin)
        db.pins.insert({"pin": pin, "pinid": counter})
        print('added pin ' + pin + ' pinid ' + str(counter))
        counter = counter + 1
    attempts = attempts + 1

  
print('Done.')
Beispiel #13
0
 def test_dec8_regression_20130716(self):
     h = hotp("fb9cda921c82d893d9cdc6d6559997b1","132974666","dec8")
     assert len(h) == 8, 'wrong length %s' % h
     assert h == '03562487'
Beispiel #14
0
    def test_accept_hotp(self):
        tvector2 = [
            (
                0,
                '4c93cf18',
                '1284755224',
                '755224',
            ),
            (
                1,
                '41397eea',
                '1094287082',
                '287082',
            ),
            (
                2,
                '82fef30',
                '137359152',
                '359152',
            ),
            (
                3,
                '66ef7655',
                '1726969429',
                '969429',
            ),
            (
                4,
                '61c5938a',
                '1640338314',
                '338314',
            ),
            (
                5,
                '33c083d4',
                '868254676',
                '254676',
            ),
            (
                6,
                '7256c032',
                '1918287922',
                '287922',
            ),
            (
                7,
                '4e5b397',
                '82162583',
                '162583',
            ),
            (
                8,
                '2823443f',
                '673399871',
                '399871',
            ),
            (
                9,
                '2679dc69',
                '645520489',
                '520489',
            ),
        ]

        for counter, hexa, deci, trunc in tvector2:
            h = hotp(self.secret, counter, format='hex')
            d = hotp(self.secret, counter, format='dec')
            d6 = hotp(self.secret, counter, format='dec6')
            self.assertEqual(d, deci)
            self.assertEqual(h, hexa)
            self.assertEqual(d6, trunc)
            self.assertTrue(accept_hotp(self.secret, trunc, counter))
Beispiel #15
0
 def test_dec8_regression_20130716(self):
     h = hotp("fb9cda921c82d893d9cdc6d6559997b1", "132974666", "dec8")
     assert len(h) == 8, 'wrong length %s' % h
     assert h == '03562487'
Beispiel #16
0
def accept_hotp(key, response, counter, format='dec6', hash=hashlib.sha1,
        drift=3, backward_drift=0):
    '''
       Validate a HOTP value inside a window of
       [counter-backward_drift:counter+forward_drift]

       :param key:
           the shared secret
       :type key:
           hexadecimal string of even length
       :param response:
           the OTP to check
       :type response:
           ASCII string
       :param counter:
           value of the counter running inside an HOTP token, usually it is
           just the count of HOTP value accepted so far for a given shared
           secret; see the specifications of HOTP for more details;
       :param format:
           the output format, can be:
             - hex40, for a 40 characters hexadecimal format,
             - dec4, for a 4 characters decimal format,
             - dec6,
             - dec7, or
             - dec8
           it defaults to dec6.
       :param hash:
           the hash module (usually from the hashlib package) to use,
           it defaults to hashlib.sha1.
       :param drift:
           how far we can look forward from the current value of the counter
       :param backward_drift:
           how far we can look backward from the current counter value to
           match the response, default to zero as it is usually a bad idea to
           look backward as the counter is only advanced when a valid value is
           checked (and so the counter on the token side should have been
           incremented too)

       :returns:
           a pair of a boolean and an integer:
            - first is True if the response is validated and False otherwise,
            - second is the new value for the counter; it can be more than
              counter + 1 if the drift window was used; you must store it if
              the response was validated.

       >>> accept_hotp('343434', '122323', 2, format='dec6')
           (False, 2)

       >>> hotp('343434', 2, format='dec6')
           '791903'

       >>> accept_hotp('343434', '791903', 2, format='dec6')
           (True, 3)

       >>> hotp('343434', 3, format='dec6')
           '907279'

       >>> accept_hotp('343434', '907279', 2, format='dec6')
           (True, 4)
    '''

    for i in range(-backward_drift, drift+1):
        if hotp(key, counter+i, format=format, hash=hash) == str(response):
            return True, counter+i+1
    return False,counter