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

任何相关的代码示例都将更好。

最佳答案

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

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

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

关于java - 我可以使用具有SkippingCipher接口(interface)的任何东西解密Bouncy CaSTLe中的GCM AES流吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53046729/

10-16 01:25