Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/210.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java AES在保存并再次解密后解密不同的结果_Java_Encryption_Aes - Fatal编程技术网

Java AES在保存并再次解密后解密不同的结果

Java AES在保存并再次解密后解密不同的结果,java,encryption,aes,Java,Encryption,Aes,当我运行scrypt时,我的第一个解密结果是正确的: 兄弟人群意味着古家伙在完美面前要求社会 怒不可遏 当我保存encryptedText、salt(例如,保存到数据库)并想再次解密时,我得到了这个结果 �Ŝ�,&6.���;�M�一个古代人要求社会在完美之前怒目而视 *更新 我认为问题在于我处理数据的方式(salt和iv)。现在我可以加密和保存-encryptText,randomIV,randomSalt到数据库,并用masterPassword对其进行解密而不会出现问题 谢谢大家的帮助,你

当我运行scrypt时,我的第一个解密结果是正确的:

兄弟人群意味着古家伙在完美面前要求社会 怒不可遏

当我保存encryptedText、salt(例如,保存到数据库)并想再次解密时,我得到了这个结果

�Ŝ�,&6.���;�M�一个古代人要求社会在完美之前怒目而视

*更新 我认为问题在于我处理数据的方式(salt和iv)。现在我可以加密和保存-encryptText,randomIV,randomSalt到数据库,并用masterPassword对其进行解密而不会出现问题

谢谢大家的帮助,你太棒了

*编辑代码后,我得到了这个解决方案

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
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.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class Aes { 
private static int pswdIterations = 65536;
private static int keySize =  256;

public static String encrypt(String plainText, String password, String salt, String initializationVector) throws 
    NoSuchAlgorithmException, 
    InvalidKeySpecException, 
    NoSuchPaddingException, 
    InvalidParameterSpecException, 
    IllegalBlockSizeException, 
    BadPaddingException, 
    UnsupportedEncodingException, 
    InvalidKeyException, 
    InvalidAlgorithmParameterException 
{   
    byte[] saltBytes = salt.getBytes("UTF-8");
    byte[] ivBytes = initializationVector.getBytes("UTF-8");

    // Derive the key, given password and salt.
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec spec = new PBEKeySpec(
            password.toCharArray(), 
            saltBytes, 
            pswdIterations, 
            keySize
    );

    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(ivBytes));

    byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
    return new Base64().encodeAsString(encryptedTextBytes);
}

    public static String decrypt(String encryptedText, String password, String salt, String initializationVector ) throws 
    NoSuchAlgorithmException, 
    InvalidKeySpecException, 
    NoSuchPaddingException, 
    InvalidKeyException, 
    InvalidAlgorithmParameterException,
    UnsupportedEncodingException
{
    byte[] saltBytes = salt.getBytes("UTF-8");
    byte[] ivBytes = initializationVector.getBytes("UTF-8");
    byte[] encryptedTextBytes = new Base64().decodeBase64(encryptedText);

    // Derive the key, given password and salt.
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec spec = new PBEKeySpec(
            password.toCharArray(), 
            saltBytes, 
            pswdIterations, 
            keySize
    );

    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

    // Decrypt the message, given derived key and initialization vector.
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivBytes));

    byte[] decryptedTextBytes = null;
    try {
        decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    }

    return new String(decryptedTextBytes);
   }  

    public String generateSalt() {
        SecureRandom random = new SecureRandom();
        byte bytes[] = new byte[16];
        random.nextBytes(bytes);
        String s = new String(bytes);
        return s;
    }

    public String generateIV(String chars, int length) {
    Random rand = new Random();
    StringBuilder buf = new StringBuilder();
    for (int i=0; i<length; i++) {
      buf.append(chars.charAt(rand.nextInt(chars.length())));
    }
    return buf.toString();
    }

    }

您的代码可以加密A和解密A,但不能加密A、加密B和解密A。 因为加密A时的salt和初始化向量在加密B时被覆盖。 我不知道你想归档什么。我留下了一个可用的代码示例

import java.security.AlgorithmParameters;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class AESDemo {

    private static final String password = "test";
    private static String salt;
    private static int pswdIterations = 65536;
    private static int keySize = 256;
    //read from DB
    private byte[] ivBytes = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

    public String encrypt(String plainText) throws Exception {

        // get salt
        if (salt == null)
            salt = generateSalt();
        byte[] saltBytes = salt.getBytes("UTF-8");

        // Derive the key
        SecretKeyFactory factory = SecretKeyFactory
                .getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes,
                pswdIterations, keySize);

        SecretKey secretKey = factory.generateSecret(spec);
        SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

        // encrypt the message
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(ivBytes));
        byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));

        return new Base64().encodeAsString(encryptedTextBytes);
    }

    @SuppressWarnings("static-access")
    public String decrypt(String encryptedText) throws Exception {

        byte[] saltBytes = salt.getBytes("UTF-8");
        byte[] encryptedTextBytes = new Base64().decodeBase64(encryptedText);

        // Derive the key
        SecretKeyFactory factory = SecretKeyFactory
                .getInstance("PBKDF2WithHmacSHA1");
        PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes,
                pswdIterations, keySize);

        SecretKey secretKey = factory.generateSecret(spec);
        SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

        // Decrypt the message
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secret,
                new IvParameterSpec(ivBytes));

        byte[] decryptedTextBytes = null;
        try {
            decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }

        return new String(decryptedTextBytes);
    }

    public String generateSalt() {
        //get the salt from DB
        return "I hate salt";
    }
}

public class stackoverflow_test {

    public static void main(String[] ag) throws Exception{
        AESDemo d = new AESDemo();

        System.out.println("Encrypted string:" + d.encrypt("brother crowd mean guy ancient demand society before perfection glare anger certain"));           
        String encryptedText = d.encrypt("brother crowd mean guy ancient demand society before perfection glare anger certain");
        String encryptedText2 = d.encrypt("Hello World");
        System.out.println("Decrypted string:" + d.decrypt(encryptedText2));        
        System.out.println("Decrypted string:" + d.decrypt(encryptedText));         

    }
}
结果

Encrypted string:c7NXCBiq7tqzon39iPtkQLJ0chuXudS5oVDPdAr5S3q1245d3uJUVcyNUY77rpGeNvOp9hOldhiOM8mp2C/aOqqNyXx82zJt2V2EFtQkauCl/oY2EMENh1jCR6Nqf1lJ
Decrypted string:Hello World
Decrypted string:brother crowd mean guy ancient demand society before perfection glare anger certain

你的代码有一些不同的问题。首先是你如何产生盐

SecureRandom random = new SecureRandom();
byte bytes[] = new byte[20];
random.nextBytes(bytes);
String s = new String(bytes);
return s;
您正在获取随机数据并试图将其转换为字符串,但字符串构造函数并不只需要任何随机数据,它需要某种编码的文本字符串(UTF-8、UTF-16或其他)。如果对二进制数据进行编码,则只能将其转换为字符串,我只需返回
字节
数组即可

public byte[] generateSalt(int length) {
    SecureRandom random = new SecureRandom();
    byte bytes[] = new byte[length];
    random.nextBytes(bytes);
    return bytes;
}
接下来,很难说为什么您的输出以您所述的特定方式解密(只有第一个块损坏),但我敢打赌,这与将IV保存到数据库时对其进行错误编码有关。更好的解决方案是在加密数据中预先添加salt和IV,然后在需要解密时将其剥离

public String encrypt(String plainText) throws Exception {   
    //get salt    
    byte[] saltBytes = generateSalt(saltLength);

    // Derive the key
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, pswdIterations, keySize);

    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

    //encrypt the message
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret);
    AlgorithmParameters params = cipher.getParameters();
    byte[] ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
    byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));

    //prepend the salt and IV
    byte[] buffer = new byte[saltBytes.length + ivBytes.length + encryptedTextBytes.length];
    System.arraycopy(saltBytes, 0, buffer, 0, saltBytes.length);
    System.arraycopy(ivBytes, 0, buffer, saltBytes.length, ivBytes.length);
    System.arraycopy(encryptedTextBytes, 0, buffer, saltBytes.length + ivBytes.length, encryptedTextBytes.length);
    return new Base64().encodeToString(buffer);
}

public String decrypt(String encryptedText) throws Exception {

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

    //strip off the salt and IV
    ByteBuffer buffer = ByteBuffer.wrap(new Base64().decode(encryptedText));
    byte[] saltBytes = new byte[saltLength];
    buffer.get(saltBytes, 0, saltBytes.length);
    byte[] ivBytes = new byte[cipher.getBlockSize()];
    buffer.get(ivBytes, 0, ivBytes.length);
    byte[] encryptedTextBytes = new byte[buffer.capacity() - saltBytes.length - ivBytes.length];
    buffer.get(encryptedTextBytes);

    // Derive the key
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, pswdIterations, keySize);

    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
    cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivBytes));

    byte[] decryptedTextBytes = null;
    try {
        decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    }

    return new String(decryptedTextBytes);
}

每次加密一段数据时使用新的IV非常重要,因为它似乎存在编码问题。请尝试UTF-16。如果只使用普通ASCII字符,则不会出现这种情况。数据库使用什么编码?保存或检索数据时似乎存在问题。你能显示相应的代码吗?即使我不把它保存到数据库,它也有这个问题。当我从控制台中取出salt字符串和加密字符串并解密时,它也会显示无法读取的内容^^^但是为什么80%的文本都可以,只是开头不可以?你应该一次生成salt和IV,保密,在做新的加密时,并没有同时生成这两个。是的,我的注意力是生成一个随机的salt和iv。在上面的解决方案中修复了它。谢谢。但有了你的解决方案,我无法做到这一点。System.out.println(“解密字符串:+d.decrypt(06scBq7GNv+jjJPpsJdOm+1mIdaWrk/SH2LO5YIWVAQYIFO6GMQ8ANULOYLWLJQJW4NUUXRVRVLN5YP/OikicB9H/DMU7TGZ5PPV8YPQTOYDK823MEOE5N0T084CWV)”;例如,我想将加密和种子保存在db中,而不是解密。我修改了代码,使IV和salt在代码中是一个常量。这样,您只需要将加密文本保存在db中,当然也可以将IV和salt保存在db中,并在代码启动时读取。@tom87416使用固定IV是一种安全措施,因为它会打开known文本攻击和使用固定的salt(通常)会使您容易受到rainbow表的攻击。
public String encrypt(String plainText) throws Exception {   
    //get salt    
    byte[] saltBytes = generateSalt(saltLength);

    // Derive the key
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, pswdIterations, keySize);

    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

    //encrypt the message
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secret);
    AlgorithmParameters params = cipher.getParameters();
    byte[] ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
    byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));

    //prepend the salt and IV
    byte[] buffer = new byte[saltBytes.length + ivBytes.length + encryptedTextBytes.length];
    System.arraycopy(saltBytes, 0, buffer, 0, saltBytes.length);
    System.arraycopy(ivBytes, 0, buffer, saltBytes.length, ivBytes.length);
    System.arraycopy(encryptedTextBytes, 0, buffer, saltBytes.length + ivBytes.length, encryptedTextBytes.length);
    return new Base64().encodeToString(buffer);
}

public String decrypt(String encryptedText) throws Exception {

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

    //strip off the salt and IV
    ByteBuffer buffer = ByteBuffer.wrap(new Base64().decode(encryptedText));
    byte[] saltBytes = new byte[saltLength];
    buffer.get(saltBytes, 0, saltBytes.length);
    byte[] ivBytes = new byte[cipher.getBlockSize()];
    buffer.get(ivBytes, 0, ivBytes.length);
    byte[] encryptedTextBytes = new byte[buffer.capacity() - saltBytes.length - ivBytes.length];
    buffer.get(encryptedTextBytes);

    // Derive the key
    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, pswdIterations, keySize);

    SecretKey secretKey = factory.generateSecret(spec);
    SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
    cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivBytes));

    byte[] decryptedTextBytes = null;
    try {
        decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    }

    return new String(decryptedTextBytes);
}