如何使用Android的身份验证标签进行GCM加密 [英] How to make GCM Encrypt with authentication tag for Android

查看:137
本文介绍了如何使用Android的身份验证标签进行GCM加密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想让一个函数通过带有Android身份验证标签的GCM模式加密数据。
这是我的源代码:

I want to make a function encrypt data by GCM mode with authentication tag for Android. This is my source code:

public static byte[] GCMEncrypt(String hexKey, String hexIV, byte[] aad) throws Exception {
        byte[] aKey = hexStringToByteArray(hexKey);
        byte[] aIV = hexStringToByteArray(hexIV);
        Key key = new SecretKeySpec(aKey, "AES");
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(16 * Byte.SIZE, aIV));
        cipher.updateAAD(aad);
        byte[] encrypted = cipher.doFinal(aKey);
        return encrypted;
    }

如何在此代码中插入身份验证标签?

How to insert authentication tag into this code?

推荐答案

您已经包含了身份验证标签。 Java(不幸的是-参见下文)在密文中包含了身份验证标签。这意味着它是在最后一次调用 doFinal 时生成的。

You already have included the authentication tag. Java (unfortunately - see below) includes the authentication tag in the ciphertext. That means that it is generated during that last call to doFinal.

您可以通过查看大小轻松地检查它密文。它的大小应与纯文本的大小相同(在本例中为 aKey )加上128位,即身份验证标签的默认大小和合理大小。

You can easily check this by viewing the size of the ciphertext. It should be the same size as the plaintext (in this case aKey) plus 128 bits, the default and sensible size of the authentication tag.

这也是为什么 AEADBadTagException 是从 BadPaddingException 派生的原因:在解密过程中会进行验证<暗中。因此,较早的代码仍将与GCM模式兼容。

This is also why AEADBadTagException is derived from BadPaddingException : during decryption the verification takes place implicitly. So older code would still be compatible with GCM mode.

正如我之前指出的,我认为在密文中包括身份验证标签是API的主要设计错误:

As I indicated earlier I think including the authentication tag in the ciphertext is a major design mistake for an API:


  • 它不允许用户将身份验证标签放置在其他地方-至少不使用数组(大小)操作;

  • 它删除了GCM的 online 性质,在这种情况下,纯文本的解密是即时的(对于每个更新调用),因为需要缓存身份验证标签;

  • 如果预先知道身份验证标签的位置(即,如果协议指定了标签位置或密文的大小),它将使代码变大,效率降低,并需要进行虚假缓冲直接);

  • it doesn't allow the user to place the authentication tag elsewhere - at least without array (size) manipulation;
  • it removes the online nature of GCM where decryption of plaintext is instantaneous (for each call to update) as the authentication tag needs to be buffered;
  • it makes the code larger, less efficient and requires spurious buffering if the location of the authentication tag is known in advance (i.e. if the protocol specifies the tag location or the size of the ciphertext directly);

在我看来,这并不能弥补 Cipher的优势类,而无需添加方法并保持兼容性。如果设计者只是添加了分别检索和验证身份验证标签的方法,那就更好了。

In my opinion that doesn't weigh up to the advantages of retrofitting the Cipher class without adding methods and maintaining compatibility. It would have been better if the designer had just added methods for retrieving and verifying the authentication tag separately.

因为当前正在下雨,我创建了一个示例:

Because it is currently raining I have created an example:

public static void main(String... args) throws Exception {
    int tagSize = 96;

    Cipher gcm = Cipher.getInstance("AES/GCM/NoPadding");

    SecretKey aesKey = new SecretKeySpec(new byte[16], "AES");

    GCMParameterSpec gcmSpec = new GCMParameterSpec(tagSize, new byte[gcm.getBlockSize()]);

    gcm.init(Cipher.ENCRYPT_MODE, aesKey, gcmSpec);

    byte[] pt = "Maarten Bodewes creates code".getBytes(StandardCharsets.UTF_8);
    System.out.println(pt.length);
    byte[] ctAndTag = new byte[gcm.getOutputSize(pt.length)];

    System.out.println(ctAndTag.length);

    int off = 0;
    off += gcm.update(pt, 0, pt.length, ctAndTag, off);
    // prints 16 (for the Oracle crypto provider)
    // meaning it is not online, buffering even during encryption
    System.out.println(off);
    off += gcm.doFinal(new byte[0], 0, 0, ctAndTag, off);
    // prints 40 for the Oracle crypto provider, meaning it doesn't *just*
    // output the tag during doFinal !
    System.out.println(off);

    int ctSize = ctAndTag.length - tagSize / Byte.SIZE;
    System.out.println(ctSize);

    byte[] ct = Arrays.copyOfRange(ctAndTag, 0, ctSize);
    byte[] tag = Arrays.copyOfRange(ctAndTag, ctSize, ctAndTag.length);

    System.out.println(Hex.toHexString(ct));
    System.out.println(Hex.toHexString(tag));
}






注意:


Notes:


  • 用自身加密密钥没有任何意义,我希望这只是出于演示目的

  • 对于较小的身份验证标签,GCM很快就会失去安全性,除非建议您明确为其设计协议,否则不建议更改其大小。

这篇关于如何使用Android的身份验证标签进行GCM加密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆