Android AES на основе пароля шифрование с использованием одного ключа и случайного IV для каждого сообщения - PullRequest
3 голосов
/ 22 февраля 2012

В настоящее время я внедряю симметричное шифрование / расшифровку с использованием AES 256 на Android, вдохновленное этим сообщением: Java 256bit AES Encryption .Цель моей реализации состоит в том, что я хочу зашифровать данные в базе данных.

Для генерации ключа я использую следующий конструктор, который принимает пароль char []:

public Cryptography(char[] password) throws NoSuchAlgorithmException,
        InvalidKeySpecException, NoSuchPaddingException {

    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
    KeySpec spec = new PBEKeySpec(password, salt, 1024, 256);
    secretKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
    cipher = Cipher.getInstance(AES/CBC/PKCS5Padding);
}

Так что когдаЯ запускаю свою активность в Android. Я инициализирую новый экземпляр своего класса криптографии и, следовательно, получаю сгенерированный ключ.Соль - это фиксированный случайный байт [] из 16 байтов.Это значит, что я всегда получаю один и тот же ключ.Причина этого позже.

Теперь, после того как я получил объект в одном действии, я могу использовать следующие методы шифрования и дешифрования с всегда одним и тем же ключом:

public byte[] encrypt(String cleartext) throws InvalidKeyException,
        IllegalBlockSizeException, BadPaddingException,
        UnsupportedEncodingException, InvalidParameterSpecException {

    cipher.init(Cipher.ENCRYPT_MODE, secretKey);

    byte[] encText = cipher.doFinal(cleartext.getBytes(CHARSET_NAME));
    byte[] iv = cipher.getParameters()
            .getParameterSpec(IvParameterSpec.class).getIV();

    byte[] enc = new byte[IV_SIZE + encText.length];

    for (int i = 0; i < enc.length; i++) {
        if (i < IV_SIZE)
            enc[i] = iv[i];
        else if (i < enc.length)
            enc[i] = encText[i - IV_SIZE];
    }

    return enc;
}

public String decrypt(byte[] encryptedText) throws InvalidKeyException,
        InvalidAlgorithmParameterException, UnsupportedEncodingException,
        IllegalBlockSizeException, BadPaddingException {

    byte[] iv = new byte[IV_SIZE];
    byte[] dec = new byte[encryptedText.length - IV_SIZE];

    for (int i = 0; i < encryptedText.length; i++) {
        if (i < IV_SIZE)
            iv[i] = encryptedText[i];
        else if (i < encryptedText.length)
            dec[i - IV_SIZE] = encryptedText[i];
    }

    cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));

    return new String(cipher.doFinal(dec), CHARSET_NAME);
}

Как видите,Я сохраняю новый IV вместе с зашифрованным текстом каждый раз, когда шифрую сообщение.

В заключение: я использую ОДИН ключ шифрования, ОДНУ случайную соль и новое поле IV для КАЖДОГО в таблице базы данных.

Сначала я хотел сгенерировать новый ключ с новой солью и новым IV каждый раз, когда я шифрую ОДНОЕ поле в таблице базы данных и сохраняю требуемое соль и IV вместе с зашифрованным текстом или, по крайней мере, для одной строки таблицы.Но причина, по которой я сделал это, как указано выше, заключается в том, что генерация ключа на устройстве Android занимает много времени.Я проверил на эмуляторе, но генерация ключа заняла около двух секунд.Вот почему я только что сгенерировал один ключ при запуске Activity.

Итак, наконец, мой вопрос: насколько мой подход достаточно безопасен, если использовать только один ключ, но новые случайные IV для каждого сообщения?В настоящее время я не вижу другого способа сделать его как можно более безопасным, поддерживая его в равновесии с производительностью.

Надеюсь, достаточно ясно, что я написал, и кто-нибудь может дать мне несколько советов по этому поводу.

С уважением

xoidberg

1 Ответ

1 голос
/ 22 декабря 2013

Я считаю, что вопрос не относится к вам (xoidberg), но он может быть актуален для некоторых других людей.

Из того, что я понимаю - вы используете соль для создания (надежно случайного) ключа из пароля. Если у каждого пользователя есть случайная (разная) соль - это нормально. В противном случае это может быть проблематично.

Я полагаю, что это то, что вы сделали, поэтому мне кажется (все в порядке).

Я просто хочу упомянуть, что обычно вы хотите использовать соли, когда сохраняете хеш-функцию некоторых значений (обычно это пароль). Хеш-функции, такие как MD5 или SHA, не имеют ключа, и вы должны добавить случайность для этой цели. Вот почему вам нужна соль, и именно поэтому в этом случае вам обычно требуется случайная соль для каждого значения (если вы просто сохраняете хэши паролей с одной и той же солью, вы можете обнаружить самые распространенные хэши и узнать, что пароль пользователей с наиболее распространенным хешем - 123456). В вашем случае - каждому пользователю нужна уникальная соль.

Об IV - вам действительно нужен случайный случай каждый раз (так что все в порядке).

...