Re: [Un peu HS] Utilisation de l'API OpenSSL

2024-07-04 Par sujet BERTRAND Joël
didier gaumet a écrit :
> Le 04/07/2024 à 20:44, BERTRAND Joël a écrit :
>> didier gaumet a écrit :
> [...]
>>> https://stackoverflow.com/questions/71763461/purpose-of-evp-encryptfinal-ex-function-in-openssl
>>>
> [...]
> 
>> Ce que je ne saisis pas, c'est pour quoi lorsqu'on
>> a déjà un multiple d'une longueur de bloc, la fonction en rajoute un. Et
>> pourquoi elle plante lamentablement en cas de déchiffrement.
> [...]
> 
> comme dit précédemment, tout ça me passe un peu au-dessus de ce qui me
> sert malaisément de cerveau mais le lien ci-dessus a quelques
> explications intéressantes fournies par un type quia l'air de comprendre
> à peu près de quoi il parle, et ça renvoie vers l'explication Wikipedia
> du mode d'opération de chiffrement, section "remplissage":
> https://fr.wikipedia.org/wiki/Mode_d%27op%C3%A9ration_(cryptographie)#Remplissage
> 
> (comme on est sur une liste en français, je pointe vers un lien en
> français, mais le texte original en anglais est peut-être plus à jour ou
> plus complet)
> 
> donc j'ai pas creusé mais une explication du comportement que tu
> observes (des blocs de 16 bits dont seuls 15 utilisés passent mais pas
> des blocs de 16 bits comportant 16 bits utiles) pourrait résider dans le
> mode utilisé, je cite:
> "[...]  Un peu plus complexe est la méthode DES originale, qui consiste
> à ajouter un seul bit, suivi de suffisamment de bits zéro pour remplir
> le bloc ; si le message se termine sur une limite de bloc, un bloc de
> remplissage entier sera ajouté. [...]"

Rien à voir, je suis en ECB. Donc chaque bloc est chiffré séparément.
Le problème est "pourquoi openssl bourre-t-il un nouveau bloc de 16
octets alors qu'il n'a pas besoin de le faire ?"

Le chiffrement est le suivant :
16 octets -> AES256 -> 16 octets (et non 32).

JB



signature.asc
Description: OpenPGP digital signature


Re: [Un peu HS] Utilisation de l'API OpenSSL

2024-07-04 Par sujet didier gaumet

Le 04/07/2024 à 20:44, BERTRAND Joël a écrit :

didier gaumet a écrit :

[...]

https://stackoverflow.com/questions/71763461/purpose-of-evp-encryptfinal-ex-function-in-openssl

[...]


Ce que je ne saisis pas, c'est pour quoi lorsqu'on
a déjà un multiple d'une longueur de bloc, la fonction en rajoute un. Et
pourquoi elle plante lamentablement en cas de déchiffrement.

[...]

comme dit précédemment, tout ça me passe un peu au-dessus de ce qui me 
sert malaisément de cerveau mais le lien ci-dessus a quelques 
explications intéressantes fournies par un type quia l'air de comprendre 
à peu près de quoi il parle, et ça renvoie vers l'explication Wikipedia 
du mode d'opération de chiffrement, section "remplissage":

https://fr.wikipedia.org/wiki/Mode_d%27op%C3%A9ration_(cryptographie)#Remplissage
(comme on est sur une liste en français, je pointe vers un lien en 
français, mais le texte original en anglais est peut-être plus à jour ou 
plus complet)


donc j'ai pas creusé mais une explication du comportement que tu 
observes (des blocs de 16 bits dont seuls 15 utilisés passent mais pas 
des blocs de 16 bits comportant 16 bits utiles) pourrait résider dans le 
mode utilisé, je cite:
"[...]  Un peu plus complexe est la méthode DES originale, qui consiste 
à ajouter un seul bit, suivi de suffisamment de bits zéro pour remplir 
le bloc ; si le message se termine sur une limite de bloc, un bloc de 
remplissage entier sera ajouté. [...]"


Enfin, je dis ça, je dis rien, c'est juste une hypothèse et c'est pas 
moi qui me coltine le problème  ;-)


plus sérieusement: bon courage :-)



Re: [Un peu HS] Utilisation de l'API OpenSSL

2024-07-04 Par sujet BERTRAND Joël
didier gaumet a écrit :
> préambule lamentable: j'ai lu ta bafouille en diagonale, je n'ai pas le
> niveau, j'ai pas envie de creuser, etc... donc ma réponse ne va
> peut-être pas être très pertinente, désolé ;-)
> 
> En très gros de la part d'un inculte du sujet, même si la fonction
> openssl semble légèrement différente sur cette page, je me demande si le
> mécanisme sur lequel tu butes n'est pas le même (du padding qui
> nécessite la décomposition en sous-variables dont la dernière doit être
> traitée par une fonction de type "final"):
> https://stackoverflow.com/questions/71763461/purpose-of-evp-encryptfinal-ex-function-in-openssl
> 
> 
> j'ai peut-être rien compris, hein, c'est hors de mes maigres compétences
> et je n'ai de plus pas envie de vriller les pauvres neurones qui me
> restent à chercher à comprendre ;-)

Ça tourne effectivement autour de cela. Je connais la différence entre
les deux fonctions. Ce qui me dérange, c'est que dans tous les exemples
que j'ai pu trouver EVP_CipherFinal_ex() est toujours appelée sur le
dernier bloc (pour bourrer les octets manquant pour avoir un multiple de
la longueur de bloc). Ce que je ne saisis pas, c'est pour quoi lorsqu'on
a déjà un multiple d'une longueur de bloc, la fonction en rajoute un. Et
pourquoi elle plante lamentablement en cas de déchiffrement.

Je pense (naïvement sans doute) que si aucun test n'est fait dans les
exemples sur la longueur des données à chiffrer, cette fonction doit
être appelée dans tous les cas.

Bien cordialement,

JB



signature.asc
Description: OpenPGP digital signature


Re: [Un peu HS] Utilisation de l'API OpenSSL

2024-07-04 Par sujet didier gaumet
préambule lamentable: j'ai lu ta bafouille en diagonale, je n'ai pas le 
niveau, j'ai pas envie de creuser, etc... donc ma réponse ne va 
peut-être pas être très pertinente, désolé ;-)


En très gros de la part d'un inculte du sujet, même si la fonction 
openssl semble légèrement différente sur cette page, je me demande si le 
mécanisme sur lequel tu butes n'est pas le même (du padding qui 
nécessite la décomposition en sous-variables dont la dernière doit être 
traitée par une fonction de type "final"):

https://stackoverflow.com/questions/71763461/purpose-of-evp-encryptfinal-ex-function-in-openssl

j'ai peut-être rien compris, hein, c'est hors de mes maigres compétences 
et je n'ai de plus pas envie de vriller les pauvres neurones qui me 
restent à chercher à comprendre ;-)




[Un peu HS] Utilisation de l'API OpenSSL

2024-07-04 Par sujet BERTRAND Joël
Bonjour à tous,

Désolé de venir avec un problème pas tout à fait Debian. J'essaye de
m'inscrire sur les listes de diffusion OpenSSL depuis plusieurs jours
sans aucun retour. Je pense que des lecteurs ont déjà été confrontés au
problème.

J'utilise OpenSSL (3.3.1) pour chiffrer des messages et les déchiffrer.
J'observe un comportement que je ne comprends pas. Je n'utilise qu'un
chiffrement de type AES256-ECB (donc le chiffrement d'un bloc ne dépend
que du bloc en question. Je sais, ce n'est pas bien, mais le
périphérique en face est un microcontrôleur qui cause en 4G et qui
possède très peu de mémoire).

Lorsque mon périphérique parle à mon serveur Debian, mon programme
plante méchamment lors de l'appel à la fonction EVP_CipherFinal_ex().

Que fais-je ?

Je crée un contexte, je l'initialise avec la clef et tout ce qui va
bien puis je chiffre :

if ((contexte = EVP_CIPHER_CTX_new()) == NULL)
{
return(NULL);
}

EVP_CIPHER_CTX_reset(contexte);

longueur_bloc_de_chiffrement =
EVP_CIPHER_block_size(type_chiffrement);

if (EVP_CipherInit_ex(contexte, type_chiffrement, NULL, clef,
vecteur_initialisation, (encodage == d_vrai) ? 1 : 0) != 1)
{
EVP_CIPHER_CTX_free(contexte);
return(NULL);
}

nombre_blocs = longueur_message / longueur_bloc_de_chiffrement;

if ((longueur_message % longueur_bloc_de_chiffrement) != 0)
{
nombre_blocs++;
}

(*longueur_message_chiffre) = nombre_blocs *
longueur_bloc_de_chiffrement;

printf("longueur_message_chiffre = %lld\n", (*longueur_message_chiffre));

// On prévoit une zone de garde pour EVP_CipherFinal_ex() en
// espérant
// qu'il ne faille pas plus qu'une longueur de bloc de chiffrement.
// Méchant hack en raison d'un comportement étrange de
// EVP_CipherFinal_ex().
if ((message_chiffre = malloc(((size_t) ((*longueur_message_chiffre)
+ longueur_bloc_de_chiffrement)) *
sizeof(unsigned char))) == NULL)
{
EVP_CIPHER_CTX_free(contexte);
return(NULL);
}

printf("longueur_message = %d\n", (int) longueur_message);

if (EVP_CipherUpdate(contexte, message_chiffre, &longueur_message_1,
message, (int) longueur_message) != 1)
{
free(message_chiffre);
EVP_CIPHER_CTX_free(contexte);
return(NULL);
}

printf("longueur_message_1 = %d\n", longueur_message_1);

if (EVP_CipherFinal_ex(contexte, message_chiffre +
longueur_message_1,
&longueur_message_2) != 1)
{
free(message_chiffre);
EVP_CIPHER_CTX_free(contexte);
return(NULL);
}

printf("longueur_message_2 = %d\n", longueur_message_2);

(*longueur_message_chiffre) = longueur_message_1 +
longueur_message_2;

// Mise à jour du vecteur d'initialisation

EVP_CIPHER_CTX_get_updated_iv(contexte, vecteur_initialisation,
(size_t) EVP_CIPHER_iv_length(type_chiffrement));

EVP_CIPHER_CTX_free(contexte);

Cette routine est appelée pour chiffrer et pour déchiffrer. Je ne mets
pas tout le code, ça n'a pas beaucoup d'intérêt. Maintenant, mon problème.

Le code AES256 utilise des blocs de 16 octets. Si je chiffre un message
de 15 octets, j'obtiens un message chiffré de 16 octets. Normal.

longueur_message_chiffre = 16
longueur_message = 15
longueur_message_1 = 0
longueur_message_2 = 16

Ainsi, EVP_CipherUpdate() ne fait rien (aucun bloc entier) et le
chiffrement est effectué par EVP_CipherFinal_ex().

Si maintenant je cherche à chiffrer un message de 16 octets, voici ce
qui sort :

longueur_message_chiffre = 16
longueur_message = 16
longueur_message_1 = 16
longueur_message_2 = 16
=> longueur_message_chiffre donne la longueur nécessaire au chiffrement
du message. La longueur effectivement renvoyée est
longueur_message_1+longueur_message_2 soit ici 32 !

Si je comprends bien, EVP_CipherUpdate() chiffre un bloc de 16 octets.
Mais pourquoi EVP_CipherFinal_ex() rajoute-t-il un autre bloc de 16
octets ? J'obtiens un message de 32 octets alors que seuls les 16
premiers sont signifiants.

Dans mon cas, j'obtiens :
"?r\xF1\xF0-\x89\x83]\xD3\xEE\xF0bj\xE2\xB7\x9E\xE34\xF2\xD2f
\xF6w\x02\x14\x0DbS\xD5\x01\x1A"

alors que seul

"?r\xF1\xF0-\x89\x83]\xD3\xEE\xF0bj\xE2\xB7\x9E" contient le message
chiffré (le formalisme est le suivant : les caractères affichables sont
directement affichés, les autres sont \x + octet en hexadécimal).

Le problème est aussi que je suis capable de déchiffrer le message
complet "?r\xF1\xF0-\x89\x83]\xD3\xEE\xF0bj\xE2\xB7\x9E\xE34\xF2\xD2f
\xF6w\x02\x14\x0DbS\xD5\x01\x1A"
en une chaîne de 16 octets (qui est bien le message envoyé). En
revanche, si je tente le déchiffrement des seuls 16 premiers octets,
EVP_CipherFinal_ex() renvoie une erreur.

Je ne comprends pas mon erreur. Quelqu'un a-t-il déjà été confronté à
ce p