Android,AES-GCM或普通AES上的数据加密?

时间:2012-11-16 15:58:12

标签: android encryption aes bouncycastle aes-gcm

我的团队需要开发一个解决方案,在用Java编写的Android应用程序的上下文中加密二进制数据(存储为byte[])。加密数据将以各种方式传输和存储,在此期间不能排除数据损坏。最终,另一个Android应用程序(再次用Java编写)将不得不解密数据。

已经确定加密算法必须是AES,密钥为256位。 但是,我想知道我们应该使用哪种AES实现和/或“模式”。我已经阅读了一些名为GCM模式的内容,我们已经对它进行了一些测试(使用BouncyCastle / SpongyCastle),但我并不完全清楚AES-GCM的用途是什么以及与普通相比它“购买”了什么AES - 以及是否需要考虑任何权衡因素。

以下是我们所关注/要求/问题的列表:

  • 填充:我们需要加密的数据并不总是128位的倍数,因此AES实现/模式应该添加填充,但仅在必要时添加。 我的印象是,javax.crypto.Cipher提供的简单AES实现不会这样做,但初始测试表明它确实如此。所以我猜测填充要求本身并没有理由采用GCM而不是“普通”AES。这是对的吗?

  • 身份验证:我们需要一种万无一失的方法来检测是否发生了数据损坏。但是,理想情况下,我们还希望检测何时使用不正确的密钥进行解密。因此,我们希望能够区分这两种情况。我最初考虑GCM的原因是由于这个Stackoverflow question,其中一个响应者似乎暗示使用AES-GCM可以实现这种区分,尽管他没有提供详细的解释(让我们单独的代码)。

  • 最大限度地减少开销:我们需要限制加密数据的存储和传输开销。因此,我们希望了解特定AES实施/模式的选择是否以及在何种程度上影响开销量。

  • 加密/解密性能虽然这不是主要问题,但我们想知道特定AES实施/模式的选择在多大程度上影响加密和解密性能,无论是CPU时间和内存占用。

提前感谢任何建议,澄清和/或代码示例。

编辑: delnan有帮助地指出没有“普通AES”这样的东西。所以澄清一下,我的意思是使用Java的内置AES支持 像这样:Cipher localCipher = Cipher.getInstance("AES");

1 个答案:

答案 0 :(得分:10)

2012年,答案是选择GCM,除非您有严重的兼容性问题。

GCM经过身份验证的加密模式。它一次性为您提供机密性(加密),完整性和身份验证(MAC)。

到目前为止,正常的操作模式是ECB(这是Java的默认设置),CBC,CTR,OFB和其他一些操作模式。他们都只提供加密。如果没有诚信,保密本身很少有用;必须以特别的方式将这些经典模式与完整性检查相结合。由于加密很难做到正确,通常这种组合是不安全的,比必要的慢,甚至两者兼而有之。

经验证的加密模式(最近)由密码学家创建以解决该问题。 GCM是最成功的之一:它已被NIST选中,效率高,无专利,并且可以携带其他经过身份验证的数据(即,保留的数据)清楚,但你可以验证真实性)。有关其他模式的说明,请参阅this excellent article of Matthew Green

引起你的担忧:

  • 填充:默认情况下,Java使用PKCS#7填充。这是有效的,但它常常容易受到padding oracle attacks的影响,MAC最好被PBKDF2击败。 GCM已嵌入MAC(称为GMAC)。

  • 身份验证: AES-GCM只接受一个AES密钥作为输入,而不是密码。它将告诉您AES密钥是否错误或有效负载是否已被篡改,但这些条件被视为一个。相反,您应该考虑使用适当的密钥派生算法(如bcrypt或{{3}})从密码中派生AES密钥。我不认为总是可以判断密码是否不正确或者有效负载是否已被修改,因为验证前者所需的数据总是会被破坏。您可以加密一个小的已知字符串(使用ECB AES),一起发送,并使用它来验证密码是否正确。

  • 最小化开销:在一天结束时,如果您需要身份验证,所有模式都会产生相同的开销(大约10-20个字节)。除非您使用非常小的有效负载,否则可以忽略这一点。

  • 性能:GCM相当不错,因为它是在线模式(无需缓冲整个有效负载,因此内存较少),可并行化并且它需要一个AES操作和每个明文块一个Galois乘法。像ECB这样的经典模式更快(每个块仅一个AES操作),但是 - 再次 - 您还必须考虑完整性逻辑,这可能最终比GMAC慢。

话虽如此,我们必须意识到GCM安全性依赖于良好的随机数生成来创建IV。