RSA Cipher

RSA n°10 | Oracle tell me the True

Introduction : Généralement, dans un contexte de CTF , il est possible de tomber sur un oracle de déchiffrement RSA , on nous donne accès : à un oracle permettant de déchiffrer des messages sauf le flag chiffré le flag chiffré Voici donc plusieurs méthodes pour trouver le flag en clair : Méthode 1: La première méthode est de Factoriser le message $c$ . On peut ainsi demander de déchiffrer les facteurs du flag puis remultiplier les clairs entre eux pour récupérer le message original:

RSA n°9 | Breaking Signature Shema

Introduction : Le chiffrement RSA permet l’utilisation d’un système de signature des messages lors de la transmission de ceux-ci. Ainsi, un message chiffré peut être accompagné de sa signature qui atteste de son intégrité au prêt du serveur. Voici un message chiffré & signé : $<s,c>$ Fonctionnement global. Le chiffrement RSA se compose : un exposant de chiffrement une clé publique une clé privée On va réutiliser les propriétés arithmétiques du chiffrement pour inventer la signature noté $s$ .

RSA n°8 | CopperSmith saves you

Introduction : Don Coppersmith est un mathématicien et cryptologue américain né en 1950. Il a contribué dans de nombreux domaines de la Cryptographie et en particulier le chiffrement RSA. Il s’intéresse particulièrement aux liens possibles entre des notions d’algèbres et les mathématiques arithmétiques du chiffrement RSA Papier de recherche: CopperSmith présente un papier de recherche mathématique nommé : <em>Finding Small Solutions to Small Degree Polynomials</em> Il y explique comment trouver les racines de polynômes à 1 et 2 variables , modulo un entier n grâce à la réduction de Base via des matrices et l’algorithme Lenstra–Lenstra–Lovász (LLL).

RSA n°7 | Hey this is Franklin (Reiter)

Introduction L’attaque Franklin-Reiter sur le chiffrement RSA requiert d’avoir deux messages chiffrés avec une différence connu entre les deux messages Contextualisation Exemple : $m_1 = 100000000000$ $m_2 = 100000000999$ Ici , si la différence $m_2-m_1 = 999$ est connu , alors il est possible de retrouver le message à partir de : $c_1 = m_1^e \pmod n$ $c_2 = m_2^e \pmod n$ A l’origine, cet attaque était faisable pour $e=3$ puis elle a était généralisé pour n’importe quel $e$ .

RSA n°6 | Message for all

Introduction Il est courant d’envoyer le même message à plusieurs personnes et cela pose un gros problème de sécurité pour l’intégrité du message si une personne arrive à intercepter plusieurs communications. Nous allons ici parler de l’attaque Hastads-Broadcast. Contextualisation On sait qu’un message chiffré par RSA est de la forme : $c = m^e \pmod n$ Nous avions vu ici que si $m$ était petit, on pouvait déchiffrer le message en appliquant une racine $3^{ième}$ au texte chiffré.

RSA n°5 | E takes confidence

Introduction Nous allons ici voir 2 vulnérabilités sur RSA liés à un mauvais choix de l’exposant $e$. Contextualisation On sait que $d$ , clé privée du chiffrement RSA est généré de la sorte: $d = e^{-1} \pmod \Phi(n)$ Par convention, on utilise souvent $e=3$ ou $e=65537$ . Mais pourquoi ? Ces nombres présentes plusieurs propriétés intéressante, d’abord : ils sont premiers ils sont petits C’est $2$ premières propriétés sont majeures , elles permettent un temps de calcul raisonnable pour le chiffrement/déchiffrement des messages .

RSA n°4 | Fermat is Watching U

Introduction Nous allons ici voir 2 vulnérabilités sur RSA liés à une mauvaise génération de clé publique. Vulnérabilité : On rappelle que $n$ et généré avec $p$ et $q$ très grand : $n = p*q$ . On se place dans un cas idéal ou $p$ et $q$ cryptographiques et que donc $n$ n’est pas cassable par force brute . La vulnérabilités réside dans le fait que $p$ et $q$ sont très proche.

RSA n°3 | Module/Premier commun

Introduction Nous allons ici voir 2 vulnérabilités sur RSA liés à une mauvaise gestion des clés publiques . Common Modulus . On suppose le schéma suivant : On dispose de 2 chiffrés différent à partir d’un même message et d’une clé commune (n): $c_1 = e_1^{-1} \pmod {\Phi(n)}$ $c_2 = e_2^{-1} \pmod {\Phi(n)}$ Alors si on a les égalité suivantes, alors on peut décoder le message $c_1$ ( = $c_2$):

RSA n°2 | Premières attaques

Introduction Nous avons vu précédemment (ici) que le chiffrement RSA reposé sur 2 nombres premiers , notés $p$ et $q$. Grâce à ces deux nombres cryptographiquement grands, il était ainsi possible de générer une paires de clé $(publique/privée)$ et chiffré des messages grâce à celle-ci. Nous allons voir ici quelques premières vulnérabilités sur le chiffrement RSA. 1) $P$ et $Q$ trop petit. On rappèle que la clé privée est :

RSA n°1 | Principes Fondamentals

Introduction Le chiffrement RSA est utilisé pour chiffrer des communications, il est aujourd’hui souvent utilisé pour les certificats SSL sur internet ou encore les clés de connections via le protocole ssh. Il est dit asymétrique car il fonctionne par paires de clés. Toute la sécurité de ce chiffrement repose sur le fait qu’il est aujourd’hui infiniment long de factoriser un nombre cryptographique rapidement . Ronald Rivest, Adi Shamir et Leonard Adleman ont ainsi crée un chiffrement basé sur l’arithmétique modulaire, encore d’actualité aujourd’hui.

RSA n°0 | Bases Mathématiques

Introduction Voici les différents théorèmes est application pour comprendre le chiffrement RSA Opération Modulaires L’opérateur modulo et une opération qui retourne le reste de la division euclidienne d’un nombre A par B: $a \equiv r \pmod b$ $\Rightarrow~\exists~k \in N~|~a = b*k + r$ Si r = 0 , on dit que n divise a Pgcd Le PGCD (ou gcd) de 2 nombres est le plus grand diviseur commun à ces deux nombres :

RSA n°9 | Breaking Signature Shema

Planted December 9, 2022


Introduction :

Le chiffrement RSA permet l’utilisation d’un système de signature des messages lors de la transmission de ceux-ci.
Ainsi, un message chiffré peut être accompagné de sa signature qui atteste de son intégrité au prêt du serveur.
Voici un message chiffré & signé :

  • $<s,c>$

Fonctionnement global.

Le chiffrement RSA se compose :

  • un exposant de chiffrement
  • une clé publique
  • une clé privée

On va réutiliser les propriétés arithmétiques du chiffrement pour inventer la signature noté $s$ .

Création de la signature :

Soit $m$ un message clair et $hash$ une fonction de hash classique (sha256,md5):

  • On calcul $h = hash(m)$
  • On a : $s = h^d \pmod n$

Vérification de la signature :

  • On déchiffre le message $c$ comme un RSA classique
  • On calcul $h = hash(m)$
  • On déchiffre $h’ = s^e \pmod n$
  • On compare $h$ et $h’$.

Relation mathématique :

$h’ = s^e \pmod n = (h^d)^e \pmod n = h$

Première attaque : Choosen Message

On va supposer avoir a disposition un Oracle de signature qui nous permet de signé n’importe quel message .

On souhaite obtenir la signature :

  • $s = m^d \pmod n$

Alors, grâce à deux autres signatures, on peut obtenir $s$.

Etapes :
  • On signe un message connu $m_1$:
    $s_1 = m_1^d \mod n$

  • On signe un second message $m_2$ tel que :
    $\begin{cases} m_2 = m * m_1^{-1} \pmod n \newline s_2 = m_2^d \mod n \end{cases}$

  • Alors on peut récupérer la signature de $m$ , noté $s$:
    $s = s_1 *s_2 \pmod n$

Relation mathématique :

$s \equiv s_1*s_2 \equiv m_1^d*m_2^d\equiv m_1^d*(m * m_1^{-1})^d \equiv m_1^d*m^d * m_1^{-d} \equiv m^d \pmod n$

Source:Chosen-Message-Attack RSA-Signature

Seconde Attaque : Fault attack

Pour calculer des signatures, on utilise souvent le Théorème des restes chinois.

Ainsi, pour calculer $s = hash(m)^d \pmod n$.
On calcul :

  • $\begin{cases} d_p = d\pmod{p-1}\newline d_q = d\pmod{q-1}\newline S_p = m^{d_p} \pmod p \newline S_q = m^{d_q} \pmod q \end{cases}$

En utilisant le Théorème, on obtient $s$ grâce à $S_p$ et $S_q$

Injection de Faute:

Si on arrive a injecter une faute en faisant baisser la tension d’un processeur, on peut rendre un des calculs de $S_p$ ou $S_q$ faux.

On a donc :

$\begin{cases} S_p = m^{d_p} \pmod p \newline S_q \neq m^{d_q} \pmod q \end{cases}$

$\implies S = crt([S_p,S_q],n)$

$\implies \begin{cases} S^e = m \pmod p \newline S^e \neq m \pmod q \end{cases}$

$\implies \begin{cases} S^e - m = 0 \pmod p \newline S^e -m \neq 0 \pmod q \end{cases}$

$\implies \begin{cases} p~\mid~S^e - m \newline q~\nmid~S^e - m \pmod q \end{cases}$

On peut ainsi retrouver un des 2 facteurs de la clé publique de la manière suivante :

  • $q = gcd(S^e-m,n)$

Implémentation en python

from Crypto.Util.number import *
from hashlib import sha256

def gen():
	e,p,q = (0x10001,getPrime(256),getPrime(256))
	n = p*q
	d = inverse(e,(p-1)*(q-1))
	return e,p,q,n,d

def sign(m,e,n,p,q,d):
	dp,dq = (d % (p-1),
			 d % (q-1))
	sp,sq = (pow(m,dp,p),
			 pow(m,dq,q))

	# Fault
	sq = sq+1

	h = ((sp-sq) * pow(q,-1,p)) % p
	return sq + q*h

def attack_sig(m,e,n,s):
	return GCD(s**e - m,n)


e,p,q,n,d = gen()
hash  = bytes_to_long(sha256(b'Hello From Vozec').digest())
sig   = sign(hash,e,n,p,q,d)

q = attack_sig(hash,e,n,sig)
p = n//q
#...

Source:Fault Attacks on RSA Signatures with Partially Unknown Messages⋆

Troisième Attaque : Signature Forgery

Le Standart PKCS#1 v1.5

PKCS est un standart de formatage du chiffrement RSA.
Il permet de formatter un message avec de le signer.

Il fonctionne de la manière suivante :
- 0x00 0x01 || pad() || 0x00 || ASN.1 || hash(M)

Avec :
- 0x00 0x01: Deux bytes qui annoncent le début du message
- pad(): Du padding de 0xff.
- 0x00: Un byte qui annonce la fin du padding.
- ASN.1: byte identifiant le hash
- hash(M): Le message hashé

Vulnérabilité sur la fonction de Vérification :

Avant de vérifier la signature , les serveurs vérifient souvent la forme du message reçu: 0x00 0x01 || 0xff 0xff ... || 0x00 || ASN.1 || hash(M)

Or , certain serveur ne regarde pas le contenue du padding. Ainsi , dans le cas ou $e=3$ , il est possible d’envoyer un message valide de la forme:

  • 0x00 0x01 || 0xff || 0x00 || ASN.1 || hash(M) || Garbage

Le module $n$ n’est pas appliqué car le message est inférieur à n.
Alors , si il n’y a pas de vérification du contenue du padding de 0xFF , alors il est possible de placer des bytes voulu entre 0x00 0x01 et 0x00

On peut brute-forcer 254 qui permette la création d’une signature tel que celle ci mise à la puissance $e=3$ , elle soit valide et commence par 0x00 || ASN.1 || hash(M)

  • $(254 = \dfrac{2048}{2} - 2)$ ( “-2” pour les 0x00 0x11)
import hashlib
from os import urandom
from gmpy2 import mpz, iroot

set_bit   = lambda n,b,x: ~(1 << b) & n if x == 0 else  (1 << b) | n
to_bytes  = lambda n: n.to_bytes((n.bit_length() // 8) + 1, byteorder='big')
from_bytes= lambda b: int.from_bytes(b, byteorder='big')
get_bit   = lambda n,b: ((1 << b) & n) >> b
cube_root = lambda n: int(iroot(mpz(n), 3)[0])

message = b"Ciao, mamma!!"

# Suffix
hash_msg    = hashlib.sha256(message).digest()
asn1_sha256 = b'\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20'
suffix      = b'\x00' + asn1_sha256 + hash_msg

sig_suffix = 1
for b in range(len(suffix)*8):
    if get_bit(sig_suffix ** 3, b) != get_bit(from_bytes(suffix), b):
        sig_suffix = set_bit(sig_suffix, b, 1)

while True:
    sig = (
        to_bytes(cube_root(
                from_bytes(b'\x00\x01' + urandom(2048//8 - 2)
                ))
    )[:-len(suffix)] \
        + b'\x00' * len(suffix))[:-len(suffix)] \
        + to_bytes(sig_suffix)

    if b'\x00' not in to_bytes(from_bytes(sig) ** 3)[:-len(suffix)]:
        break

assert to_bytes(from_bytes(sig) ** 3).endswith(suffix)
assert to_bytes(from_bytes(sig) ** 3).startswith(b'\x01')
assert len(to_bytes(from_bytes(sig) ** 3)) == 2048//8 - 1
assert b'\x00' not in to_bytes(from_bytes(sig) ** 3)[:-len(suffix)]

print(sig)

Code repris de la ressource ci dessous

Source: BLEICHENBACHER'06 SIGNATURE FORGERY IN PYTHON-RSA

Quatrième Attaque : Padding attacks

Un jour … Car c’est long à expliquer x)
Bleichenbacher Attack