Skip to content

Instantly share code, notes, and snippets.

@danielfaust
Last active November 12, 2023 18:06
Show Gist options
  • Save danielfaust/b72f0f1f49c97f41228337444aafb27e to your computer and use it in GitHub Desktop.
Save danielfaust/b72f0f1f49c97f41228337444aafb27e to your computer and use it in GitHub Desktop.
Deprecated. Use this one instead https://gist.github.com/danielfaust/a9807b2f2256a49b18564daa8bc6cdf2 -- Original Text: This file contains the code to check a YubiKey OTP against YubiCloud's v2 protocol servers for Python 2.7. This code is not well tested, it is only meant for internal stuff like to prevent accidental execution of scripts which …
import sys
sys.dont_write_bytecode = True
import yubikey_otp_check_v2
users = {
'cccccabcdef1': 'user1',
'cccccabcdef2': 'user2',
}
client = { 'id': '0123456', 'secret': 'base64_encoded_secret' }
# client details obtained from https://upgrade.yubico.com/getapikey/
if len(sys.argv) != 2:
print 'pass otp as an argument'
else:
otp = sys.argv[1]
if users.has_key(otp[:12]):
yubikey = yubikey_otp_check_v2.YubiKeyOTPCheck(client['id'], client['secret'])
yubikey.check_otp(otp)
if yubikey.valid == True:
user = users[otp[:12]]
message = "ok-" + user
else:
message = "not-ok-1"
else:
message = "not-ok-2"
print message
# -*- coding: utf-8 -*-
# In response to the `[2018-12-10] YubiCloud changes` email
# Made for YubiCloud v2 & Python 2.7
# Code is based on https://bitbucket.org/nagylzs/yubistorm
import urllib, urllib2, urlparse
import copy, uuid, hmac, base64, hashlib, random
##################################################################
class YubiKeyOTPCheck():
#-------------------------------------------------------------------------
api_servers = [
"api.yubico.com",
"api2.yubico.com",
"api3.yubico.com",
"api4.yubico.com",
"api5.yubico.com",
]
#-------------------------------------------------------------------------
def __init__(self, client_id, client_secret):
self.status = 'INITIALIZED'
self.valid = False
self.client_id = client_id
self.client_secret = base64.b64decode(client_secret)
#-------------------------------------------------------------------------
def _create_signature(cls, params):
data = []
for key in sorted(params.keys()):
data.append("%s=%s" % (key, params[key]))
hashed = hmac.new(cls.client_secret, "&".join(data).encode("ascii"), hashlib.sha1)
return base64.b64encode(hashed.digest()).rstrip('\n').decode("ascii")
#-------------------------------------------------------------------------
def _verify_signature(cls, params):
if "h" not in params:
return False
bare = copy.copy(params)
del bare["h"]
good_signature = cls._create_signature(bare)
return good_signature == params["h"]
#-------------------------------------------------------------------------
def _add_query_params(cls, url, params):
url_parts = list(urlparse.urlparse(url))
query = dict(urlparse.parse_qsl(url_parts[4]))
query.update(params)
if "h" in query:
del query["h"]
query["h"] = cls._create_signature(query)
url_parts[4] = urllib.urlencode(query)
return urlparse.urlunparse(url_parts)
#-------------------------------------------------------------------------
def _fetch(cls, params):
code = 0
txt = None
try:
server_host = random.choice(cls.api_servers)
url = cls._add_query_params("https://" + server_host + "/wsapi/2.0/verify", params)
result = urllib2.urlopen(url)
code = result.getcode()
try: txt = result.read().decode("UTF-8")
except: pass
result.close()
except: pass
return code, txt
#-------------------------------------------------------------------------
def _check(cls, params):
code, txt = cls._fetch(params)
data = {}
if code == 200 and txt is not None:
try:
for item in txt.strip().split('\r\n'):
segments = item.split('=', 1)
data[segments[0]] = segments[1]
except: pass
else:
data['SERVER_CODE'] = code
return data
#-------------------------------------------------------------------------
def check_otp(self, otp):
self.valid = False
params = {
'id': self.client_id,
'nonce': uuid.uuid4().hex,
'timestamp': "1",
'otp': otp,
}
response = self._check(params)
if self._verify_signature(response):
self.status = response['status']
if self.status == 'OK':
self.valid = True
else:
self.status = 'RESPONSE_SIGNATURE_VERIFICATION_FAILED'
return response
#-------------------------------------------------------------------------
##################################################################
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment