Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using ECC Curve25519 to encrypt/decrypt data in Java

Tags:

I am trying to use Curve25519 in my Android app to encrypt/decrypt AES encryption key locally. I don't need any key exchange, key agreement or signing. Why I need to use that particular curve? Because I need to be able to provide private key myself and be able to calculate it's matching public key. So as far as I got, only Curve25519 does this. Please correct me if I am wrong.

All Curve25519 implementations just do key generation, key exchange and signing/verifying.

Is it possible to do data encryption/decryption after I get Curve25519 private/public keys or maybe you can suggest any alternative curves that matches my criteria?

Edit

So why I need this? I'll explain more carefully. My app is doing local file encryption, particularly photos. My goal is to be able for user to take a photo without entering a password and then enter password to view them. For this I need to be able to create public/private keypair from password and be able to recreate on the fly the same keypair whenever same password is provided. So on first run I generate ECC keypair from password and store public key on the device. When user wants to take a new photo app encrypts photo with random 256 bit AES key and then encrypt that key with stored public key. When user wants to view photo, he/she provides correct password, I derive same ECC keypair and decrypt AES key with my private key and then I can decrypt the photo using AES 256.

So as far as I get Curve25519 can give me this ability or there are any other alternatives. Code examples in Java are welcomed!

like image 258
Alex Amiryan Avatar asked Nov 07 '15 14:11

Alex Amiryan


People also ask

Can you encrypt with ECC?

The elliptic curve cryptography (ECC) does not directly provide encryption method. Instead, we can design a hybrid encryption scheme by using the ECDH (Elliptic Curve Diffie–Hellman) key exchange scheme to derive a shared secret key for symmetric data encryption and decryption.


1 Answers

They key to encrypting files on an Android device is to never store the key. To this you've added the constraint that encrypting pictures should not require a password. Finally, because asymmetric encryption is slow, you would need AES to do the heavy lifting.

This works with RSA or any other asymmetric algorithm.

Initial Run

  1. On first run, generate a keypair and require the user to input a password.
  2. Store the public key in clear. Encrypt the private key using an AES key generated from the password.

Encryption

  1. Generate a different AES key for each picture and encrypt the image with it. Encrypt the AES key with the public key and store it alongside the picture.

Decryption

  1. Have the user input the password. Generate the first AES key from it. Use it to decrypt the private key. Decrypt the AES key for this image using the private key. Use the AES key to decrypt the file and display it.

(We actually have 4 keys. We need the key pair to allow us to encrypt without a password. We need the first AES key to store the private key securely. We need the second and changing AES key to encrypt the file.)

I think this should be secure, except for attacks such as key logging. The Java code should be very straightforward. Hope this is clear.

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

Complete example Using AES and RSA. For Curve, switch the RSA code only, though it isn't supported out of the box, so you'll need an external library. Also, in the interest of time and brevity, the code is less secure than it should be. For example, I used ECB and not 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;     } } 

}

like image 103
Roy Falk Avatar answered Sep 28 '22 11:09

Roy Falk