我可以使用具有SkippingCipher接口的任何内容解密Bouncy Castle中的GCM AES流吗? [英] Can I decrypt GCM AES stream in Bouncy Castle using anything having SkippingCipher interface?

查看:128
本文介绍了我可以使用具有SkippingCipher接口的任何内容解密Bouncy Castle中的GCM AES流吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有Bouncy Castle(本机API)的有效AES GCM解决方案,该解决方案公开了流接口( CipherInputStream 类)。我知道GCM模式可以像点击率一样,因此,如果我不需要身份验证,我应该能够从随机位置解密流(如果我知道位置),但是模式是什么我可以使用密码来解密AES / GCM流并具有 SkippingCipher 接口吗?

I have working AES GCM solution with Bouncy Castle (native API) exposing stream interface (CipherInputStream class). I know that GCM mode can be considered like CTR one so if I do not need authentication I should be able to decrypt stream from random place (if I know position) but what mode cipher can I use so it can decrypt AES/GCM stream and have SkippingCipherinterface?

任何相关的代码示例都可以甚至更好。

Any related code example would be even better.

推荐答案

这是我根据有问题的建议和示例并基于其得出的代码片段。我没有发布 import 部分,但这很简单。另外,由于客户端知道内容长度,因此我不处理数据身份验证标签(流的最后16个字节)。是的,我知道忽略标签是不好的,但是我需要流媒体访问和随机访问。最后,当我不需要随机访问时(实际上就是这种情况),没有人阻止我使用其他解密方法。

Here is the code fragment I have resulted based on the advice and examples referred in question and around it. I do not post import section but it is trivial. Also I do not deal with data authentication tag (last 16 bytes of the stream) as client knows the content length. Yes, I know ignoring tag is bad but I need both streaming and random access. At the end nobody prevents me from other decryption approach when I do not need random access (which is actually the case).

方法 createGcmStreamDecryptor() (公开一)结果块密码,实际上是CTR密码包装AES。作为输入,它将IV用于GCM密码并适当地进行转换。在我的情况下,IV的长度为16个字节,但它可以在Bouncy Castle方法起作用的任何地方使用。我已经尽可能多地重用了BC,包括 GCMUtil 类。

Method createGcmStreamDecryptor() (public one) results block cipher which is actually CTR cipher wrapping AES. As an input it takes IV intended for GCM cipher and converts it appropriately. In my case IV length is 16 bytes but it will work on anything where Bouncy Castle approach works. I have reused BC as much as possible including GCMUtil class.

// AES block size in bytes.
private static final int AES_BLOCK_SIZE = 16;

// Default (recommended) GCM IV size.
private static final int GCM_DEFAULT_IV_SIZE = 12;


// Perform 'inc32' operation on CTR counter.
private static byte inc32(byte[] counter) {
    for (int i = counter.length - 1; i >= 0; i--) {
        if (++counter[i] != 0) {
            return 0;
        }
    }
    return 1;
}

// Get GCM gHASH function result.
private static void gHASHPartial(
        final GCMMultiplier multiplier, byte[] Y, byte[] b, int off, int len) {
    GCMUtil.xor(Y, b, off, len);
    multiplier.multiplyH(Y);
}

// Get GCM gHASH function result.
private static void gHASHBlock(
        final GCMMultiplier multiplier, byte[] Y, byte[] b) {
    GCMUtil.xor(Y, b);
    multiplier.multiplyH(Y);
}

// Get GCM gHASH function result.
private static void gHASH(
        final GCMMultiplier multiplier, byte[] Y, byte[] b, int len) {
    for (int pos = 0; pos < len; pos += AES_BLOCK_SIZE)
    {
        final int num = Math.min(len - pos, AES_BLOCK_SIZE);
        gHASHPartial(multiplier, Y, b, pos, num);
    }
}

// Convert GCM initialization vector into appropriate CTR one
// so our CTR-based 'GCM decryptor' works.
// This is based on Bouncy Castle GCM block cipher implementation
// in accordance with NIST 800-38D Nov 2007 document.
private static byte[] createGcmStreamDecryptorIv(
        final AESEngine aes,
        byte[] gcmIv) {

    final byte [] J0 = new byte[AES_BLOCK_SIZE];
    if (gcmIv.length == GCM_DEFAULT_IV_SIZE) {

        // In case of 12 bytes IV ieverything is simple.
        System.arraycopy(gcmIv, 0, J0, 0, gcmIv.length);
        J0[AES_BLOCK_SIZE - 1] = 0x01;

    } else {

        // For other sizes it is much more complex.

        // We need to init GCM multiplier based on given
        // (already initialized) AES cipher.
        // Pay attention GCMMultiplier tables don't change
        // unless the key changes.
        final byte [] H = new byte[AES_BLOCK_SIZE];
        aes.processBlock(H, 0, H, 0);

        final GCMMultiplier multiplier = new Tables4kGCMMultiplier();
        multiplier.init(H);

        final byte [] nonce = new byte[AES_BLOCK_SIZE];
        System.arraycopy(gcmIv, 0, nonce, 0, gcmIv.length);

        gHASH(multiplier, J0, nonce, nonce.length);
        final byte[] X = new byte[AES_BLOCK_SIZE];
        Pack.longToBigEndian((long)gcmIv.length * 8, X, 8);
        gHASHBlock(multiplier, J0, X);
    }
    inc32(J0);
    return J0;
}

/**
 * Create streaming block cipher to decrypt AES/GCM data.
 * Actually we are taking parameters of AES/GCM encryption
 * and construct CTR (SIC) cipher with converted IV to get stream
 * skipping ability.
 * @param key Decrypted file encryption key.
 * @param iv GCM cipher initialization vector.
 * @return Streaming (actually AES/CTR) cipher to decrypt file stream 
 */
public static StreamBlockCipher createGcmStreamDecryptor(
        final SecretKey key,
        final byte[] iv) {

    try {
        // AES cipher is required both as basis for SIC/CTR cipher
        // and for IV conversion.
        final AESEngine aes = new AESEngine();
        aes.init(true, new KeyParameter(key.getEncoded()));

        // We convert GCM IV into appropriate CTR IV.
        byte[] ctrIv = createGcmStreamDecryptorIv(aes, iv);

        // Now resulting SIC cipher can be created and initialized.
        StreamBlockCipher c = new SICBlockCipher(aes);
        c.init(false, new ParametersWithIV(null, ctrIv));
        return c;

    } catch (final Exception e) {
        throw new RuntimeException(e);
    }
}

这篇关于我可以使用具有SkippingCipher接口的任何内容解密Bouncy Castle中的GCM AES流吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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