Java 让AES/GCM使用密码时遇到问题

Java 让AES/GCM使用密码时遇到问题,java,encryption,cryptography,Java,Encryption,Cryptography,我正在尝试使用Java的加密库来实现使用GCM模式的AES加密(因为这是一个AEAD方案,我希望确保数据完整无缺地到达),但为了方便用户,我希望使用密码。让程序无误地编译是一件困难的事情,直到我把头撞在砖墙上读了几遍 现在,不幸的是,程序可以编译,但它返回的密文只是消息中字节数的一小部分(我怀疑GCM使用的只是头,而实际的消息根本没有被写入)。有人能帮忙吗 以下是一些程序变量: private static final byte[] SALT = {(byte)0x3b,(byte)0x12,(

我正在尝试使用Java的加密库来实现使用GCM模式的AES加密(因为这是一个AEAD方案,我希望确保数据完整无缺地到达),但为了方便用户,我希望使用密码。让程序无误地编译是一件困难的事情,直到我把头撞在砖墙上读了几遍

现在,不幸的是,程序可以编译,但它返回的密文只是消息中字节数的一小部分(我怀疑GCM使用的只是头,而实际的消息根本没有被写入)。有人能帮忙吗

以下是一些程序变量:

private static final byte[] SALT = {(byte)0x3b,(byte)0x12,(byte)0x44,(byte)0x61,
        (byte)0xec,(byte)0xc0,(byte)0xa1,(byte)0x82,
        (byte)0x4d, (byte)0x97, (byte)0x4d, (byte)0x3c,
        (byte)0x57, (byte)0xd9, (byte)0x94, (byte)0x52};

private static final String CIPHER_ALG = "AES/GCM/PKCS5Padding";
private static final String SEC_RANDOM_ALG = "SHA1PRNG";
private static final String S_KEY_FACTORY_ALG = "PBKDF2WithHmacSHA1";

private static final int AES_KEY_SIZE = 128; //num bits
private static final int GCM_NONCE_LENGTH = 16; //num bytes
private static final int GCM_TAG_LENGTH = 16; //num bytes
private static final int KEY_SPEC_ROUNDS = 65536;
下面是加密方法:

//FIXME somehow the cipher is truncating the message or something
private byte[] encrypt(File file, String password) throws IOException{

    Path path = Paths.get(file.toURI());
    byte[] messageBytes = Files.readAllBytes(path);
    //Message bytes: 3253
    System.out.printf("Message bytes: %d%n", messageBytes.length);
    byte[] messageName = path.getFileName().toString().getBytes();

    byte[] cipherBytes = {};
    byte[] iv = {};
    try{

        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(S_KEY_FACTORY_ALG);
        PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray(), SALT, KEY_SPEC_ROUNDS, AES_KEY_SIZE);
        SecretKey key = keyFactory.generateSecret(pbeKeySpec);
        System.out.printf("Secret key take 1: " + Arrays.toString(key.getEncoded()) + "%n");

        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getEncoded(), "AES");

        //FIXME this is not encrypting the message correctly
        Cipher cipher = Cipher.getInstance(CIPHER_ALG);
        final byte[] nonce = new byte[GCM_NONCE_LENGTH];
        SecureRandom random = SecureRandom.getInstanceStrong();
        random.nextBytes(nonce);
        GCMParameterSpec paramSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, nonce);
        iv = paramSpec.getIV();

        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, paramSpec);
        cipher.updateAAD(messageName);
        cipher.update(messageBytes);
        cipherBytes = cipher.doFinal();

    }catch(NoSuchAlgorithmException e){
        e.printStackTrace();
    }catch(NoSuchPaddingException e){
        e.printStackTrace();
    }catch(InvalidKeyException e){
        e.printStackTrace();
    }catch(InvalidAlgorithmParameterException e){
        e.printStackTrace();
    }catch(InvalidKeySpecException e){
        e.printStackTrace();
    }catch(BadPaddingException e){
        e.printStackTrace();
    }catch(IllegalBlockSizeException e){
        e.printStackTrace();
    }

    //IV bytes: 16
    System.out.printf("IV bytes: %d%n", iv.length);
    //Cipher bytes: 21
    System.out.printf("Cipher bytes: %d%n", cipherBytes.length);
    //Cipher bytes: [121, 68, 7, -69, -35, -9, -83, 101, -60, -80, 42, 59, -67, 126, 18, -82, 79, -60, 34, -125, 12]
    System.out.printf("Cipher bytes: " + Arrays.toString(cipherBytes) + "%n");

    //FIXME somehow the cipher is shortening the message or something
    return cipherBytes;
}

不应忽略
cipher.update(messageBytes)的返回值。此外,GCM在下面使用CTR模式。CTR模式不需要填充,因此您应该使用
“AES/GCM/NoPadding”


此时,您可能正在取回密文的最后一部分和身份验证标记(即尾部而不是头部)。

您可能想看看我关于加密相关异常的介绍。那么我是否应该将返回值导入cipher.doFinal()方法?或者我可以跳过这一行,直接调用cipher.doFinal(messageBytes);我想也是这样。