Avatar billede fredand Forsker
13. december 2004 - 20:22 Der er 10 kommentarer og
1 løsning

How to encrypt a file with only assym. crypto

Hello!

I'm working with a encryption project.

The task is to build a app that can encrypt a file like a jpg-file.
When the encryption is done the application shall not be able to decrypt it back.

After this the encrypted file may be send over a network an decrypted by an other application.

My idea how to solve this would be like using assymetric keys like public and private keys.

And I my first attempt of doing this would be (please correct me if this is stupid in any way):

1 generate keys
2 put public key in app 1
3 put private key in app 2
4 encrypt a file with the public key in app 1
5 send the encrypted file by a regular email
6 encrypt the received file in app2 with the private key.


How ever when I run this approach like below I get a:
javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes

it occurs at line with:
byte[] encryptedFileBytes = cipher.doFinal(decryptedFileBytes);

public void enCrypt(File file)
{
    try
    {
        //Generate keys
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();

        //Save keys to files
        ObjectOutputStream objectOutputStream = new ObjectOutputStream( new FileOutputStream(new File("assignments6/image_filter_private_key")) );
        objectOutputStream.writeObject(privateKey);
        objectOutputStream.flush();
        objectOutputStream.close();

        objectOutputStream = new ObjectOutputStream( new FileOutputStream(new File("assignments6/image_filter_public_key")) );
        objectOutputStream.writeObject(publicKey);
        objectOutputStream.flush();
        objectOutputStream.close();

        //Get original text
        FileInputStream fileInputStream = new FileInputStream(file);
        byte[] decryptedFileBytes = new byte[fileInputStream.available()];
        fileInputStream.read(decryptedFileBytes);
        fileInputStream.close();

        //Get the key
        ObjectInputStream objectInputStream = new ObjectInputStream( new FileInputStream( new File("assignments6/image_filter_public_key") ) );
        publicKey = (PublicKey)objectInputStream.readObject();

        //Encrypt
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedFileBytes = cipher.doFinal(decryptedFileBytes);

        //Save encrypted data
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        fileOutputStream.write(encryptedFileBytes);
        fileOutputStream.flush();
        fileOutputStream.close();
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}

I really thought that this would be a correct approch to encrypt a file with public and private keys. If I'm right nobody then the holder of the private key should be able to decrypt it.


So please help me how to do this?

Best regards
Fredrik
Avatar billede arne_v Ekspert
13. december 2004 - 20:29 #1
The exception text indicat ethat you should call update and then dofinal with a
chunk smaller than 117 bytes.
Avatar billede arne_v Ekspert
13. december 2004 - 20:33 #2
It is common practice to encrypt the main text with a randomly chossen
symmetric key and the just use the assymmetric key to encrypt the symmetric key.

For performance reasons.
Avatar billede fredand Forsker
13. december 2004 - 20:37 #3
Hello Arne!

Thanks for your fast reply.

Do you by any chance got some code that do what you are sayin in your first comment, I'm not sure taht I understand. Should I devide my original data into smaller chunks? But how do I do that?

Best regards
Fredrik
Avatar billede arne_v Ekspert
13. december 2004 - 20:40 #4
I can create some code.
Avatar billede arne_v Ekspert
13. december 2004 - 21:40 #5
It is not just calling update (as for other ciphers).

There is a 117 limit in the RSA algorithm.

So we have to call doFinal multiple times.

Example:

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;

public class RSA {
    public static void main(String[] args) {
        String s2;
        try {
            String s = "ABC DEF GHIJ 123 - ÆØÅæøå - dette er en lang tekst - " +
                      "som gerne skulle være længere end 177 tegn - bla bla " +
                      "bla bla bla bla bla bla bla bla bla bla bla bla bla " +
                      "bla bla bla bla bla bla bla bla bla bla bla bla bla " +
                      "bla bla bla bla bla bla bla bla bla bla bla bla bla";
            byte[] plain = s.getBytes("ISO-8859-1");
            System.out.println(s);
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(1024);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            PrivateKey privateKey = keyPair.getPrivate();
            PublicKey publicKey = keyPair.getPublic();
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] code = new byte[(((plain.length-1)/100+1))*128];
            int ixplain = 0;
            int ixcode = 0;
            while((plain.length - ixplain) > 100) {
                ixcode += cipher.doFinal(plain, ixplain, 100, code, ixcode);
                ixplain += 100;
            }
            cipher.doFinal(plain, ixplain, plain.length - ixplain, code, ixcode);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] plain2 = new byte[code.length];
            int ixplain2 = 0;
            int ixcode2 = 0;
            while((code.length - ixcode2) > 128) {
                ixplain2 += cipher.doFinal(code, ixcode2, 128, plain2, ixplain2);
                ixcode2 += 128;
            }
            ixplain2 += cipher.doFinal(code, ixcode2, code.length - ixcode2, plain2, ixplain2);
            s2 = new String(plain2, 0, ixplain2, "ISO-8859-1");
            System.out.println(s2);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (ShortBufferException e) {
            e.printStackTrace();
        }
    }
}
Avatar billede arne_v Ekspert
13. december 2004 - 21:40 #6
And as stated previously: this is not how RSA is intended to be used. It is not even¨
guaranteed to be very secure.
Avatar billede fredand Forsker
14. december 2004 - 09:13 #7
Hello Arne!

Thanks for your great example, as always!

My guess is that you must use 128 for chunks for the encrypted part. Or is it possible to use any other number?

I also guess that you can use any number under 118 for chunks for the decrypted part, that must be a limit in RSA?

Perhaps you could give a hint way this may be stupid and perhaps I can ask you how you would have solved this task in some small pseduo-code.
The task:
The task is to build a app that can encrypt a file like a jpg-file.
When the encryption is done the application shall not be able to decrypt it back.

Best regards
Fredrik

BTW give a svar so I can reward you ;-)
Avatar billede arne_v Ekspert
14. december 2004 - 10:45 #8
As I understand it the encrypted chunks are always 128 bytes.

The max. plain is 117 due to some limits in RSA.

I think you should use symmetric to encrypt the file and assymetric to encrypt the
symetric key.

I can make a code example.
Avatar billede arne_v Ekspert
14. december 2004 - 10:45 #9
answer
Avatar billede arne_v Ekspert
14. december 2004 - 21:02 #10
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.util.Random;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class RSA3DES {
    public static void main(String[] args) {
        try {
            String s = "ABC DEF GHIJ 123 - ÆØÅæøå - dette er en lang tekst - " +
                      "som gerne skulle være længere end 117 tegn - bla bla " +
                      "bla bla bla bla bla bla bla bla bla bla bla bla bla " +
                      "bla bla bla bla bla bla bla bla bla bla bla bla bla " +
                      "bla bla bla bla bla bla bla bla bla bla bla bla bla";
            byte[] plain = s.getBytes("ISO-8859-1");
            System.out.println(s);
            Random rng = new Random();
            byte[] key = new byte[24];
            rng.nextBytes(key);
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DESede");
            SecretKey secretKey = secretKeyFactory.generateSecret(new DESedeKeySpec(key));
            Cipher realcipher = Cipher.getInstance("DESede");
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(1024);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            PrivateKey privateKey = keyPair.getPrivate();
            PublicKey publicKey = keyPair.getPublic();
            Cipher cipher = Cipher.getInstance("RSA");
            realcipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] code = realcipher.doFinal(plain);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] codekey = cipher.doFinal(secretKey.getEncoded());
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] key2 = cipher.doFinal(codekey);
            realcipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key2, "DESede"));
            byte[] plain2 = realcipher.doFinal(code);
            String s2 = new String(plain2, "ISO-8859-1");
            System.out.println(s2);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
    }
}
Avatar billede fredand Forsker
15. december 2004 - 12:42 #11
Looks interesting!
Thanks mate!
/Fredrik
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester