Operating Systems
Introduction
Dans le cadre de ce travail pratique nous étions amené à effectuer une prise en main de divers aspects cryptographiques d’une télécommunication définie dans le standard GSM à travers COMP128
Qu’est-ce qu’est COMP128 ?
COMP128 est une implémentation des algorithmes A3 et A8 définis dans le standard GSM. Du fait que le standard ne définit pas d’implémentation unique de ces algorithmes, la responsabilité de l’implémentation de ceux-ci est laissée aux opérateurs
”[…] The operation of these functions falls completely within the domain of an individual operator, and therefore, the functions are specified by each operator rather than being fully standardised. […] — RFC 4186 Section 12.1
A3 est utilisé pour l’authentification de la station mobile (MS), quant à A8, il est utilisé pour générer une clé de session qui sera utilisé pour chiffrer la communication.
Dérivation de la clé de session
Le principe de base du chiffrement des communications GSM est que la station mobile ainsi que l’opérateur ont déjà “négocié” au préalable un secret partagé. La clé de 16 bytes est présente dans la carte SIM de la station mobile ainsi que du côté du centre d’authentification de l’opérateur. Cette clé permettra en premier lieu d’authentifier la station mobile puis de dériver la clé de session pour le chiffrement des données.

La première étape de l’algorithme est l’envoie d’un nombre aléatoire de 16 bytes à la station mobile. En théorie, la combinaison de la clé avec le nombre aléatoire en entrée de l’algorithme A3 est censé produire une réponse signée (signed response SRES) de 4 bytes. La comparaison des valeurs obtenues du côté de la station mobile ainsi que du côte de la station de base (opérateur) permet dans le cas d’une valeur identique d’authentifier le client et de passer à l’étape suivante.
En second lieu, ainsi que SRES seront fournis à l’algorithme A8 afin de dériver une clé de session de 8 bytes.
Finalement, sera utilisé comme clé de chiffrement par l’algorithme A5 afin de protéger la communication entre la station mobile et la station de base.
Prise en main
Du fait que COMP128 n’est pas un algorithme public et d’autant plus que les implémentations de A3 et de A8 n’étaient pas standardisées, il est impossible de se baser sur une source fiable et véridique de ces algoritmes (d’autant plus que le lien fourni dans “l’énoncé” n’est pas fonctionnel).
Par conséquent voici les sources utilisées pour ce travail pratique :
-
- Exemple de rétro-ingénierie des algorithmes A3 et A8 constituant COMP128.
-
- Algorithme de chiffrement symétrique utilisé pour le chiffrement des données à la place d’A5 car son implémentation n’est pas disponible.
Envoi / Réception du nombre aléatoire
Le serveur s’occupe d’envoyer un nombre généré aléatoirement grâce à un générateur
sécurisé (cryptographiquement parlant). Pour faire ceci, nous utilisons la librairie
secrets.
rand = secrets.token_bytes(16)
print(
f"Sending random number ({rand.hex()})to client for authentication")
conn.send(rnd)
Du côté du client, après avoir établi une connexion TCP avec le serveur, nous attendons de recevoir de sa part le nombre généré aléatoirement qui représente le challenge pour la station mobile.
rand = s.recv(16)
print(f"Random number received from server = {rand.hex()}")
Calcul de SRES et
# Computing SRES and Kc
argv = ["./comp128_orig", args.key, "0x" + rand.hex()]
stdout = subprocess.run(
argv, capture_output=True).stdout.decode("ascii")
values = stdout.split(" ")
SRES, KC = "0x" + values[0], "0x" + values[1]
En ayant obtenu celui-ci, nous créeons un sous-processus écrit en C qui va
s’occuper de calculer SRES et à partir de notre secret partagé
et le nombre aléatoire.
Du côté du serveur, le procédé est identique car il nous est nécessaire d’aboutir à la même signature SRES afin d’authentifier le client ce que nous faisons avec le bout de code ci-dessous.
print(f"Client = {sres_client_str} Ours = {SRES}")
if sres_client.decode("ascii") != SRES:
print("Authentication has failed, terminating connection...")
conn.close()
os.exit(3)
print(f"{addr} you've been successfully authenticated!")
Chiffrement des données avec Blowfish
Après que le client est passé la phase d’authentification, il peut à présent envoyer ces données (sous la forme d’un fichier au serveur). Pour cette partie le choix d’algorithme était laissé libre, par conséquent nous avons choisi “Blowfish” qui est un algorithme de chiffrement symétrique par blocs développé par le fameux Bruce Schneier. Une des raisons pour lesquelles nous l’avons séléctionné est que cet algorithme est très flexible en terme de taille de clé ce qui nous est crucial afin d’émuler le comportement d’A5 qui fonctionne avec une clé de 8 bytes (64 bits).
Ci-dessous, voici l’extrait de code du côté du client qui s’occupe de chiffrer le contenu du fichier passé en argument au script.
cipher = blowfish.Cipher(str(args.key).encode())
with open(args.file, "rb") as file:
while True:
chunk = file.read(8)
if len(chunk) == 0:
break
elif len(chunk) % 8 != 0:
chunk += b' ' * (8 - len(chunk) % 8)
encrypted_chunk = cipher.encrypt_block(chunk)
s.send(encrypted_chunk)
Conclusion
Ce travail pratique nous a permis de prendre en main, la manière dont
fonctionnait le chiffrement des données lors d’une communication GSM ainsi que
d’émuler ce comportement à l’aide d’un modèle client-serveur écrit en python.