Why is desktop AES file IO incompatible with Andro

2019-03-21 13:13发布

问题:

I have ported an application from Android to desktop that uses AES to encrypt some private data. Both applications are able to encrypt and decrypt the data for their own use but unable to decrypt the other applications data. The AES keys, IVs, and algorithms are identical. The main difference between the two applications is that the android-sdk comes with the BouncyCastle provider already added to the security while the desktop application needed

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

Android app:

public class AesFileIo {
 public final static String EOL = "\n";
 public static final String AES_ALGORITHM = "AES/CTR/NoPadding";
 public static final String PROVIDER = "BC"; 
 private static final SecretKeySpec secretKeySpec = 
  new SecretKeySpec(AES_KEY_128, "AES");
 private static final IvParameterSpec ivSpec = new IvParameterSpec(IV);

 public String readAesFile(Context c, String fileName) {
  StringBuilder stringBuilder = new StringBuilder();
  try {
   InputStream is = c.openFileInput(fileName);
   Cipher cipher = Cipher.getInstance(AES_ALGORITHM, PROVIDER);
   cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
   CipherInputStream cis = new CipherInputStream(is, cipher);
   InputStreamReader isr = new InputStreamReader(cis);
   BufferedReader reader = new BufferedReader(isr);
   String line;
   while ((line = reader.readLine()) != null) {
    stringBuilder.append(line).append(EOL);
   }
   is.close();
  } catch (java.io.FileNotFoundException e) {
   // OK, file probably not created yet
   Log.i(this.getClass().toString(), e.getMessage(), e);
  } catch (Exception e) {
   Log.e(this.getClass().toString(), e.getMessage(), e);
  }
  return stringBuilder.toString();
 }

 public void writeAesFile(Context c, String fileName, String theFile) {
  try {
   Cipher cipher = Cipher.getInstance(AES_ALGORITHM, PROVIDER); 
   cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
   byte[] encrypted = cipher.doFinal(theFile.getBytes()); 
   OutputStream os = c.openFileOutput(fileName, 0);
   os.write(encrypted);
   os.flush();
   os.close();
  } catch (Exception e) {
   Log.e(this.getClass().toString(), e.getMessage(), e);
  }
 }
}

Desktop app:

public class AesFileIo {
    private static final String EOL = "\n";
    private static final String AES_ALGORITHM = "AES/CTR/NoPadding";
    private static final SecretKeySpec secretKeySpec =
            new SecretKeySpec(AES_KEY_128, "AES");
    private static final IvParameterSpec ivSpec = new IvParameterSpec(IV);

    public void AesFileIo() {
        Security.addProvider(new org.bouncycastle.jce.provider
                .BouncyCastleProvider());
    }

    public String readFile(String fileName) {
        StringBuilder stringBuilder = new StringBuilder();
        try {
            ObjectInputStream is = new ObjectInputStream(
                new FileInputStream(fileName));
            Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
            CipherInputStream cis = new CipherInputStream(is, cipher);
            InputStreamReader isr = new InputStreamReader(cis);
            BufferedReader reader = new BufferedReader(isr);
            String line;
            while ((line = reader.readLine()) != null) {
                stringBuilder.append(line).append(EOL);
            }
            is.close();
        } catch (java.io.FileNotFoundException e) {
            System.out.println("FileNotFoundException: probably OK");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return stringBuilder.toString();
    }

    public void writeFile(String fileName, String theFile) {
        try {
            Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
            byte[] encrypted = cipher.doFinal(theFile.getBytes());
            ObjectOutputStream os = new ObjectOutputStream(
                new FileOutputStream(fileName));
            os.write(encrypted);
            os.flush();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

回答1:

Solved by

  1. Adding proper constructors to initialize SecretKeySpec and IvParameterSpec.
  2. Getting rid of ObjectOutputStream and ObjectInputStream in desktop app.

Android app:

public class AesFileIo {
    private static final String EOL = "\n";
    private static final String AES_ALGORITHM = "AES/CTR/NoPadding";
    private SecretKeySpec secretKeySpec;
    private IvParameterSpec ivSpec;
    private static final String PROVIDER = "BC"; 

    AesFileIo(byte[] aesKey, byte[] iv) {
        ivSpec = new IvParameterSpec(iv);
        secretKeySpec = new SecretKeySpec(aesKey, "AES");
    }

    public String readFile(Context c, String fileName) {
        StringBuilder stringBuilder = new StringBuilder();
        try {
            InputStream is = c.openFileInput(fileName);
            Cipher cipher = Cipher.getInstance(AES_ALGORITHM, PROVIDER);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
            CipherInputStream cis = new CipherInputStream(is, cipher);
            InputStreamReader isr = new InputStreamReader(cis);
            BufferedReader reader = new BufferedReader(isr);
            String line;
            while ((line = reader.readLine()) != null) {
                stringBuilder.append(line).append(EOL);
            }
            is.close();
        } catch (java.io.FileNotFoundException e) {
            // OK, file probably not created yet
            Log.i(this.getClass().toString(), e.getMessage(), e);
        } catch (Exception e) {
            Log.e(this.getClass().toString(), e.getMessage(), e);
        }
        return stringBuilder.toString();
    }

    public void writeFile(Context c, String fileName, String theFile) {
        try {
            Cipher cipher = Cipher.getInstance(AES_ALGORITHM, PROVIDER); 
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
            byte[] encrypted = cipher.doFinal(theFile.getBytes()); 
            OutputStream os = c.openFileOutput(fileName, 0);
            os.write(encrypted);
            os.flush();
            os.close();
        } catch (Exception e) {
            Log.e(this.getClass().toString(), e.getMessage(), e);
        }
    }
}

Desktop app:

public class AesFileIo {

    private static final String EOL = "\n";
    private static final String AES_ALGORITHM = "AES/CTR/NoPadding";
    private SecretKeySpec secretKeySpec;
    private IvParameterSpec ivSpec;

    AesFileIo(byte[] aesKey, byte[] iv) {
        Security.addProvider(new org.bouncycastle.jce.provider
                .BouncyCastleProvider());
        ivSpec = new IvParameterSpec(iv);
        secretKeySpec = new SecretKeySpec(aesKey, "AES");
    }

    public String readFile(String fileName) {
        StringBuilder stringBuilder = new StringBuilder();
        try {
            FileInputStream fis = new FileInputStream(fileName);
            Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
            CipherInputStream cis = new CipherInputStream(fis, cipher);
            InputStreamReader isr = new InputStreamReader(cis);
            BufferedReader reader = new BufferedReader(isr);
            String line;
            while ((line = reader.readLine()) != null) {
                stringBuilder.append(line).append(EOL);
            }
            fis.close();
        } catch (java.io.FileNotFoundException e) {
            System.out.println("FileNotFoundException: probably OK");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return stringBuilder.toString();
    }

    public void writeFile(String fileName, String theFile) {
        try {
            Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
            byte[] encrypted = cipher.doFinal(theFile.getBytes());
            FileOutputStream fos = new FileOutputStream(fileName);
            fos.write(encrypted);
            fos.flush();
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}