Bonjour,
J'avais fais il y a un moment une classe utilitaire pour le chiffrement en AES-CBC mais j'aimerais ajouter un chiffrement plus résistant toujours en AES (j'ai vu par exemple que ECB et CBC sont moins résistants que d'autres modes). Or, je suis perdu entre les différents mode de chiffrement d'AES (CBC, OCB, XTS, GCM...).
J'ai vu des exemples avec GCM qui semble t-il est mieux que CBC mais je ne comprend pas bien les notions d'initialization vector (IV) et de nonce. Certaines fois cela semble correspondre à la même chose alors que d'autres fois cela semble différents.
Egalement, parfois il y a un sel qui est utilisé dans les exemples, et parfois il n'y a que cet IV (ou nonce je ne sais pas trop). Du coup je me demande s'il me faudrait toujours un sel pour le mot de passe.
Avant j'utilisais juste Cipher.update() pour mes blocs de 1024 puis Cipher.doFinal() à la fin. Dans les exemples pour AES-GCM ils utilisent parfois juste Cipher.doFinal(input) ou bien Cipher.updateAAD() avant le doFinal.

Bref, je suis perdu avec tout ca et je ne sais pas comment coder correctement ce nouvel algo.

Voici le code existant pour chiffrer en AES-CBC:
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
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
 
private static final String ENCRYPT_ALGORITHM = "AES";
private static final String AES_CBC_CIPHER_SPEC = "AES/CBC/PKCS5Padding";
 
private static final String AES_CBC_KEYGEN_SPEC = "PBKDF2WithHmacSHA1";
private static final int AES_CBC_SALT_LENGTH = 16; // in bytes = N x 8 bits
 
private static final int AUTH_KEY_LENGTH = 8; // in bytes
private static final int ITERATIONS = 32768;
 
public static void encryptAESCBC(int lKeyLength, String pPassword, InputStream pInput, OutputStream pOutput)
	    throws EncryptionException, IOException {
	// Check validity of key length
	if (lKeyLength != 128 && lKeyLength != 192 && lKeyLength != 256) {
	    throw new EncryptionException("Invalid AES key length: " + lKeyLength);
	}
 
	// generate salt and derive keys for authentication and encryption
	SecureRandom lSecureRandom = new SecureRandom();
	byte[] lSalt = getByteArrayFromRandom(lSecureRandom, AES_CBC_SALT_LENGTH);
	Keys lKeys = keygenAESCBC(lKeyLength, pPassword.toCharArray(), lSalt);
 
	// initialize AES encryption
	Cipher lEncrypt = null;
	try {
	    lEncrypt = Cipher.getInstance(AES_CBC_CIPHER_SPEC);
	    lEncrypt.init(Cipher.ENCRYPT_MODE, lKeys.encryption);
	} catch (NoSuchAlgorithmException exc) {
	    throw new EncryptionException(
		    "Transformation is null, empty, in an invalid format, or no Provider supports a CipherSpiimplementation for the specified algorithm",
		    exc);
	} catch (NoSuchPaddingException exc) {
	    throw new EncryptionException("Transformation contains a padding scheme that is not available", exc);
	} catch (InvalidKeyException exc) { // 192 or 256-bit AES not available
	    throw new EncryptionException(lKeyLength + "-bit AES encryption is not available on this Java platform.", exc);
	}
 
	// get initialization vector
	byte[] lIv = null;
	try {
	    lIv = lEncrypt.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
	} catch (InvalidParameterSpecException exc) {
	    throw new EncryptionException("Invalid parameter for initialization vector", exc);
	}
 
	// write authentication and AES initialization data
	pOutput.write(lKeyLength / 8);
	pOutput.write(lSalt);
	pOutput.write(lKeys.authentication.getEncoded());
	pOutput.write(lIv);
 
	// read data from input into buffer, encrypt and write to output
	byte[] lBuffer = new byte[BUFFER_SIZE];
	int lNumRead;
	byte[] lEncrypted = null;
	while ((lNumRead = pInput.read(lBuffer)) > 0) {
	    lEncrypted = lEncrypt.update(lBuffer, 0, lNumRead);
	    if (lEncrypted != null) {
		pOutput.write(lEncrypted);
	    }
	}
	try { // finish encryption - do final block
	    lEncrypted = lEncrypt.doFinal();
	} catch (IllegalBlockSizeException | BadPaddingException exc) {
	    throw new EncryptionException("Exception when doing doFinal", exc);
	}
	if (lEncrypted != null) {
	    pOutput.write(lEncrypted);
	}
    }
 
private static byte[] getByteArrayFromRandom(SecureRandom pSecureRandom, int pLength) {
	byte[] lSalt = new byte[pLength];
	pSecureRandom.nextBytes(lSalt);
	return lSalt;
    }
 
private static Keys keygenAESCBC(int pKeyLength, char[] pPassword, byte[] pSalt) throws EncryptionException {
	SecretKeyFactory lFactory;
	try {
	    lFactory = SecretKeyFactory.getInstance(AES_CBC_KEYGEN_SPEC);
	} catch (NoSuchAlgorithmException impossible) {
	    return null;
	}
	// derive a longer key, then split into AES key and authentication key
	KeySpec lSpec = new PBEKeySpec(pPassword, pSalt, ITERATIONS, pKeyLength + AUTH_KEY_LENGTH * 8);
	SecretKey lTmp = null;
	try {
	    lTmp = lFactory.generateSecret(lSpec);
	} catch (InvalidKeySpecException impossible) {
	    // TODO
	}
	byte[] lFullKey = lTmp.getEncoded();
	SecretKey lAuthKey = new SecretKeySpec( // key for password authentication
		Arrays.copyOfRange(lFullKey, 0, AUTH_KEY_LENGTH), ENCRYPT_ALGORITHM);
	SecretKey lEncKey = new SecretKeySpec( // key for AES encryption
		Arrays.copyOfRange(lFullKey, AUTH_KEY_LENGTH, lFullKey.length), ENCRYPT_ALGORITHM);
	return new Keys(lEncKey, lAuthKey);
    }
 
private static class Keys {
	public final SecretKey encryption, authentication;
 
	public Keys(SecretKey pEncryption, SecretKey pAuthentication) {
	    this.encryption = pEncryption;
	    this.authentication = pAuthentication;
	}
    }
Je souhaiterais avoir une méthode similaire (niveau paramètres) mais qui chiffrerait selon le nouveau mode choisi (exemple: AES-GCM ou bien un autre selon ce qui est mieux). En paramètre il y a des InputStream et OutputStream car je souhaite pouvoir l'appeler pour une chaine de caractères ou un fichier (je ne sais pas si c'est correct de manipuler ca ou s'il y a plus simple comme manipuler byte[]).

Que me recommandez-vous comme mode de chiffrement? GCM?

Pouvez-vous m'expliquer les notions que je n'ai pas comprises (début du message) et l'utilisation des méthodes comme Cipher.doFinal(input) ou bien Cipher.updateAAD() qui n'étaient pas utilisées avant avec mon algorithme pour AES-CBC svp?