web-dev-qa-db-fra.com

Comment choisir un IV (vecteur d'initialisation) approprié pour AES / CTR / NoPadding?

Je voudrais crypter les cookies qui sont écrits par une webapp et je voudrais garder la taille des cookies au minimum, d'où la raison pour laquelle j'ai choisi AES/CTR/NoPadding.

Que recommanderiez-vous d'utiliser comme IV qui est suffisamment aléatoire et conservez l'application apatride. Je sais que je peux simplement générer un IV aléatoire et l'ajouter au message, mais cela augmentera la taille du cookie.

De plus, quelle est la taille recommandée de l'IV pour AES 128 bits?

Sinon, comment tout le monde fait-il cela? Existe-t-il des moyens "éprouvés"? Je ne veux pas réinventer la roue.

31
Drew

La sécurité du CTR nécessite que vous jamais réutilisez un IV pour deux cryptages de message avec la même clé. En fait, il est encore plus strict: le mode CTR fonctionne en chiffrant les valeurs successives d'un compteur (l'IV n'est que la valeur initiale de ce compteur) et une sécurité appropriée n'est obtenue que si la même valeur de compteur n'est pas utilisée deux fois; cela signifie que le chiffrement d'une valeur avec un IV "consomme" en fait une séquence de valeurs IV successives qui ne doivent pas être réutilisées avec un autre chiffrement.

Le moyen le plus simple est d'utiliser un générateur de nombres aléatoires sécurisé cryptographiquement et de créer un nouveau IV aléatoire de 16 octets pour chaque message. Je souligne "cryptographiquement sécurisé" parce que c'est important; un générateur de nombres aléatoires de base ne suffit pas. Avec Java, utilisez Java.util.SecureRandom. Avec Win32, appelez CryptGenRandom(). Avec une sélection aléatoire, l'espace d'un possible IV 128 bits est suffisamment grand pour que les collisions soient extrêmement improbables. En fait, c'est pourquoi AES utilise des blocs de 128 bits (ce qui implique donc un IV de 128 bits).

L'entité qui décryptera le message doit connaître l'IV, vous devez donc le stocker avec le message crypté. Cela représente 16 octets supplémentaires. Je comprends que ce surcoût est ce que vous voulez éviter, bien que 16 octets ne soient pas beaucoup pour un cookie. La longueur maximale effective d'un cookie dépend du navigateur Web, mais 4000 caractères semblent fonctionner "partout". Un IV de 16 octets, lorsqu'il est codé en caractères (par exemple avec Base64), utilisera environ 22 caractères, soit beaucoup moins de 1% de votre taille maximale de cookie: peut-être pouvez-vous vous le permettre?

Maintenant, nous pouvons devenir funky et essayer de réduire la durée de l'IV par la ruse:

  • Générez l'IV avec une fonction de hachage: côté serveur, utilisez un compteur, qui commence à 0 et est incrémenté chaque fois qu'un nouveau IV est nécessaire. Pour obtenir l'IV, vous hachez le compteur avec une fonction de hachage appropriée, par ex. SHA-256 et vous conservez les 16 premiers octets de la valeur de hachage. Les "propriétés de randomisation" de la fonction de hachage seront suffisantes pour rendre l'IV suffisamment aléatoire par rapport aux exigences du CTR. Cela nécessite une fonction de hachage cryptographiquement sécurisée, d'où SHA-256 (éviter MD5). Il vous suffit alors de stocker la valeur du compteur dans le cookie, et le compteur sera plus court que 16 octets (par exemple, si vous n'avez pas plus de 4 milliards de clients, le compteur tiendra sur 4 octets). Cependant, il y a un coût caché: le serveur (je suppose que le serveur effectue le cryptage dans votre système) doit s'assurer qu'il ne réutilise jamais une valeur de compteur, il doit donc stocker le "compteur actuel" quelque part d'une manière qui persiste le serveur redémarre et n'échoue pas non plus si vous mettez à l'échelle plusieurs frontaux. Ce n'est pas aussi simple que ça.

  • Utilisez une valeur unique externe: éventuellement, le cookie peut faire partie d'un contexte qui fournit suffisamment de données pour générer une valeur qui sera unique à chaque cryptage. Par exemple, si la demande contient également (en clair) un "ID utilisateur", vous pouvez utiliser l'ID utilisateur comme source IV. La configuration est similaire à celle ci-dessus: vous obtenez toutes ces données, les insérez dans SHA-256, et les 16 premiers octets de sortie SHA-256 sont l'IV dont vous avez besoin. Cela ne fonctionne que si ces données ne changent pas pour un message chiffré donné et si elles sont vraiment uniques. Ceci est rare: par exemple, un "ID utilisateur" n'est bon pour cela que s'il n'est jamais nécessaire de rechiffrer un nouveau message pour le même utilisateur, et s'il n'y a jamais de possibilité qu'un ID utilisateur soit réutilisé (par exemple un ancien utilisateur quitte, un nouvel utilisateur vient et sélectionne l'ID utilisateur désormais gratuit).

Utiliser un IV aléatoire de 16 octets généré avec un cryptage sécurisé PRNG est toujours le moyen "sûr", et celui que je recommande. Si vous trouvez un espace restreint dans le cookie, cela signifie que vous vous approchez de la limite de 4 Ko, auquel point vous voudrez peut-être utiliser la compression (sur les données avant le cryptage; après le cryptage, il est très peu probable que la compression fonctionne). Utilisez zlib (en Java, vous pouvez accéder à zlib via Java.util.Zip).

Avertissement: dans tout ce qui précède, je ne dis pas n'importe quoi si le cryptage des cookies aide à fournir la sécurité caractéristiques que vous essayez d'atteindre. Habituellement, lorsque le cryptage est nécessaire, vous avez réellement besoin à la fois du cryptage et de l'intégrité, puis vous devez utiliser un mode de cryptage et d'intégrité combiné. Recherche GCM et CCM . De plus, le cryptage des cookies est généralement bon dans un but, qui est d'éviter le coût de stockage côté serveur d'un peu de données spécifiques à l'utilisateur. Si vous souhaitez crypter un cookie pour autre chose, par ex. pour authentifier un utilisateur valide, alors vous vous trompez: le chiffrement n'est pas le bon outil pour cela.

49
Thomas Pornin

Je n'ai pas de réponse directe à votre question mais quelques choses à ajouter cependant.

Tout d'abord, le cryptage du cookie n'a pas de sens pour moi. Si vous souhaitez la confidentialité de vos données, vous ne devez de toute façon pas les stocker dans un cookie. Si vous souhaitez l'intégrité (c'est-à-dire qu'il n'est pas possible de falsifier le contenu du cookie), vous devez utiliser un hachage à clé (HMAC, par exemple).

Une autre note est de jamais utiliser un IV qui est tout 0 juste pour plus de commodité.

Les IV sont de taille égale à celle de votre bloc. Dans le cas d'AES-128, la taille de bloc est de 128, la taille de clé est de 128 et donc l'IV est de 128 bits.

La meilleure façon de le faire est de créer une clé AES aléatoire et de l'utiliser comme IV. Ce IV aléatoire peut être public tant qu'il n'est pas réutilisé dans les cryptages ultérieurs avec la même clé

modifier :

Vous voudrez peut-être consulter cette page wiki pour plus d'informations sur le mode à utiliser. Cependant, n'utilisez jamais ECB sauf si vous êtes sûr de devoir l'utiliser. Et même alors, vérifiez auprès d'un expert. CBC est pour autant que je sache le plus sûr (avec PCBC).

http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation

4
Henri

Si vous ne faites pas le IV au hasard (c'est-à-dire que vous utilisez un groupe de chiffres répétitifs), il sera plus facile de comprendre la clé si le cookie commence toujours par le même texte clair.

La taille IV pour AES-128 est de 128 bits. IIRC, l'IV est de la même taille que le bloc de chiffrement. 128 bits est de 16 octets. 32 octets si vous le stockez en tant que chaîne hexadécimale ASCII. Est-ce vraiment trop? 32 octets de nos jours, ce n'est pas grand-chose du tout ...

2

Il est possible d'éviter l'IV aléatoire en utilisant CBC et en stockant le HMAC devant le message. L'utilisation d'une constante IV choisie au hasard est acceptable. Mais vous devez être sûr que les messages sont tous différents.

C'est le cas lorsque le message chiffré est toujours différent. Une clé de licence avec un numéro de série correspondrait à ces critères. Un cookie avec un identifiant utilisateur ou un identifiant de session lui correspondrait également.

Vous pouvez utiliser CBC avec une IV aléatoire constante si vous stockez le hmac devant le message. Le hachage cumule toutes les variations réparties dans le message dans le premier bloc. Vous pouvez également ajouter quelques octets aléatoires ou de préférence un numéro de série si vous pouvez vous assurer qu'il sera unique ou non réutilisé dans très longtemps.

Ne pensez même pas à utiliser le CTR avec une IV constante.

0
chmike

Incluez un grand nombre aléatoire avec le cookie. Un nombre de 64 ou 128 bits est probablement assez grand. Il doit être suffisamment grand pour qu'il soit très difficile d'obtenir des doublons. Assurez-vous de mettre suffisamment d'entropie dans ce nombre. N'utilisez pas seulement gettime (). Si vous avez accès à CRNG, utilisez-le ici.

Stockez une clé principale de 256 bits avec votre application. Utilisez SHA256 pour dériver vos informations clés. Encore une fois, utilisez un CRNG pour cela.

$keyblob = sha256( concat("aeskeyid", $masterkey , $randomnumberwithcookie ) )
$aeskey = $keyblob[0..15]
$aesiv = $keyblob[16..31]

Vous pouvez également vouloir dériver une clé pour un HMAC.

$mackeyblob = sha256( concat("hmackeyid", $masterkey , $randomnumberwithcookie ) )

Vous pouvez également combiner les deux opérations de hachage ci-dessus en une seule à l'aide de SHA512.

$keyblob = sha512( concat("randomkeyid", $masterkey , $randomnumberwithcookie ) )
$aeskey = $keyblob[0..15]
$aesiv = $keyblob[16..31]
$hmackey = $keyblob[32..63]