首页 文章

使用ECC Curve25519在Java中加密/解密数据

提问于
浏览
23

我想在我的Android应用程序中使用Curve25519在本地加密/解密AES加密密钥 . 我不需要任何密钥交换,密钥协议或签名 . 为什么我需要使用那条特定的曲线?因为我需要能够自己提供私钥并能够计算它匹配的公钥 . 所以就我而言,只有Curve25519这样做 . 如果我错了,请纠正我 .

所有Curve25519实现都只进行密钥生成,密钥交换和签名/验证 .

在获得Curve25519私钥/公钥后,是否可以进行数据加密/解密,或者您可以建议任何符合我标准的替代曲线?

Edit

那我为什么需要这个呢?我会更仔细地解释一下 . 我的应用正在进行本地文件加密,尤其是照片 . 我的目标是让用户无需输入密码即可拍照,然后输入密码进行查看 . 为此,我需要能够从密码创建公钥/私钥对,并且只要提供相同的密码,就能够在运行时重新创建相同的密钥对 . 所以在第一次运行时,我从密码生成ECC密钥对,并在设备上存储公钥 . 当用户想要使用新的照片应用程序使用随机256位AES密钥加密照片,然后使用存储的公钥加密该密钥 . 当用户想要查看照片时,他/她提供正确的密码,我获得相同的ECC密钥对并使用我的私钥解密AES密钥,然后我可以使用AES 256解密照片 .

所以,就我而言,Curve25519可以给我这种能力,或者还有其他选择 . 欢迎使用Java中的代码示例!

1 回答

  • 2

    加密Android设备上的文件的关键是永远不存储密钥 . 为此,您添加了加密图片不需要密码的约束 . 最后,因为非对称加密很慢,所以你需要使用AES来完成繁重的工作 .

    这适用于RSA或任何其他非对称算法 .

    Initial Run

    • 首次运行时,生成密钥对并要求用户输入密码 .

    • 将公钥存储为明文 . 使用密码生成的AES密钥加密私钥 .

    Encryption

    • 为每张图片生成不同的AES密钥,并使用它加密图像 . 使用公钥加密AES密钥并将其与图片一起存储 .

    Decryption

    • 让用户输入密码 . 从中生成第一个AES密钥 . 用它来解密私钥 . 使用私钥解密此图像的AES密钥 . 使用AES密钥解密文件并显示它 .

    (我们实际上有4个密钥 . 我们需要密钥对来允许我们在没有密码的情况下加密 . 我们需要第一个AES密钥来安全地存储私钥 . 我们需要第二个和更改AES密钥来加密文件 . )

    我认为这应该是安全的,除了密钥记录等攻击 . Java代码应该非常简单 . 希望这很清楚 .

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

    完整示例使用AES和RSA . 对于Curve,仅切换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;
        }
    }
    

    }

相关问题