Подтвердить что ты не робот

Использование ECC Curve25519 для шифрования/дешифрования данных в Java

Я пытаюсь использовать Curve25519 в своем Android-приложении для шифрования/дешифрования ключа шифрования AES локально. Мне не нужен обмен ключами, ключевое соглашение или подписание. Почему мне нужно использовать эту конкретную кривую? Потому что мне нужно иметь возможность самостоятельно предоставлять секретный ключ и иметь возможность рассчитать его соответствие открытому ключу. Насколько мне известно, только Curve25519 делает это. Пожалуйста, поправьте меня, если я ошибаюсь.

Все реализации Curve25519 просто делают ключевое поколение, обмен ключами и подписание/проверку.

Возможно ли сделать шифрование/дешифрование данных после получения частных/открытых ключей Curve25519 или, возможно, вы можете предложить любые альтернативные кривые, соответствующие моим критериям?

Edit

Так зачем мне это? Я объясню более внимательно. Мое приложение выполняет локальное шифрование файлов, особенно фотографии. Моя цель - сделать так, чтобы пользователь мог сделать снимок без ввода пароля, а затем ввести пароль для их просмотра. Для этого мне нужно иметь возможность создавать общедоступную/закрытую пару ключей из пароля и иметь возможность воссоздать "на лету" ту же самую пару ключей, когда такой же пароль предоставляется. Поэтому при первом запуске я генерирую ключевую пару ECC из пароля и сохраняю открытый ключ на устройстве. Когда пользователь хочет принять новое приложение для фотографий, он шифрует фотографию со случайным 256-битным ключом AES, а затем шифрует этот ключ с помощью открытого открытого ключа. Когда пользователь хочет просмотреть фотографию, он/она предоставляет правильный пароль, я получаю ту же ключевую пару ECC и дешифрую ключ AES с помощью своего личного ключа, а затем я могу расшифровать фотографию с помощью AES 256.

Итак, насколько я могу получить Curve25519, я могу дать мне эту способность или есть другие альтернативы. Примеры кода в Java приветствуются!

4b9b3361

Ответ 1

Ключи к шифрованию файлов на устройстве Android - это никогда не хранить ключ. К этому вы добавили ограничение, согласно которому для шифрования изображений не требуется пароль. Наконец, поскольку асимметричное шифрование происходит медленно, вам понадобится AES для тяжелого подъема.

Это работает с RSA или любым другим асимметричным алгоритмом.

Начальный запуск

  • При первом запуске создайте пару ключей и попросите пользователя ввести пароль.
  • Сохранять открытый ключ открытым. Шифруйте закрытый ключ, используя ключ AES, сгенерированный с помощью пароля.

Шифрование

  1. Создайте другой ключ AES для каждого изображения и зашифруйте его. Зашифруйте ключ AES открытым ключом и сохраните его вместе с изображением.

дешифрование

  1. Введите пароль пользователя. Создайте из него первый ключ AES. Используйте его для дешифрования закрытого ключа. Расшифруйте ключ AES для этого изображения с помощью закрытого ключа. Используйте ключ AES для дешифрования файла и отображения его.

(У нас на самом деле есть 4 ключа. Нам нужна пара ключей, чтобы мы могли шифровать без пароля. Нам нужен первый ключ AES для безопасного хранения секретного ключа. Нам нужен второй и изменяющийся ключ AES для шифрования файла. )

Я думаю, что это должно быть безопасно, за исключением атак, таких как ведение журнала ключей. Код Java должен быть очень простым. Надеюсь, это ясно.

=============================================== =======================

Полный пример Использование AES и RSA. Для кривых переключите только код RSA, хотя он не поддерживается из коробки, поэтому вам понадобится внешняя библиотека. Кроме того, в интересах времени и краткости код менее безопасен, чем должен быть. Например, я использовал ECB, а не CBC.

package il.co.falk;

import javax.crypto.*;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;

public class SecureFile {
private PublicKey publicKey;
private byte[] privateKeyArray;
private byte[] salt = {1,2,3,4,5,6,7,8};


public static void main(String[] args) {
    String password = "PASSWORD";
    SecureFile secureFile = new SecureFile(password);
    secureFile.test();
}


public void test() {
    String password = "PASSWORD";
    String imageFile = "348756348975634897562398479623896";

    ImageAndKey imageAndKey = encryptImage(imageFile.getBytes());
    byte[] decryptedImage = decryptImage(imageAndKey, password);

    System.out.println(new String(imageFile));
    System.out.println(new String(decryptedImage));
}

public SecureFile(String password) {
    try {
        generateRSAKeys(password);
    } catch (Exception e) {
        e.printStackTrace();
    }
}



public ImageAndKey encryptImage(byte[] imageBytes) {
    try {
        byte[] secretKeyBytes = generateAESKey();
        byte[] encryptedFile = aesEncrypt(imageBytes, secretKeyBytes);
        byte[] encryptedKey = rsaEncrypt(secretKeyBytes);

        return new ImageAndKey(encryptedFile, encryptedKey);
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }

}

public byte[] decryptImage(ImageAndKey imageAndKey, String password) {
    try {
        byte[] secretKeyBytes = generateAESKey(password);
        byte[] decryptedPrivateKey = aesDecrypt(privateKeyArray, secretKeyBytes);
        byte[] decryptedKey = rsaDecrypt(imageAndKey.aesKey, decryptedPrivateKey);

        SecretKey secretKey = new SecretKeySpec(decryptedKey, "AES");
        secretKeyBytes = secretKey.getEncoded();

        byte[] decryptedBytes = aesDecrypt(imageAndKey.imageBytes, secretKeyBytes);

        return  decryptedBytes;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}



// RSA
private void generateRSAKeys(String password) throws Exception {
    final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
    keyGen.initialize(512); // TODO: make this 2048 at least
    final KeyPair keyPair = keyGen.generateKeyPair();
    publicKey = keyPair.getPublic();
    PrivateKey privateKey = keyPair.getPrivate();

    byte[] secretKeyBytes = generateAESKey(password);
    byte[] privateKeyBytes = privateKey.getEncoded();
    privateKeyArray = aesEncrypt(privateKeyBytes, secretKeyBytes);
}

public byte[] rsaEncrypt(byte[] plainText) throws Exception {
    final Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    byte[] cipherText = cipher.doFinal(plainText);
    return cipherText;
}

public byte[] rsaDecrypt(byte[] cipherText, byte[] decryptedPrivateKeyArray) throws Exception {
    PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decryptedPrivateKeyArray));

    final Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    byte[]  plainText = cipher.doFinal(cipherText);
    return plainText;
}

// AES
private byte[] aesEncrypt(byte[] plainText, byte[] secretKeyBytes) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(secretKeyBytes));
    byte[] cipherText = cipher.doFinal(plainText);
    return cipherText;
}

public byte[] aesDecrypt(byte[] cipherText, byte[] secretKeyBytes) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, getSecretKey(secretKeyBytes));
    byte[] plainText = cipher.doFinal(cipherText);
    return plainText;
}

private byte[] generateAESKey() throws Exception {
    KeyGenerator keyGen = KeyGenerator.getInstance("AES");
    keyGen.init(256);
    SecretKey secretKey = keyGen.generateKey();
    return secretKey.getEncoded();
}

private byte[] generateAESKey(String password) throws Exception {
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
    SecretKey tmp = factory.generateSecret(spec);
    SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
    return secret.getEncoded();
}

private SecretKey getSecretKey(byte[] secretKeyBytes) throws Exception {
    SecretKey secretKey = new SecretKeySpec(secretKeyBytes, "AES");
    return secretKey;
}



// Classes
class ImageAndKey {
    public byte[] imageBytes;
    public byte[] aesKey;

    public ImageAndKey(byte[] imageBytes, byte[] aesKey) {
        this.imageBytes = imageBytes;
        this.aesKey = aesKey;
    }
}

}