Skip to content

Instantly share code, notes, and snippets.

@gimiki
Last active April 10, 2020 17:11
Show Gist options
  • Save gimiki/377a58fa0400d21986163505daf293b5 to your computer and use it in GitHub Desktop.
Save gimiki/377a58fa0400d21986163505daf293b5 to your computer and use it in GitHub Desktop.
Example - Get a public key given the modulus and public exponent from an Identity Provider metadata service
import sys
import base64
from typing import Tuple, Dict, List
import json
import urllib.error
from urllib.request import urlopen
import ssl
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# pip install cryptodome
from Crypto.PublicKey import RSA
# Funzione che decodifica una stringa codificata in base64url
def base64urlDecode(encStr):
# Effettua il padding della stringa affinche' possa essere divisa in bytes e decodifcata
padding_factor = (4 - len(encStr) % 4) % 4
encStr += "=" * padding_factor
return base64.urlsafe_b64decode(encStr)
# Funzione per estrarre il modulo e l'esponente. La codifica e' Base64Url.
# I byte ottenuto vanno convertiti con notazione intero big endian senza segno
def keyComponentsExtractor(vDict: Dict, keyType='*') -> List:
retList = []
if 'keys' in vDict.keys():
logging.debug("Chiave keys trovata!")
for k in vDict['keys']:
logging.debug("Chiave: " + str(k))
if keyType == '*' or 'use' in k and k['use'] == keyType:
nInt = int.from_bytes(base64urlDecode(k['n']), byteorder='big', signed=False)
eInt = int.from_bytes(base64urlDecode(k['e']), byteorder='big', signed=False)
logging.debug("Modulo: " + str(nInt) + " Esponente: " + str(eInt))
retList.append((nInt, eInt))
return retList
# Creo il contesto ignorando eventuali certificati self-signed
sslContex = ssl.create_default_context()
sslContex.check_hostname = False
sslContex.verify_mode = ssl.CERT_NONE
# Chiamo il servizio ed estraggo il json
try:
response = urlopen("https://www.googleapis.com/oauth2/v3/certs", context=sslContex)
jsonResponse = json.load(response)
logging.debug("Risposta JSON: " + str(jsonResponse))
except urllib.error.URLError as e:
logging.error("" + str(e.reason))
sys.exit()
# Estraggo le componenti modulo e esponente dalle chiavi contenuti nella risposta JSON
# Se non viene specificato il tipo di chiave vengono restituite tutte le chiavi
# sig = signature key, enc = encryption key -> ref Oauth spec
componentsList = keyComponentsExtractor(jsonResponse, "sig")
if not componentsList:
logging.error("Lista delle componenti vuota!")
sys.exit()
logging.debug("Lista componenti chiavi estratti: " + str(componentsList))
# Creo i certificati pubblici e scrivo la chiave pubblica in un file
keyfile = open("publicKey.txt", "w")
for (n,e) in componentsList:
pKey = RSA.construct((n, e))
print(pKey.export_key().decode(), file=keyfile)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment