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

Mat*_*ias 8 encryption android bouncycastle aes aes-gcm

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

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

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

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

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

  • 最小化开销:我们需要限制加密数据的存储和传输开销.因此,我们希望知道特定AES实现/模式的选择是否以及在何种程度上影响开销量.

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

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

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

Squ*_*ree 10

在2012年,答案是去GCM,除非你有严重的兼容性问题.

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

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

验证加密模式(最近)由密码学家创建以解决该问题.GCM是最成功的之一:它已被NIST选中,效率高,无专利,并且可以携带额外的经过验证的数据(即,数据保持清晰,但您可以验证其真实性) .有关其他模式的描述,请参阅Matthew Green的这篇优秀文章.

提出你的担忧:

  • 填充:默认情况下,Java使用PKCS#7填充.这样可行,但它通常容易受到填充oracle攻击,这种攻击最好被MAC击败.GCM嵌入了一个MAC(称为GMAC).

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

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

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

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

  • 我不会使用SHA2进行密码派生.它太"快",因此对字典和彩虹攻击很敏感.具有随机盐和足够高的迭代次数的PBKDF2是优选的.我认为可以使用生成的密钥,哈希(即使使用SHA2)来获取检查值并将其发送(使用salt). (3认同)