Generazione di una chiave AES sicura?

3

Ho chiesto questa domanda qualche tempo fa su IVs in AES, e Ho avuto una risposta molto gentile e utile (grazie!), Quindi stavo pensando che forse voi ragazzi potreste aiutarmi di nuovo, questa volta con la vera generazione di chiavi.

TL; DR - Vedi in basso

Attualmente sto crittografando in questo modo:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
SecureRandom randomSecure = SecureRandom.getInstance("SHA1PRNG");
byte[] iv = new byte[cipher.getBlockSize()];
randomSecure.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParams);
rawCryptotext = cipher.doFinal(textToEncrypt.getBytes());

Quindi puoi vedere che sto usando la classe SecureRandom per generare il IV casuale.

Tuttavia:

Notare la variabile key nella sesta riga di codice:

SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");

Quella variabile proviene dal mio metodo getKey() , che è la seguente:

public static String getKey()
    {
        String possibleKey = "init";
        String validKey = null;

        while (possibleKey.length() != 16)
        {
            System.out.printf("\nPlease enter a 128-bit key: ");
            possibleKey = input.nextLine();
        }

        if (possibleKey.length() == 16)
        {
            validKey = possibleKey;
        }
        else
        {
            System.out.println("Something has gone very wrong...");
        }

        return validKey;
    }

Noterai che ottengo la chiave da parte dell'utente e la passo in testo normale a SecretKeySpec .

Quindi la mia domanda: la combinazione di una chiave in chiaro con una IV casuale rende la crittografia sicura? O dovrei prima inserire la stringa chiave con SHA-256 o qualcosa del genere e usare il risultato per la chiave?

    
posta Android Dev 28.08.2016 - 21:26
fonte

2 risposte

7

No

Quello che stai facendo è chiedere all'utente di inserire una stringa di 16 caratteri o, in altre parole, una password. È vero che 16 byte possono contenere 128 bit, ma ciò vale solo per i dati in cui tutti i possibili valori di byte sono (ugualmente) possibili. Il testo composto da caratteri è tutto tranne questo. Primo, perché il set di caratteri stampabili è molto più piccolo di quello di tutti i byte. (È probabile che non saranno nemmeno in grado di inserire tutti i possibili byte se ci provassero.) Secondo, perché gli utenti non inseriranno byte casuali, ma parole. E le parole sono ancora più prevedibili.

Se vuoi che l'utente inserisca una password, non limitare la lunghezza (tranne forse per impostare un minimo) e usa qualcosa come PBKDF2 per allungare la chiave e rallentare le ipotesi del dizionario contro la password. (Come ha commentato @marstato).

D'altro canto, se vuoi generare una chiave casuale, estrai un generatore di bit casuale strong e salvalo in un file.

    
risposta data 28.08.2016 - 22:29
fonte
3

Suppongo che key sia una password inserita dall'utente.

Non utilizzarlo direttamente per la crittografia. Gli attacchi Brute-Force contro (possibilmente molto deboli) le password degli utenti sono molto più facili rispetto a un intero 128 bit (o 192, 256) bit key. Il solo hashing della password per ottenere una chiave non fa il trucco perché non rallenta la forza bruta di una quantità rilevante. Le password devono essere sottoposte a hash decine di migliaia di volte per ritardare una singola prova abbastanza a lungo da rendere un attacco a forza bruta contro la password non possibile.

PBKDF2 è la soluzione per questo. Combina un sale, una funzione di hashing sicura e tonnellate di iterazioni:

// obtain password from wherever you like
char[] password;

// generate salt using a secureRandom; store salt with ciphertext
byte[] salt;

// key size in bits
int keySize = 128;
// choose so that it takes the computer of your average user about 1 second to do the derivation (lower if running on mobile devices, higher on an enterprise server)
int nIterations = 10000;

SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBDKF2WithHmacSHA256");
SecretKeySpec keySpec = keyFactory.generateSecret(new PBEKeySpec(password, salt, keysize));
// init cipher with keySpec
    
risposta data 28.08.2016 - 22:29
fonte

Leggi altre domande sui tag