Analyse Spectrale, Stéganographie Audio, Filtrage, Modulation, Étalement de Spectre (DSSS), Code de Hamming et Entrelacement (Chapitres 2, 3 et 4)
L'objectif de cette série est de cacher un message secret en le superposant dans un signal anodin. Pour ce faire, nous distinguons deux éléments :
Fe = 44.1 kHz.
Le signal rouge original est trop "large" pour être caché facilement. La solution est de filtrer les hautes fréquences, sachant que la voix reste compréhensible même réduite :
On utilise un Filtre Passe-Bas de Chebyshev de type II défini de manière méticuleuse :
Pour décaler le signal rouge hors de la bande audible de base, on applique une Modulation d'Amplitude (AM) avec une fréquence porteuse fp = 17 kHz :
On additionne ensuite la voix modulée au signal noir. L'équation de mélange est naïvement affectée d'un gain faible (ex: multiplié par 1/10).
Afin de mieux cacher le message (« Ceci est un message caché ! »), nous l'encodons en binaire, où chaque caractère ASCII génère un bloc de 8 bits via formatage. Puis un bit est défini par un symbole (BPSK : 1 symbole = 1 bit).
Pour Fe = 44.1 kHz avec un facteur de longueur de code de 256, notre débit D = Fe/N = 171.875 symboles/s (soit ~21.4 lettres ASCII/seconde).
Le secret réside dans le code de Walsh-Hadamard généré récursivement (ici avec un facteur d'étalement imposant : sf = 512).
Principe à l'émission : Pour chaque bit à +1 ou -1, on transmet l'intégralité de la séquence Hadamard. Au lieu d'une impulsion brève, l'énergie du bit est diluée sur un laps de temps large et sur une vaste bande de fréquences.
Le RSI (Rapport Signal sur Interférence) est la valeur en Décibels (dB) qui dit à quel point le signal rouge doit être enfoui sous le signal noir.
On définit l'équation globale du son envoyé : y[n] = x_noir[n] + alpha × x_rouge[n]
Le paramètre alpha calcule automatiquement le bon gain pour forcer un ratio précis donné par :
Puisque notre signal est tellement assourdi (RSI extrême) qu'il crée des erreurs à la réception, nous rajoutons deux blindages logiques :
Sur chaque bloc de 4 bits utiles, on rajoute 3 bits de parité (`p1, p2, p3`).
A la réception : L'algorithme calcule le Syndrome (Position d'Erreur = (p3×4) + (p2×2) + p1). Si non-nul, la valeur désigne de 1 à 7 la place du bit erroné. Le bit est directement corrigé via inversion booléenne `block[pos - 1] ^= 1`. Hamming (7,4) ne peut corriger qu'une seule erreur par bloc de 7 bits.
Les erreurs dans les ondes ou via un mix fort tombent généralement en "rafales" (burst errors). Si une rafale détruit 3 bits consécutifs, un bloc Hamming unique ne saura rien faire (puisqu'il est limité à 1 bit corrigeable maximum).
La solution : Utiliser une matrice (de profondeur N = 4 par exemple) pour mélanger l'ordre des bits avant l'envoi, et désentrelacer à la réception.
L'erreur en rafale survenant est alors dispersée et éclatée sur divers blocs Hamming différents au moment du désentrelacement. Ainsi, chaque bloc Hamming ne doit réparer qu'un unique bit isolé.
L'écoute de terrain demande une lecture du bruit radio constant :
Une fois le signal de l'émission suspecte capturé à 44.1 kHz, on doit le filtrer pour isoler notre source.
À nouveau, la démodulation par 17000 Hz ramène le signal cryptique. Le passage par le Filtre Passe-Bas Chebyshev de type 2 re-sculpte la bande passante avec un roll-off féroce et une phase optimisée.
Comment le script python de réception lit-il ce vacarme binaire éternel et sait où démarre le message réel ?
On utilise un Préambule Caché (la chaîne asciifiée : "_ #"). Le récepteur génère la version étalée de cette séquence exacte. Ensuite, on passe un algorithme mathématique extrêmement exigeant : la Corrélation Croisée Complexe (`np.correlate()`) entre le signal live brut reçu et notre séquence-clé générée.
t, l'énergie des signaux s'aligne d'un coup (Somme en phase) générant un immense PIC ! start_idx = np.argmax(corr) récupère l'index précis du moment 0. La matrice s'aligne : nous pouvons démarrer le déchiffrement.
Voici la chaîne complète finale qui intervient pour vaincre la forteresse de sécurité stéganographique, rédigée de manière précise point par point :
sf=512) est multiplié par le code `spreading_code`. Tout ce qui corrèle ressort positif. Les valeurs dont la somme > 0 retournent la décision de bit numérique "1" ; les <= 0 donnent le bit "0". Notre message reprend forme.{p1,p2,p3} est retourné.