Voici un ensemble de méthodes permettant d'effectuer le chiffrement d'une chaine en AES-256 avec Java et d'effectuer le déchiffrement avec Windev, et inversement.
L'idée est de voir comment rendre les méthodes de chiffrement interopérables entre les deux langages, ce qui n'est pas forcément évident au premier abord.
La première étape consiste à générer une clé de chiffrement.
Pour des raisons de sécurité, cette clé sera générée en hachant un mot de passe avec l'algo de hachage SHA-256.
Ensuite, pour des raisons d'inter-compatibilité, cette clé sera encodée en base64.
Génération de la clé de chiffrement en Windev :
Génération de la clé de chiffrement en Java :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 PROCÉDURE GenererCleSHA256_Base64(_sMotDePasse est une chaîne) LOCAL buffCle est un Buffer //Clé de chiffrement sCleBase64 est une chaîne //Clé de chiffrement encodée en base64 //Pour une meilleure sécurité, je vais générer la clé en hachant un mot de passe avec un algorithme de hachage de la famille SHA-1 buffCle = HashChaîne(HA_HMAC_SHA_256,_sMotDePasse) //Pour des raisons dinter-compatibilité Windev / JAVA, j'encode le résultat du hachage en base64. sCleBase64 = Encode(buffCle,encodeBASE64) RENVOYER sCleBase64
Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.util.Base64; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; public String GenererCleSHA256_Base64(String _sMotDePasse,String _sSel) throws NoSuchAlgorithmException, InvalidKeySpecException { SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); KeySpec spec = new PBEKeySpec(_sMotDePasse.toCharArray(),_sSel.getBytes(),65536,256); SecretKey tmp = factory.generateSecret(spec); String sCleBase64 = Base64.getEncoder().encodeToString(tmp.getEncoded()); return sCleBase64; }
Dans un cas comme dans l'autre, les clés générées peuvent être utilisées indifférement pour chiffrer ou déchiffrer avec Java ou Windev.
Je vais maintenant utiliser la clé pour chiffrer un message.
Chiffrement avec Windev :
Chiffrement avec Java :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 PROCÉDURE Chiffrer_AES256(LOCAL _sMessageAChiffrer est une chaîne,LOCAL _sCleBase64 est une chaîne) LOCAL buffCle est un Buffer buffMessageAChiffrer est une Buffer //Message en clair à chiffrer buffContenuChiffre est un Buffer //Vecteur d'initialisation + message chiffrés // bufIV est un Buffer //Partie chiffrée du vecteur d'initialisation // bufDonnees est un Buffer //Partie chiffrée du message sMessageChiffreBase64 est une chaîne //Je décode la clé depuis l'encode base64 buffCle = Décode(_sCleBase64,encodeBASE64) //Je passe le message d'un encodage ANSI à un encodage UTF-8 buffMessageAChiffrer = ChaîneVersUTF8(_sMessageAChiffrer) //Je chiffre le message à l'aide de la clé buffContenuChiffre = CrypteStandard(buffMessageAChiffrer,buffCle,crypteAES256,crypteCBC,cryptePaddingPKCS) ////Récupérer la partie chiffrée du vecteur d'initialisation //bufIV = buffContenuChiffre[[ À 16]] ////Récupérer la partie chiffrée des données //bufDonnees = buffContenuChiffre[[16+1 À]] //J'encode les deux parties en base64 sMessageChiffreBase64 = Encode(buffContenuChiffre,encodeBASE64) RENVOYER sMessageChiffreBase64
Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 import java.nio.charset.Charset; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Base64; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; public String Chiffrer_AES256(String _sMessageAChiffrer,String _sCleBase64) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { byte[] keyData = Base64.getDecoder().decode(_sCleBase64); SecretKeySpec secretKey = new SecretKeySpec(keyData,"AES"); Cipher cipher = null; cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //Générer le vecteur d'initialisation sur 16 octets int ivSize = 16; byte[] iv = new byte[ivSize]; SecureRandom random = new SecureRandom(); random.nextBytes(iv); IvParameterSpec ivspec = new IvParameterSpec(iv); cipher.init(Cipher.ENCRYPT_MODE,secretKey,ivspec); //On ajoute le vecteur d'initialisation, car Windev s'attend à ce que les 16 premiers octets de la chaine retournée contiennent le vecteur, lors du décryptage avec DecrypteStandard. byte[] mess = _sMessageAChiffrer.getBytes(Charset.forName("UTF-8")); byte[] encrypted = cipher.doFinal(mess); byte[] encryptedIVAndText = new byte[ivSize + encrypted.length]; System.arraycopy(iv, 0, encryptedIVAndText, 0, ivSize); System.arraycopy(encrypted, 0, encryptedIVAndText, ivSize, encrypted.length); String sMessageChiffreBase64 = Base64.getEncoder().encodeToString(encryptedIVAndText); return sMessageChiffreBase64; }
Je récupère le message chiffré encodé en base64, que je peux déchiffrer de la même manière avec Windev ou Java :
Déchiffrement avec Windev :
Déchiffrement avec Java :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 PROCÉDURE Dechiffrer_AES256(LOCAL _sMessageChiffreBase64 est une chaîne,LOCAL _sCleBase64 est une chaîne) LOCAL buffCle est un Buffer buffMessageChiffre est un Buffer//Message chiffré après décodage base64 buffMessageDechiffre est un Buffer//Message déchiffré sous forme de buffer sMessageDechiffre est une chaîne//Message déchiffré sous forme de chaine //Je décode la clé depuis l'encodage base64 buffCle = Décode(_sCleBase64,encodeBASE64) //je décode le message depuis l'encodage base64 buffMessageChiffre = Décode(_sMessageChiffreBase64,encodeBASE64) //je déchiffre le message à l'aide de la clé buffMessageDechiffre = DécrypteStandard(buffMessageChiffre,buffCle,crypteAES256,crypteCBC,cryptePaddingPKCS) //Je passe le message d'un encodage UTF-8 à un encodage ANSI sMessageDechiffre = UTF8VersChaîne(buffMessageDechiffre,alphabetAnsi) RENVOYER sMessageDechiffre
Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 import java.nio.charset.Charset; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Base64; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; public String Dechiffrer_AES256(String _sMessageChiffreBase64,String _sCleBase64) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { byte[] keyData = Base64.getDecoder().decode(_sCleBase64); SecretKeySpec secretKey = new SecretKeySpec(keyData,"AES"); Cipher cipher = null; cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); int ivSize = 16; byte[] encryptedIvTextBytes = Base64.getDecoder().decode(_sMessageChiffreBase64); //Récupérer la partie chiffrée du vecteur d'initialisation byte[] iv = new byte[ivSize]; System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length); IvParameterSpec ivspec = new IvParameterSpec(iv); //Récupérer la partie chiffrée des données int encryptedSize = encryptedIvTextBytes.length - ivSize; byte[] encryptedBytes = new byte[encryptedSize]; System.arraycopy(encryptedIvTextBytes, ivSize, encryptedBytes, 0, encryptedSize); cipher.init(Cipher.DECRYPT_MODE,secretKey,ivspec); byte[] decrypted = cipher.doFinal(encryptedBytes); String sMessageDechiffre = new String(decrypted,Charset.forName("UTF-8")); return sMessageDechiffre; }
Voici un code Windev final de test :
Et la classe Java :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 //------------------------------------------------------------- //Création de la clé de chiffrement LOCAL sCleBase64 est une chaîne//Clé de chiffrement encodée en base64 sCleBase64 = GenererCleSHA256_Base64("MotDePasse") //------------------------------------------------------------- //Chiffrement Windev LOCAL sMessageAChiffrer est une chaîne//Message en clair à chiffrer sMessageChiffreBase64 est une chaîne //Message chiffré encodé en base64 sMessageAChiffrer = "Ce message peut être chiffré avec Java et déchiffré avec Windev." sMessageChiffreBase64 = Chiffrer_AES256(sMessageAChiffrer,sCleBase64) Info("Message chiffré : "+sMessageChiffreBase64) //------------------------------------------------------------- //Déchiffrement Windev LOCAL sMessageDechiffre est une chaîne sMessageDechiffre = Dechiffrer_AES256(sMessageChiffreBase64,sCleBase64) Info("Message déchiffré : "+sMessageDechiffre)
Code Java : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89 import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.util.Base64; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import java.nio.charset.Charset; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.SecureRandom; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; public class AES256 { public String GenererCleSHA256_Base64(String _sMotDePasse,String _sSel) throws NoSuchAlgorithmException, InvalidKeySpecException { SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); KeySpec spec = new PBEKeySpec(_sMotDePasse.toCharArray(),_sSel.getBytes(),65536,256); SecretKey tmp = factory.generateSecret(spec); String sCleBase64 = Base64.getEncoder().encodeToString(tmp.getEncoded()); return sCleBase64; } public String Chiffrer_AES256(String _sMessageAChiffrer,String _sCleBase64) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { byte[] keyData = Base64.getDecoder().decode(_sCleBase64); SecretKeySpec secretKey = new SecretKeySpec(keyData,"AES"); Cipher cipher = null; cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //Générer le vecteur d'initialisation sur 16 octets int ivSize = 16; byte[] iv = new byte[ivSize]; SecureRandom random = new SecureRandom(); random.nextBytes(iv); IvParameterSpec ivspec = new IvParameterSpec(iv); cipher.init(Cipher.ENCRYPT_MODE,secretKey,ivspec); //On ajoute le vecteur d'initialisation, car Windev s'attend à ce que les 16 premiers octets de la chaine retournée contiennent le vecteur, lors du décryptage avec DecrypteStandard. byte[] mess = _sMessageAChiffrer.getBytes(Charset.forName("UTF-8")); byte[] encrypted = cipher.doFinal(mess); byte[] encryptedIVAndText = new byte[ivSize + encrypted.length]; System.arraycopy(iv, 0, encryptedIVAndText, 0, ivSize); System.arraycopy(encrypted, 0, encryptedIVAndText, ivSize, encrypted.length); String sMessageChiffreBase64 = Base64.getEncoder().encodeToString(encryptedIVAndText); return sMessageChiffreBase64; } public String Dechiffrer_AES256(String _sMessageChiffreBase64,String _sCleBase64) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { byte[] keyData = Base64.getDecoder().decode(_sCleBase64); SecretKeySpec secretKey = new SecretKeySpec(keyData,"AES"); Cipher cipher = null; cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); int ivSize = 16; byte[] encryptedIvTextBytes = Base64.getDecoder().decode(_sMessageChiffreBase64); //Récupérer la partie chiffrée du vecteur d'initialisation byte[] iv = new byte[ivSize]; System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length); IvParameterSpec ivspec = new IvParameterSpec(iv); //Récupérer la partie chiffrée des données int encryptedSize = encryptedIvTextBytes.length - ivSize; byte[] encryptedBytes = new byte[encryptedSize]; System.arraycopy(encryptedIvTextBytes, ivSize, encryptedBytes, 0, encryptedSize); cipher.init(Cipher.DECRYPT_MODE,secretKey,ivspec); byte[] decrypted = cipher.doFinal(encryptedBytes); String sMessageDechiffre = new String(decrypted,Charset.forName("UTF-8")); return sMessageDechiffre; } }
Voilà
Partager