简体   繁体   English

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

[英]encrypt/decrypt file and Incorrect data

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();
}   

I am using these functions for encrypt/ decrypt file, but on some devices I get incorrect data. 我正在使用这些功能来加密/解密文件,但是在某些设备上我得到了不正确的数据。

for example, my correct data is : 例如,我的正确数据是:

one

two

three

four

five

after decrypt : 解密后:

one

two

three

൰Ẓ㫩 ൰Ẓ㫩

൰Ẓ㫩 ൰Ẓ㫩

I have used postDelayed() function But it did not matter ! 我已经使用了postDelayed()函数,但这没关系!

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

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

            getContentsFile();
            }
        }, 7000);

the file size is 80 Kilobytes! 文件大小为80千字节!

it had problem on emulator!! 在模拟器上有问题!! it had problem on samsung gt-s7562, but on galaxy s4 everything is ok !! 它在三星GT-S7562上有问题,但在银河S4上一切正常!

I see at least two potential platform compatibility issues with your code: 我发现您的代码至少存在两个潜在的平台兼容性问题:

  1. Never call getBytes() without declaring a charset: 在未声明字符集的情况下,切勿调用getBytes()

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

    should be: (eg) 应该是:(例如)

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

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

    should be (eg) 应该是 (例如)

     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 

This alone could be the cause of your problem. 仅此一个可能是您的问题的原因。 Different platforms have different default character sets, which means you would get a different string of bytes for your key. 不同的平台具有不同的默认字符集,这意味着您将为密钥获得不同的字节字符串。

Less commonly, different crypto providers have different defaults when you selet "AES" . 不太常见的是,当您选择"AES"时,不同的加密提供程序具有不同的默认值。 Some will do ECB-mode encryption, some will do CBC-mode encryption. 有些将执行ECB模式加密,有些将进行CBC模式加密。 It's always safest to declare exactly what you want. 确切地声明您想要的东西总是最安全的。


Side note: you really shouldn't be creating a key from the raw bytes of a string. 旁注:您实际上不应该从字符串的原始字节创建键。 Use a password derivation method instead, such as PBKDF2. 请改用密码派生方法,例如PBKDF2。

I'm using these two methods for encrypt/decrypt and they work perfectly to me on any device. 我正在使用这两种方法进行加密/解密,它们对我在任何设备上都能正常工作。 It's done a slightly different way than you so try comparing both approaches to see what could be working wrong. 它的执行方式与您稍有不同,因此请尝试比较两种方法以查看可能出了什么问题。

For encryption : 对于加密

Gets : iv vector and the message to encrypt: 获取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 "";
}

For decryption: 对于解密:

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"));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM