Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/367.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 AEADBadTagException不';在AEAD GCM模式下篡改AES加密缓冲区时不会抛出_Java_Cryptography_Aes_Bouncycastle_Aes Gcm - Fatal编程技术网

Java AEADBadTagException不';在AEAD GCM模式下篡改AES加密缓冲区时不会抛出

Java AEADBadTagException不';在AEAD GCM模式下篡改AES加密缓冲区时不会抛出,java,cryptography,aes,bouncycastle,aes-gcm,Java,Cryptography,Aes,Bouncycastle,Aes Gcm,Java:OracleJRE1.8.045 提供商:BC,BouncyCastle v1.52 密码:AES 256bit密钥(已安装安全策略) AEAD模式:GCM 算法:AES/GCM/NOP 我有一个完美的AES加密/解密,参数如上所示。然后在调试期间,我添加了一个简单的篡改模拟,在解密之前更改加密缓冲区中的数据。我期望抛出AEADBadTagException,但它没有发生。我还没有使用任何upedatad(),我们讨论的是纯加密数据的付费负载 我只是这样做篡改,在字节[]已经包含加密数

Java:OracleJRE1.8.045

提供商:BC,BouncyCastle v1.52

密码:AES 256bit密钥(已安装安全策略)

AEAD模式:GCM

算法:AES/GCM/NOP

我有一个完美的AES加密/解密,参数如上所示。然后在调试期间,我添加了一个简单的篡改模拟,在解密之前更改加密缓冲区中的数据。我期望抛出AEADBadTagException,但它没有发生。我还没有使用任何upedatad(),我们讨论的是纯加密数据的付费负载

我只是这样做篡改,在字节[]已经包含加密数据和身份验证标记的16个额外字节之后,我覆盖字节[]的第一个字节

// set-up for encryption, key, IV, etc...
...
try
{
  String sPlainText="The non-encrypted (AES) message.";    
  byte[] baEncrypted=oCIPH.doFinal(sPlainText.getBytes());

  MetaLogbook.info(baEncrypted); // Shows well encrypted buffer

  // Tampering simulations
  baEncrypted[0]=0x67;

  // re-initialize for decryption, same key and IV...

  String sDecryptedText=new String(oCIPH.doFinal(baEncrypted),"UTF-8");
  MetaLogbook.info(sDecryptedText);

  // The above log line shows the plain text with a different first letter
  // each time that i change 0x67 in other values. The rest of the message
  // matches the plain text on input. I can see the 16 extra bytes of the 
  // authentication tag appended to the clear text.
}
catch(Exception e)
{
  // I expected to come here due to a AEADBadTagException but I never 
  // come here.
  MetaLogbook.error(e);
}
当我在模拟篡改时更改分配的值时,得到的解密文本在第一个字符处更改。它以非线性方式变化。0x65产生一个“c”,0x67产生一个“?”等等。普通消息的其余部分保持正确,只有解密输出的第一个字符似乎受到影响

我从Cipher类的标准Java 8文档中了解到,在AEAD GCM模式下,身份验证标记是在加密时创建的(这是因为我在末尾附加的加密输出字节[]中看到了它),并在解密时进行验证(我提供了完整的加密输出,包括16字节标记作为解密输入)如果标记不使用该数据(包括我现在不使用但会使用的AAD数据)进行验证,它将抛出AEADBadTagException。在我的代码中,它不这样做

我用16字节倍数的数据和非16字节倍数的数据进行了尝试。两者的结果相同。如果使用相同的篡改(0x67)值,则如果消息变长,纯文本输出中的第一个字母将发生更改,但这是有意义的。如果我向消息中添加一些字节,使其不是16的倍数,则所述错误的第一个字符“c”将变为“6”。在使用的AES/GCM/NOP中,无论如何,添加长度不能是16的倍数

这是否是对文档的错误理解,是否需要调用其他方法来“启用”此抛出行为(我可以找到任何方法),或者BounceyCastle没有抛出它(我了解提供商需要实现加密类ISP,以便一切都按照Java 8 Docs Cipher类中的描述运行)

我无法与SunJCE提供程序进行比较,因为它不支持AES/GCM/NoPadding

有人有额外的信息吗。 短暂性脑缺血发作

8月29日更新:添加代码以显示相同的代码与SunJCE抛出,而不是与BC provider抛出,这是评论中讨论的一部分

private static void testing()
{
  try
  {
    // Unremark these lines to see it work
    //Security.addProvider(new BouncyCastleProvider()); // "BC"
    //Cipher oCIPH=Cipher.getInstance("AES/GCM/NoPadding", "BC");

    // Unremark these lines to see it fail
    Cipher oCIPH=Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); 

    // Make a quick and dirty IV and Symmetric Key
    byte[] baIV="EECE34808EF2A9AC".getBytes("UTF-8");
    byte[] baKey="010F05E3E0104EB59D10F37EA8D4BB6B".getBytes("UTF-8");

    // Make IV and Key (well KeySpec for AES) object. Use IV parspec because
    // defaults to 128bit Authentication tag size & works in both GCM & CBC.
    IvParameterSpec ps=new IvParameterSpec(baIV);
    SecretKeySpec sk=new SecretKeySpec(baKey,"AES");

    // Unremakr one line, either shrtline (multiple of 16 bytes) or long line   
    //String sPlainText="The non-encrypted (AES) message.";
    String sPlainText="The non-encrypted (AES) message. Everything after the . makes this NOT a multiple of 16 bytes.";

    // Encrypt
    oCIPH.init(Cipher.ENCRYPT_MODE, sk, ps);
    byte[] baEncrypted=oCIPH.doFinal(sPlainText.getBytes());

    // Decrypt
    oCIPH.init(Cipher.DECRYPT_MODE, sk, ps);
    String sDecryptedText=new String(oCIPH.doFinal(baEncrypted),"UTF-8");        
  }
  catch(Exception e)
  {
    MetaLogbook.log("Security Tools Exception",e);
  }
} 
上面的代码可以使用SunJCE或BouncyCastle运行,方法是取消标记顶部需要的行。在BC中,这些代码运行并执行预期的操作。如果未标记SunJCE提供程序,则会引发错误:

类java.security.InvalidalgorithParameterException:不支持 参数:javax.crypto.spec。IvParameterSpec@4fccd51b com.sun.crypto.provider.CipherCore.init(CipherCore.java:509) com.sun.crypto.provider.aesciper.engineInit(aesciper.java:339) javax.crypto.Cipher.init(Cipher.java:1394)javax.crypto.Cipher.init (Cipher.java:1327)


原始帖子讨论了两个问题。一个问题已经解决(AEADBadTagException),另一个问题仍然悬而未决(见原始帖子中的8月29日更新)

解决的问题是: 我最近不得不为使用AES的Key/SecretKey类编写异常代码,以使用SecretKeySpec。更改导致了一个错误,影响了代码所遵循的路径,现在在搜索AEADBadTagException的非抛出的上下文中得到了纠正。事实上,所有其余部分都继续工作是因为flow更改导致两次初始化以进行加密,而不是第二次解密。 我不明白的是,解密无论如何都能正常工作。AES是一种对称算法,但它有一个S盒和一个反向S盒,因此人们会认为加密不能像DES这样的完全对称密码那样仅仅用来代替解密

第二个问题仍然悬而未决:

类java.security.invalidalgorithParameterException:不支持的参数:javax.crypto.spec。IvParameterSpec@4fccd51b

只需选择代码顶部的提供程序,其余部分保持不变,就可以由提供的代码复制。该代码适用于BC,而不适用于SunJCE

我看到您自己的日志代码中可能有一行Metalogbook代码需要更改

尽管SunJCE提供者不是我用于加密的提供者,而且就我而言,GCM问题已经解决,但如果需要的话,我将继续关注这个问题,为SunJCE抛出提供更多信息


更新:通过进一步挖掘,我发现了IVParamSpec抛出的问题。BC接受CBC和GCM的此对象,并将身份验证标记默认为128位。另一方面,SunJCE特别需要GCMParamSpec对象和GCM的身份验证标记的显式大小,并接受CBC的IVParamSpec,但不接受t代表GCM。

GCM由普通Java 8 JRE支持。真的,这里发生了什么?我真的怀疑这是一个非常草率的实现。每一个AES GCM代码都可以用一行,即回火注释上的一行来验证这一点。草率的实现?它对所有其他代码都是100%有效的。如果添加tamp,就不会抛出一个异常模拟。如果有人可能有相同的问题,或者通过在加密缓冲区中覆盖一个字节而用一行代码创建问题,那么为什么要关闭此问题。@Maarten,该算法在SunJCE中确实受支持,但相同的代码在BC中工作,而不在SunJCE提供程序中工作(抛出不支持的参数:javax.crypto.spec)。IvParameterSpec@cc62a