当前位置: 首页 > 知识库问答 >
问题:

在AEAD GCM模式下篡改AES加密缓冲区时,AEADBadTagException不抛出

和弘博
2023-03-14

Java:Oracle JRE1.8.0_45

提供商:BC,BouncyCastle v1.52

我只是像这样做篡改,在byte[]已经包含加密数据和身份验证标记的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类的标准Java8文档中了解到,在AEAD GCM模式中,身份验证标记是在加密时创建的(这是因为我在末尾附加的加密输出字节[]中看到了它),并在解密时进行验证(我提供了加密的完整输出,包括16字节标记作为解密输入),如果标记不能用该数据进行验证(包括我现在不用但会用的AAD数据),它将抛出AEADBadTagException。在我的代码中,它不这样做。

这是对文档的错误理解吗?是否需要调用其他方法来“启用”这个抛出行为(我可以找到任何方法),或者BounceyCastle没有抛出它(我理解提供者需要实现加密类ISP,以便所有的行为都像Java8Docs密码类中描述的那样。

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

有人有额外的信息吗。TIA

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

共有1个答案

裴昕
2023-03-14

最初的帖子有两个正在讨论的问题。一个已经解决(AEADBadTagException),另一个仍然悬而未决(参见原始帖子中的Update29/aug)。

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

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

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

 类似资料:
  • 我试图在Android上使用javax.crypto.cipher使用AES-GCM对数据流进行块加密。据我所知,对于一个多部分的加密操作,可以使用cipher.update多次,并使用cipher.doFinal完成。但是,当使用aes/gcm/nopadding转换时,cipher.update拒绝将数据输出到提供的缓冲区,并返回0个写入字节。缓冲区在密码中建立,直到我调用。doFinal。这

  • 我们正在BigQuery表上进行流式插入。 我们希望在不更改表名的情况下更新表的模式。 例如,我们希望删除一列,因为它包含敏感数据,但是我们希望保持所有其他数据和表名不变。 我们的流程如下: 将原始表复制到临时表 删除原始表 使用原始表名和新架构创建新表。 用旧表的数据填充新表。 哭,因为最后(最多)90分钟的数据卡在流缓冲区中,未传输 如何避免最后一步?

  • 我实现了一个简单的Java实用程序类,使用aes/gcm/nopadding进行加密和解密。我使用这段代码: IV总是一个12字节数组,key是32字节数组,SecureRandom使用种子生成。我知道在不同的OS上SecureRandom是不同的,但是加密和解密是在同一个OS上执行的,所以应该没有问题。 是不是很线性,对吧?它在Windows上工作得很好,加密和破译返回相同的文本。然而,在Doc

  • 问题内容: 在编写用于OpenGL库的Matrix类时,我遇到了一个问题,即使用Java数组还是使用Buffer策略存储数据(JOGL为Matrix操作提供直接缓冲区复制)。为了对此进行分析,我编写了一个小型性能测试程序,该程序比较了Arrays vs Buffers和Direct Buffers上循环和批量操作的相对速度。 我想在这里与您分享我的结果(因为我发现它们很有趣)。请随时发表评论和/或

  • 我正在连载: 和反序列化:

  • 我正在将Scopus数据抓取到h2文件数据库中。数据中有超过46,000,000条记录,每条记录都被视为不同的,这意味着重复数百GB的数据(因此是关系数据库)。为了减少所有这些数据的插入时间,我最初创建了一组没有约束的临时表,然后使用SELECT DISTINCT和GROUP BY将数据复制到真实表中以强制执行唯一性。 唯一的例外是“文档”( documents)表格和“参考文档”( refere