Cryptage des données dans Oracle 9i

Mohammed Bouayoun

Dans cet article, on décrit comment crypter les données dans une base Oracle 9i ♪

- Titre : Cryptage des données dans Oracle 9i

- Auteur : Mohammed Bouayoun

- Parution : 16 novembre 2006

- Licence : Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.

Sommaire

- I. Introduction

- II. Remplissage et Chaînage

- III. Cryptage des données

- IV. Le vecteur d'initialisation

- V. Décryptage de données

- VI. Remerciements

I - Introduction

Le Cryptage, appelé également chiffrement, est un processus consistant à convertir des données de texte simple en texte crypté afin de les rendre incompréhensibles par un tiers non autorisé. Ce procédé se fait par le biais d'une clé de cryptage.

À partir de la 9i, Oracle fournit le paquetage DBMS_OBFUSCATION_TOOLKIT qui utilise seulement deux types de cryptages standards : DES et Triple DES.

DES : Data Encryption Standard. Outil de cryptographie, mis au point par IBM dans les années 1970.

Le triple DES est basé sur une clé de 128 bytes et est plus robuste qu'un simple DES qui est basé sur une clé de 56 bytes.

Le DES 56 bits a été cassé en moins de 24 heures par Distributed.net, en janvier 1999. À la place du DES, NIST (novembre 2001) recommande l'utilisation de l'AES (Advanced Encryption Standard) qu'on va trouver dans le nouveau paquetage DBMS_CRYPTO (Oracle 10g).

II - Remplissage et Chaînage

Quand une chaîne de caractères est cryptée, elle est divisée en plusieurs morceaux de 8 bytes, qui sont traités indépendamment par l'algorithme de cryptage. Quand la longueur de données n'est pas un multiple de 8 bytes, l'algorithme ajoute quelques caractères à la fin pour l'amener exactement à 8 bytes. Ce processus est connu sous le nom de Remplissage (Padding).

Pour sécuriser la valeur de ce remplissage, on peut utiliser une méthode de remplissage prédéveloppée dans Oracle, connue sous le nom de PCKS#5 (Public Key Cryptography System), mais il existe d'autres options.

Quand une chaîne a été divisée en plusieurs morceaux, après, on doit ensuite les relier ensemble, ce processus est connu sous le nom de Chaînage (chaining). En général, la sécurité d'un système de cryptage est basée sur la manière d'enchaîner ces morceaux. Oracle fournit les méthodes suivantes :

Méthode

Description

CBC

Cipher Block Chaining, la méthode la plus utilisé

ECB

Electronic Code Book

CFB

Cipher Feedback

OFB

Output Feedback

III - Cryptage des données

On va chiffrer le mot MOHAMMEDBOUAYOUN avec la clé ABCDEFGHIJKLMNOP

DECLARE
val_crypt VARCHAR2(200);
BEGIN
DBMS_OBFUSCATION_TOOLKIT.des3encrypt
(entree    =>    'MOHAMMEDBOUAYOUN',
cle        =>    'ABCDEFGHIJKLMNOP',
crypte => chif_val
);
DBMS_OUTPUT.put_line('Valeur chiffrée = '|| val_crypt);
END;

Valeur chiffrée = â4u¿Nc
\x81ä§)^Sóq

Il peut être intéressant de stocker le résultat de la requête, pour par exemple l'imprimer. On peut également convertir cette valeur en un type de données RAW par le package UTL_RAW puis en Hexadécimal avec la fonction RAWTOHEX.

Ce qui donne :

DECLARE
val_chif VARCHAR2(200);
BEGIN
DBMS_OBFUSCATION_TOOLKIT.des3encrypt
(entree    =>    'MOHAMMEDBOUAYOUN',
cle        =>    'ABCDEFGHIJKLMNOP',
crypte => chif_val
);
val_chif := RAWTOHEX(UTL_RAW.cast_to_raw(val_chif));
DBMS_OUTPUT.put_line('Valeur chiffrée = '|| val_chif);
END;

Valeur chiffrée = E23475AD8A4E630A81E4A7295E53F371

On peut aussi convertir la valeur chiffrée de l'Hexadecimal en valeur numérique

val_chif := to_number('E23475AD8A4E630A81E4A7295E53F371','XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');

Valeur chiffrée = 300677913275234235803498582057300521841

Dans les exemples précédents, on a utilisé la fonction DES3ENCRYPT qui est un triple chiffrement DES. On peut utiliser d'autres fonctions.

Pour faciliter les choses, on crée la fonction :

CREATE OR REPLACE FUNCTION encrypte (p_entree IN VARCHAR2, p_cle IN VARCHAR2)
RETURN VARCHAR2
IS
l_crypte   VARCHAR2 (200);
BEGIN
l_crypte :=
DBMS_OBFUSCATION_TOOLKIT.des3encrypt (input_string      => p_entree,
key_string        => p_cle
);
l_crypte := RAWTOHEX (UTL_RAW.cast_to_raw (l_crypte));
RETURN l_crypte;
END;

DECLARE
v_crypte   VARCHAR2 (200);
BEGIN
v_crypte := encrypte ('MOHAMMEDBOUAYOUN', 'ABCDEFGHIJKLMNOP');
DBMS_OUTPUT.put_line ('Valeur chiffrée= ' || v_crypte);
END;
/

Le résultat est :

Valeur chiffrée = E23475AD8A4E630A81E4A7295E53F371

Modifions la valeur à chiffrer MOHAMMEDBOUAYOUN par MOHAMMEDBOUAYOUN1.

Ceci nous donne le script suivant :

DECLARE
v_crypte   VARCHAR2 (200);
BEGIN
v_crypte := encrypte ('MOHAMMEDBOUAYOUN1', 'ABCDEFGHIJKLMNOP');
DBMS_OUTPUT.put_line ('Encrypted value = ' || v_crypte);
END;
/

En lançant le script précédent, on a l'erreur suivante :

ORA-28232: invalid input length for obfuscation toolkit
ORA-06512: at "SYS.DBMS_OBFUSCATION_TOOLKIT_FFI", line 0
ORA-06512: at "SYS.DBMS_OBFUSCATION_TOOLKIT", line 216
ORA-06512: at "SYSTEM.ENCRYPTE", line 6
ORA-06512: at line 4

On obtient cette erreur, car l'entrée de la fonction DES3ENCRYPT doit être un multiple de 8 caractères, ce type de chiffrement est connu sous le nom de chiffrement par bloc (block ciphering). Pour remédier à ce problème, on écrit une autre fonction qui ajoute des espaces pour que la longueur de l'entrée soit un multiple de 8.

CREATE OR REPLACE FUNCTION encrypte (p_entree IN VARCHAR2, p_cle IN VARCHAR2)
RETURN VARCHAR2
IS
l_crypte   VARCHAR2 (200);
l_entree       VARCHAR2 (200);
BEGIN
l_entree := RPAD(p_entree,(8*ROUND(LENGTH(p_entree)/8,0)+8));
l_crypte :=
DBMS_OBFUSCATION_TOOLKIT.des3encrypt (input_string      => l_entree,
key_string        => p_cle
);
l_crypte := RAWTOHEX (UTL_RAW.cast_to_raw (l_crypte));
RETURN l_crypte;
END;

DECLARE
v_crypte   VARCHAR2 (200);
BEGIN
v_crypte := encrypte ('MOHAMMEDBOUAYOUN1', 'ABCDEFGHIJKLMNOP');
DBMS_OUTPUT.put_line ('Valeur chiffrée = ' || v_crypte);
END;
/

Le résultat est :

Valeur chiffrée = E23475AD8A4E630A81E4A7295E53F371DC94046D7D5747F8

IV - Le vecteur d'initialisation

Dans la méthode utilisée précédemment, un intrus peut utiliser un utilitaire de cryptoanalyse pour vérifier l'entête de l'information cryptée en identifiant le pattern. Pour éviter ceci, il est possible d'ajouter une valeur aléatoire au début la donnée en cours. Si par exemple, on a la valeur 12345678, on peut attacher au début la valeur 6564 qui devient 656412345678 puis l'encrypter après. L'entête de l'information contiendra des valeurs en relation avec 6564, et non pas avec la valeur en cours 12345678. Il ne faut pas oublier d'enlever la valeur aléatoire 6564 après le décryptage.

La valeur aléatoire préfixe aux données est connu sous le nom vecteur d'initialisation (IV). Dans DBMS_OBFUSCATION_TOOLKIT, on spécifie ce vecteur d'initialisation dans la fonction DES3ENCRYPT comme un paramètre supplémentaire appelé iv_string. La combinaison de l'IV avec la donnée doit être un multiple de huit.

CREATE OR REPLACE FUNCTION encrypte (
p_entree   IN   VARCHAR2,
p_cle      IN   VARCHAR2,
p_iv       IN   VARCHAR2 := NULL
)
RETURN VARCHAR2
IS
l_crypte   VARCHAR2 (200);
l_entree    VARCHAR2 (200);
l_iv        VARCHAR2 (200);
BEGIN
l_entree := RPAD (p_entree, (8 * ROUND (LENGTH (p_entree) / 8, 0) + 8));
l_iv := RPAD (p_iv, (8 * ROUND (LENGTH (p_iv) / 8, 0) + 8));
l_crypte :=
DBMS_OBFUSCATION_TOOLKIT.des3encrypt (input_string      => l_entree,
key_string        => p_cle,
iv_string         => l_iv
);
l_crypte := RAWTOHEX (UTL_RAW.cast_to_raw (l_crypte));
RETURN l_crypte;
END;

V - Décryptage de données

Maintenant, on va essayer de décrypter la valeur originale avec la fonction DES3DECRYPT. On créera une valeur cryptée depuis un texte clair et on le décryptera.

DECLARE
l_crypte   VARCHAR2 (2000);
l_decrypte   VARCHAR2 (2000) := 'Clear Text Data';
l_cle       VARCHAR2 (2000) := 'ABCDEFGHIJKLMNOP';
BEGIN
l_crypte := get_enc_val (l_decrypte, l_cle, '12345678');
l_decrypte :=
DBMS_OBFUSCATION_TOOLKIT.des3decrypt
(input_string      => UTL_RAW.cast_to_varchar2
(HEXTORAW (l_crypte)
),
key_string        => l_cle
);
DBMS_OUTPUT.put_line ('Valeur décryptée = ' || l_decrypte);
END;
/

Le résultat est différent de la valeur originale !

Tout simplement, on doit spécifier l'IV pendant le décryptage qui était 12345678.

DECLARE
l_crypte   VARCHAR2 (2000);
l_decrypte   VARCHAR2 (2000) := 'Clear Text Data';
l_cle       VARCHAR2 (2000) := 'ABCDEFGHIJKLMNOP';
BEGIN
l_enc_val := encrypte (l_decrypte, l_cle, '12345678');
l_decrypte :=
DBMS_OBFUSCATION_TOOLKIT.des3decrypt
(input_string      => UTL_RAW.cast_to_varchar2
(HEXTORAW (l_crypte)
),
key_string        => l_cle,
iv_string         => '12345678'
);
DBMS_OUTPUT.put_line ('Valeur Décryptée = ' || l_decrypte);
END;
/

Le résultat est :

Valeur Décryptée = Clear Text Data

PL/SQL procedure successfully completed.

VI - Remerciements

Je tiens à remercier toute l'équipe de Developpez.com pour son aide dans la relecture et l'amélioration du présent tutoriel, en particulier Xo pour la correction de l'orthographe.