加密/解密文件和不正确的数据

时间:2014-04-04 13:14:00

标签: java android encryption

static void encrypt() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
    // Here you read the cleartext.
    FileInputStream fis = new FileInputStream("data/cleartext");
    // This stream write the encrypted text. This stream will be wrapped by another stream.
    FileOutputStream fos = new FileOutputStream("data/encrypted");

    // Length is 16 byte
    SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(), "AES");
    // Create cipher
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, sks);
    // Wrap the output stream
    CipherOutputStream cos = new CipherOutputStream(fos, cipher);
    // Write bytes
    int b;
    byte[] d = new byte[8];
    while((b = fis.read(d)) != -1) {
        cos.write(d, 0, b);
    }
    // Flush and close streams.
    cos.flush();
    cos.close();
    fis.close();
}

static void decrypt() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
    FileInputStream fis = new FileInputStream("data/encrypted");

    FileOutputStream fos = new FileOutputStream("data/decrypted");
    SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(), "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, sks);
    CipherInputStream cis = new CipherInputStream(fis, cipher);
    int b;
    byte[] d = new byte[8];
    while((b = cis.read(d)) != -1) {
        fos.write(d, 0, b);
    }
    fos.flush();
    fos.close();
    cis.close();
}   

我将这些功能用于加密/解密文件,但在某些设备上我收到的数据不正确。

例如,我的正确数据是:

一个

2

3

4

5

解密后

一个

2

3

൰Ẓ㫩

൰Ẓ㫩

我使用了postDelayed()函数但是没关系!

 decrypt();
new Handler().postDelayed(new Runnable() {

    @Override
    public void run() {
    // TODO Auto-generated method stub

            getContentsFile();
            }
        }, 7000);

文件大小为80 Kilobytes!

它在模拟器上有问题!! 它在samsung gt-s7562上有问题,但是对于galaxy s4一切都还可以!!

2 个答案:

答案 0 :(得分:0)

我发现您的代码至少存在两个潜在的平台兼容性问题:

  1. 如果没有声明字符集,请不要致电getBytes()

    SecretKeySpec sks = new SecretKeySpec("MyDifficultPassw".getBytes(), "AES");
    

    应该是:(例如)

    SecretKeySpec sks = new SecretKeySpec(
        "MyDifficultPassw".getBytes("UTF-8"), "AES");
    
  2. 始终指定完整转换,例如“AES / CBC / PKCS5Padding”:

    Cipher cipher = Cipher.getInstance("AES");
    

    (例如)

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    
  3. 这可能是导致问题的原因。不同的平台具有不同的默认字符集,这意味着您将获得密钥的不同字节串。

    不常见的是,当您选择"AES"时,不同的加密提供程序具有不同的默认值。有些人会进行ECB模式加密,有些人会进行CBC模式加密。最准确地宣布你想要的是最安全的。


    旁注:你真的不应该从字符串的原始字节创建一个键。请改用密码派生方法,例如PBKDF2。

答案 1 :(得分:0)

我使用这两种方法进行加密/解密,它们可以在任何设备上完美地运行。它的完成方式略有不同,所以尝试比较两种方法,看看哪些方法可能有误。

加密

获取iv向量和要加密的message

public String getEncrypt(final byte[] iv, final String message) throws GeneralSecurityException, NullPointerException {
  if (key.isEmpty())
    throw new NullPointerException();

  final byte[] rawData = key.getBytes(Charset.forName("US-ASCII"));
  if (rawData.length != 16) {
    // If this is not 16 in length, there's a problem with the key size, nothing to do here
    throw new IllegalArgumentException("You've provided an invalid key size");
  }

  final SecretKeySpec seckeySpec = new SecretKeySpec(rawData, "AES");
  final Cipher ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");

  ciph.init(Cipher.ENCRYPT_MODE, seckeySpec, new IvParameterSpec(iv));

  byte[] encryptedBA = ciph.doFinal(message.getBytes(Charset.forName("US-ASCII")));
  try {
    final String encryptedText = new String(Base64.encode(encryptedBA, Base64.DEFAULT), "UTF-8");
    return encryptedText.toString();
  } 
  catch (final UnsupportedEncodingException e1) { }
  return "";
}

解密:

public String getDecrypt(final byte[] encrypted) throws GeneralSecurityException, NullPointerException {
  if (key.isEmpty())
    throw new NullPointerException();

  final byte[] rawData = key.getBytes(Charset.forName("US-ASCII"));
  if (rawData.length != 16) {
    // If this is not 16 in length, there's a problem with the key size, nothing to do here
    throw new IllegalArgumentException("Invalid key size.");
  }

  final SecretKeySpec seckeySpec = new SecretKeySpec(rawData, "AES");

  final Cipher ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");
  ciph.init(Cipher.DECRYPT_MODE, seckeySpec, new IvParameterSpec(new byte[16]));
  final byte[] decryptedmess = ciph.doFinal(encrypted);

  return new String(decryptedmess, Charset.forName("US-ASCII"));
}