Question

Je suis en train d'apprendre comment faire le chiffrement avec mot de passe Java. Je trouve plusieurs exemples en ligne, mais pas (encore) sur le débordement de pile. Les exemples sont un peu de lumière sur l'explication pour moi, en particulier en ce qui concerne la sélection de l'algorithme. Il semble y avoir beaucoup de chaînes passant autour de dire ce que des algorithmes à utiliser, mais peu de documentation à l'endroit où les chaînes viennent et ce qu'ils signifient. Et il semble aussi que les différents algorithmes peuvent nécessiter différentes implémentations de la classe KeySpec, donc je ne suis pas sûr de ce que les algorithmes peuvent utiliser la classe PBEKeySpec je regarde. De plus, les exemples semblent tous un peu de ce jour, beaucoup vous obliger à obtenir un ensemble de cryptographie ancienne qui a utilisé pour ne pas faire partie du JDK, ou même une mise en œuvre par des tiers.

Quelqu'un peut-il fournir une introduction facile à ce que je dois faire pour mettre en œuvre Crypter (données de chaîne, chaîne passphrase) et décrypter (octet [] données, mot de passe String)?

Était-ce utile?

La solution

Je serai prudent de donner ou de prendre des conseils liés à la sécurité d'un forum ... les détails sont assez complexes, et souvent devenir obsolètes rapidement.

Cela dit, je pense que Sun Java de architecture cryptographie (JCA) Guide de référence est un bon point de départ. Consultez le illustrant le cryptage par mot de passe (PBE).

BTW, la norme prévoit que JRE quelques options hors-the-box pour PBE ( "PBEWithMD5AndDES" est l'un d'entre eux). Pour plus de choix, vous aurez besoin du « pack de cryptage fort » ou d'un fournisseur tiers comme Bouncy Castle . Une autre alternative serait de mettre en œuvre votre propre PBE en utilisant les algorithmes de hachage et de chiffrement fournis dans le JRE. Vous pouvez mettre en œuvre PBE avec SHA-256 et AES-128 de cette façon ( sel rel="noreferrer">.

  • Ajoutez le sel du mot de passe et calculer son hachage cryptographique href="http://en.wikipedia.org/wiki/Cryptographic_hash_function" . Répétez cette opération plusieurs fois.
  • chiffrer le texte en clair en utilisant la valeur de hachage résultante comme l'initialisation rel="noreferrer"> et / ou secrète touche.
  • Enregistrez le sel et le cryptogramme résultant.
  • Autres conseils

    Utilisez RFC2898 pour générer des clés de mots de passe. Ce ne sont pas inclus dans le JRE ou l'entreprise criminelle commune, pour autant que je sache, mais il est inclus dans les serveurs J2EE comme JBoss , Oracle et WebSphere. Il est également inclus dans la classe de base .NET Library ( Rfc2898DeriveBytes ).

    Il y a quelques implémentations LGPL en Java là-bas, mais sur un look rapide celui-ci regarde un peu plus compliqué. Il y a aussi un bon javascript Version . (Je produisais une version modifiée de cette un et emballé comme un composant Windows Script)

    Manquant une bonne mise en œuvre avec une licence appropriée, j'empaqueté un code à partir Mattias Gartner. Voici le code dans son intégralité. Court, simple, facile à comprendre. Il est distribué sous licence MS Public License .

    // PBKDF2.java
    // ------------------------------------------------------------------
    //
    // RFC2898 PBKDF2 in Java.  The RFC2898 defines a standard algorithm for
    // deriving key bytes from a text password.  This is sometimes
    // abbreviated "PBKDF2", for Password-based key derivation function #2.
    //
    // There's no RFC2898-compliant PBKDF2 function in the JRE, as far as I
    // know, but it is available in many J2EE runtimes, including those from
    // JBoss, IBM, and Oracle.
    //
    // It's fairly simple to implement, so here it is. 
    // 
    // Created Sun Aug 09 01:06:57 2009
    //
    // last saved: 
    // Time-stamp: <2009-August-09 02:19:50>
    // ------------------------------------------------------------------
    //
    // code thanks to Matthias Gartner
    //
    // ------------------------------------------------------------------
    
    package cheeso.examples;
    
    
    import java.security.NoSuchAlgorithmException;
    import java.security.InvalidKeyException;
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    
    
    public class PBKDF2
    {
        public static byte[] deriveKey( byte[] password, byte[] salt, int iterationCount, int dkLen )
            throws java.security.NoSuchAlgorithmException, java.security.InvalidKeyException
        {
            SecretKeySpec keyspec = new SecretKeySpec( password, "HmacSHA1" );
            Mac prf = Mac.getInstance( "HmacSHA1" );
            prf.init( keyspec );
    
            // Note: hLen, dkLen, l, r, T, F, etc. are horrible names for
            //       variables and functions in this day and age, but they
            //       reflect the terse symbols used in RFC 2898 to describe
            //       the PBKDF2 algorithm, which improves validation of the
            //       code vs. the RFC.
            //
            // dklen is expressed in bytes. (16 for a 128-bit key)
    
            int hLen = prf.getMacLength();   // 20 for SHA1
            int l = Math.max( dkLen, hLen); //  1 for 128bit (16-byte) keys
            int r = dkLen - (l-1)*hLen;      // 16 for 128bit (16-byte) keys
            byte T[] = new byte[l * hLen];
            int ti_offset = 0;
            for (int i = 1; i <= l; i++) {
                F( T, ti_offset, prf, salt, iterationCount, i );
                ti_offset += hLen;
            }
    
            if (r < hLen) {
                // Incomplete last block
                byte DK[] = new byte[dkLen];
                System.arraycopy(T, 0, DK, 0, dkLen);
                return DK;
            }
            return T;
        } 
    
    
        private static void F( byte[] dest, int offset, Mac prf, byte[] S, int c, int blockIndex ) {
            final int hLen = prf.getMacLength();
            byte U_r[] = new byte[ hLen ];
            // U0 = S || INT (i);
            byte U_i[] = new byte[S.length + 4];
            System.arraycopy( S, 0, U_i, 0, S.length );
            INT( U_i, S.length, blockIndex );
            for( int i = 0; i < c; i++ ) {
                U_i = prf.doFinal( U_i );
                xor( U_r, U_i );
            }
    
            System.arraycopy( U_r, 0, dest, offset, hLen );
        }
    
        private static void xor( byte[] dest, byte[] src ) {
            for( int i = 0; i < dest.length; i++ ) {
                dest[i] ^= src[i];
            }
        }
    
        private static void INT( byte[] dest, int offset, int i ) {
            dest[offset + 0] = (byte) (i / (256 * 256 * 256));
            dest[offset + 1] = (byte) (i / (256 * 256));
            dest[offset + 2] = (byte) (i / (256));
            dest[offset + 3] = (byte) (i);
        } 
    
        // ctor
        private PBKDF2 () {}
    
    }
    

    En réponse très utile de Cheeso ci-dessus, il y a un bug mauvaise performance.

    La ligne

    int l = Math.max( dkLen, hLen)
    

    ne doit pas caculate au maximum, mais le plafond de la division, de sorte

    int l = ((dkLen - 1) / hLen) + 1; // >= ceil(dkLen / hLen), == for dkLen =>1
    

    Cela permettra d'accélérer le calcul d'un facteur 20 pour les clés de 16 octets.

    Vous avez besoin d'une bibliothèque de chiffrement, qui vous dira comment le configurer.
    Je suis comme les choses de bouncycastle.org. Vous pouvez trouver leur comment Le DES REFER dans l'exemple 5.1, est l'un des chiffrements qu'ils offrent. Ce que signifie chaîne réelle, dépendra du fournisseur. Essentiellement, vous chargez la bibliothèque.

    Security.addProvider(new BouncyCastleProvider());
    

    Et puis uniquement utiliser les interfaces pour faire JCE tout ce que vous voulez:

     keyGen = KeyGenerator.getInstance("DES", "BC");
    

    Java gère la liaison de la bibliothèque et les interfaces pour vous, vous ne devez pas faire cela. Je serais plus qu'heureux d'expliquer plus, si vous avez des questions. Malheureusement, à ce moment, je souffre de « Je ne me souviens pas comment je l'ai appris » la maladie, alors s'il vous plaît ne hésitez pas à demander.

    Vous pouvez utiliser un algorithme de hachage (plusieurs fois si nécessaire) pour obtenir de la passphrase à certaines données brutes que vous pouvez utiliser comme clé (+ un vecteur d'initialisation si l'algorithme appelle à un).

    Ensuite, vous pouvez utiliser cette clé avec un algorithme symétrique - comme 3DES-CBC ou AES-CBC (DES est considérée comme obsolète ces jours-ci)

    .

    En fonction de l'entreprise criminelle commune dont vous disposez, vous pouvez avoir des algorithmes différents à votre disposition, mais AES est probablement ce que vous voulez. Choix de l'algorithme et exactement comment l'utiliser est un peu une question religieuse, cependant, et vous serait mal avisé d'essayer de rouler vos propres, ou même d'essayer de construire un certain système de cryptage de vos propres utilisant des algorithmes standards. Vous aurez presque certainement se tromper si vous ne l'avez pas étudié, et peut-être même si vous avez.

    Si la sécurité est important pour vous que vous envisagez de chiffrement, alors vous devriez envisager de regarder aussi un livre d'ingénierie de sécurité comme Cryptographie appliquée par Bruce Schneier ou ingénierie de sécurité par Ross Anderson - il y a beaucoup de pièges de mise en œuvre. Par exemple, en utilisant un mot de passe comme clé est pas terrible une idée en premier lieu, car elle réduit sensiblement la taille de votre clé.

    Vous pouvez aussi regarder des dessins que les autres ont fait, il y a beaucoup à l'IETF, .: par exemple http://tools.ietf.org/ html / projet-McGrew-AEAD-aes-cbc-HMAC-sha1-00

    Si vous n'avez pas besoin de déchiffrer le mot de passe, mais juste générer une clé de chiffrement basée sur un mot de passe / mot de passe, vous pouvez mettre en œuvre le PKCS # 5 standard, en utilisant la JCE Cipher et MessageDigest classes.

    Convertir votre chaîne à un tableau d'octets lors du chiffrement. Reconvertir une chaîne après le déchiffrement.

    /**
     * Creates a cipher for encryption or decryption.
     * 
     * @param algorithm  PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES".
     * @param mode Encyrption or decyrption.
     * @param password Password
     * @param salt Salt usable with algorithm.
     * @param count Iterations.
     * @return Ready initialized cipher.
     * @throws GeneralSecurityException Error creating the cipher.
     */
    private static Cipher createCipher(final String algorithm, final int mode, final char[] password, final byte[] salt, final int count) throws GeneralSecurityException {
        final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
        final PBEKeySpec keySpec = new PBEKeySpec(password);
        final SecretKey key = keyFactory.generateSecret(keySpec);
        final Cipher cipher = Cipher.getInstance(algorithm);
        final PBEParameterSpec params = new PBEParameterSpec(salt, count);
        cipher.init(mode, key, params);
        return cipher;
    }
    
    /**
     * Encrypts some data based on a password.
     * @param algorithm PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES"
     * @param data Data to encrypt
     * @param password Password
     * @param salt Salt usable with algorithm
     * @param count Iterations.
     * @return Encrypted data.
     */
    public static byte[] encryptPasswordBased(final String algorithm, final byte[] data, final char[] password, final byte[] salt, final int count) {
        Validate.notNull(algorithm);
        Validate.notNull(data);
        Validate.notNull(password);
        Validate.notNull(salt);
        try {
            final Cipher cipher = createCipher(algorithm, Cipher.ENCRYPT_MODE, password, salt, count);
            return cipher.doFinal(data);
        } catch (final Exception ex) {
            throw new RuntimeException("Error encrypting the password!", ex);
        }
    }
    
    /**
     * Decrypts some data based on a password.
     * @param algorithm PBE algorithm like "PBEWithMD5AndDES" or "PBEWithMD5AndTripleDES"
     * @param encryptedData Data to decrypt
     * @param password Password
     * @param salt Salt usable with algorithm
     * @param count Iterations.
     * @return Encrypted data.
     */
    public static byte[] decryptPasswordBased(final String algorithm, final byte[] encryptedData, final char[] password, final byte[] salt, final int count) {
        Validate.notNull(algorithm);
        Validate.notNull(encryptedData);
        Validate.notNull(password);
        Validate.notNull(salt);
        try {
            final Cipher cipher = createCipher(algorithm, Cipher.DECRYPT_MODE, password, salt, count);
            return cipher.doFinal(encryptedData);
        } catch (final Exception ex) {
            throw new RuntimeException("Error decrypting the password!", ex);
        }
    }
    
    Licencié sous: CC-BY-SA avec attribution
    Non affilié à StackOverflow
    scroll top