1c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrompackage org.bouncycastle.crypto.modes;
2c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
3c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.BlockCipher;
4c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.CipherParameters;
5c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.DataLengthException;
6c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.InvalidCipherTextException;
770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstromimport org.bouncycastle.crypto.modes.gcm.GCMExponentiator;
8c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.modes.gcm.GCMMultiplier;
970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstromimport org.bouncycastle.crypto.modes.gcm.Tables1kGCMExponentiator;
10c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.modes.gcm.Tables8kGCMMultiplier;
11c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.params.AEADParameters;
12c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.params.KeyParameter;
13c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.params.ParametersWithIV;
14c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.util.Pack;
15c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.util.Arrays;
16c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
17c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom/**
18c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom * Implements the Galois/Counter mode (GCM) detailed in
19c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom * NIST Special Publication 800-38D.
20c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom */
21c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrompublic class GCMBlockCipher
22c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    implements AEADBlockCipher
23c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom{
24c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private static final int BLOCK_SIZE = 16;
25c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
26c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    // not final due to a compiler bug
27c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private BlockCipher   cipher;
28c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private GCMMultiplier multiplier;
2970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private GCMExponentiator exp;
30c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
31c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    // These fields are set by init and not modified by processing
32c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private boolean             forEncryption;
33c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private int                 macSize;
34c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private byte[]              nonce;
3570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private byte[]              initialAssociatedText;
36c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private byte[]              H;
37c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private byte[]              J0;
38c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
39c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    // These fields are modified during processing
40c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private byte[]      bufBlock;
41c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private byte[]      macBlock;
4270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private byte[]      S, S_at, S_atPre;
43c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private byte[]      counter;
44c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private int         bufOff;
45c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private long        totalLength;
4670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private byte[]      atBlock;
4770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private int         atBlockPos;
4870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private long        atLength;
4970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private long        atLengthPre;
50c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
51c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public GCMBlockCipher(BlockCipher c)
52c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
53c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this(c, null);
54c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
55c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
56c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public GCMBlockCipher(BlockCipher c, GCMMultiplier m)
57c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
58c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (c.getBlockSize() != BLOCK_SIZE)
59c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
60c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            throw new IllegalArgumentException(
61c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                "cipher required with a block size of " + BLOCK_SIZE + ".");
62c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
63c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
64c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (m == null)
65c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
66c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // TODO Consider a static property specifying default multiplier
67c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            m = new Tables8kGCMMultiplier();
68c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
69c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
70c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this.cipher = c;
71c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this.multiplier = m;
72c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
73c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
74c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public BlockCipher getUnderlyingCipher()
75c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
76c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return cipher;
77c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
78c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
79c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public String getAlgorithmName()
80c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
81c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return cipher.getAlgorithmName() + "/GCM";
82c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
83c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
84c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public void init(boolean forEncryption, CipherParameters params)
85c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        throws IllegalArgumentException
86c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
87c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this.forEncryption = forEncryption;
88c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this.macBlock = null;
89c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
9070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        KeyParameter keyParam;
914c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
92c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (params instanceof AEADParameters)
93c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
94c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            AEADParameters param = (AEADParameters)params;
95c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
96c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            nonce = param.getNonce();
9770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            initialAssociatedText = param.getAssociatedText();
98c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
99c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            int macSizeBits = param.getMacSize();
100c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (macSizeBits < 96 || macSizeBits > 128 || macSizeBits % 8 != 0)
101c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
102c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                throw new IllegalArgumentException("Invalid value for MAC size: " + macSizeBits);
103c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
104c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
105c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            macSize = macSizeBits / 8;
106c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            keyParam = param.getKey();
107c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
108c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        else if (params instanceof ParametersWithIV)
109c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
110c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            ParametersWithIV param = (ParametersWithIV)params;
111c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
112c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            nonce = param.getIV();
11370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            initialAssociatedText  = null;
114c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            macSize = 16;
115c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            keyParam = (KeyParameter)param.getParameters();
116c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
117c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        else
118c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
119c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            throw new IllegalArgumentException("invalid parameters passed to GCM");
120c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
121c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
122c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize);
123c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this.bufBlock = new byte[bufLength];
124c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
125c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (nonce == null || nonce.length < 1)
126c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
127c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            throw new IllegalArgumentException("IV must be at least 1 byte");
128c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
129c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
13070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        // TODO This should be configurable by init parameters
13170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        // (but must be 16 if nonce length not 12) (BLOCK_SIZE?)
13270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom//        this.tagLength = 16;
133c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
134c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        // Cipher always used in forward mode
1354c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        // if keyParam is null we're reusing the last key.
1364c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        if (keyParam != null)
1374c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        {
1384c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            cipher.init(true, keyParam);
139c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
14070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            this.H = new byte[BLOCK_SIZE];
14170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            cipher.processBlock(H, 0, H, 0);
142c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
14370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            // GCMMultiplier tables don't change unless the key changes (and are expensive to init)
14470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            multiplier.init(H);
14570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            exp = null;
14670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
147c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
14870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        this.J0 = new byte[BLOCK_SIZE];
149c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
150c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (nonce.length == 12)
151c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
152c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            System.arraycopy(nonce, 0, J0, 0, nonce.length);
15370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            this.J0[BLOCK_SIZE - 1] = 0x01;
154c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
155c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        else
156c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
15770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            gHASH(J0, nonce, nonce.length);
15870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            byte[] X = new byte[BLOCK_SIZE];
15970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            Pack.longToBigEndian((long)nonce.length * 8, X, 8);
16070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            gHASHBlock(J0, X);
161c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
162c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
16370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        this.S = new byte[BLOCK_SIZE];
16470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        this.S_at = new byte[BLOCK_SIZE];
16570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        this.S_atPre = new byte[BLOCK_SIZE];
16670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        this.atBlock = new byte[BLOCK_SIZE];
16770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        this.atBlockPos = 0;
16870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        this.atLength = 0;
16970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        this.atLengthPre = 0;
170c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this.counter = Arrays.clone(J0);
171c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this.bufOff = 0;
172c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this.totalLength = 0;
17370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
17470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        if (initialAssociatedText != null)
17570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
17670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            processAADBytes(initialAssociatedText, 0, initialAssociatedText.length);
17770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
178c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
179c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
180c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public byte[] getMac()
181c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
182c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return Arrays.clone(macBlock);
183c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
184c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
185c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public int getOutputSize(int len)
186c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
18770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        int totalData = len + bufOff;
18870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
189c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (forEncryption)
190c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
19170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom             return totalData + macSize;
192c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
193c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
19470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        return totalData < macSize ? 0 : totalData - macSize;
195c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
196c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
197c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public int getUpdateOutputSize(int len)
198c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
19970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        int totalData = len + bufOff;
20070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        if (!forEncryption)
20170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
20270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            if (totalData < macSize)
20370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
20470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                return 0;
20570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
20670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            totalData -= macSize;
20770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
20870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        return totalData - totalData % BLOCK_SIZE;
20970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    }
21070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
21170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    public void processAADByte(byte in)
21270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    {
21370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        atBlock[atBlockPos] = in;
21470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        if (++atBlockPos == BLOCK_SIZE)
21570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
21670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            // Hash each block as it fills
21770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            gHASHBlock(S_at, atBlock);
21870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            atBlockPos = 0;
21970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            atLength += BLOCK_SIZE;
22070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
22170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    }
22270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
22370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    public void processAADBytes(byte[] in, int inOff, int len)
22470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    {
22570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        for (int i = 0; i < len; ++i)
22670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
22770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            atBlock[atBlockPos] = in[inOff + i];
22870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            if (++atBlockPos == BLOCK_SIZE)
22970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
23070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                // Hash each block as it fills
23170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                gHASHBlock(S_at, atBlock);
23270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                atBlockPos = 0;
23370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                atLength += BLOCK_SIZE;
23470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
23570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
23670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    }
23770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
23870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private void initCipher()
23970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    {
24070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        if (atLength > 0)
24170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
24270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            System.arraycopy(S_at, 0, S_atPre, 0, BLOCK_SIZE);
24370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            atLengthPre = atLength;
24470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
24570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
24670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        // Finish hash for partial AAD block
24770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        if (atBlockPos > 0)
24870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
24970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            gHASHPartial(S_atPre, atBlock, 0, atBlockPos);
25070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            atLengthPre += atBlockPos;
25170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
25270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
25370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        if (atLengthPre > 0)
25470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
25570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            System.arraycopy(S_atPre, 0, S, 0, BLOCK_SIZE);
25670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
257c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
258c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
259c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public int processByte(byte in, byte[] out, int outOff)
260c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        throws DataLengthException
261c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
26270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        bufBlock[bufOff] = in;
26370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        if (++bufOff == bufBlock.length)
26470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
26570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            outputBlock(out, outOff);
26670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            return BLOCK_SIZE;
26770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
26870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        return 0;
269c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
270c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
271c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
272c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        throws DataLengthException
273c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
274c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int resultLen = 0;
275c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
27670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        for (int i = 0; i < len; ++i)
277c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
27870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            bufBlock[bufOff] = in[inOff + i];
27970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            if (++bufOff == bufBlock.length)
280c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
28170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                outputBlock(out, outOff + resultLen);
282c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                resultLen += BLOCK_SIZE;
283c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
284c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
285c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
286c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return resultLen;
287c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
288c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
28970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private void outputBlock(byte[] output, int offset)
290c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
29170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        if (totalLength == 0)
292c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
29370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            initCipher();
29470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
29570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        gCTRBlock(bufBlock, output, offset);
29670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        if (forEncryption)
29770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
29870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            bufOff = 0;
29970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
30070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        else
30170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
30270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            System.arraycopy(bufBlock, BLOCK_SIZE, bufBlock, 0, macSize);
30370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            bufOff = macSize;
304c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
305c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
306c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
307c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public int doFinal(byte[] out, int outOff)
308c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        throws IllegalStateException, InvalidCipherTextException
309c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
31070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        if (totalLength == 0)
31170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
31270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            initCipher();
31370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
31470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
315c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int extra = bufOff;
316c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (!forEncryption)
317c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
318c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (extra < macSize)
319c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
320c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                throw new InvalidCipherTextException("data too short");
321c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
322c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            extra -= macSize;
323c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
324c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
325c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (extra > 0)
326c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
32770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            gCTRPartial(bufBlock, 0, extra, out, outOff);
32870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
32970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
33070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        atLength += atBlockPos;
33170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
33270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        if (atLength > atLengthPre)
33370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
33470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            /*
33570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom             *  Some AAD was sent after the cipher started. We determine the difference b/w the hash value
33670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom             *  we actually used when the cipher started (S_atPre) and the final hash value calculated (S_at).
33770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom             *  Then we carry this difference forward by multiplying by H^c, where c is the number of (full or
33870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom             *  partial) cipher-text blocks produced, and adjust the current hash.
33970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom             */
34070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
34170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            // Finish hash for partial AAD block
34270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            if (atBlockPos > 0)
34370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
34470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                gHASHPartial(S_at, atBlock, 0, atBlockPos);
34570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
34670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
34770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            // Find the difference between the AAD hashes
34870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            if (atLengthPre > 0)
34970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
35070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                xor(S_at, S_atPre);
35170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
35270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
35370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            // Number of cipher-text blocks produced
35470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            long c = ((totalLength * 8) + 127) >>> 7;
35570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
35670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            // Calculate the adjustment factor
35770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            byte[] H_c = new byte[16];
35870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            if (exp == null)
35970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
36070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                exp = new Tables1kGCMExponentiator();
36170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                exp.init(H);
36270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
36370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            exp.exponentiateX(c, H_c);
36470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
36570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            // Carry the difference forward
36670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            multiply(S_at, H_c);
36770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
36870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            // Adjust the current hash
36970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            xor(S, S_at);
370c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
371c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
372c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        // Final gHASH
37370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        byte[] X = new byte[BLOCK_SIZE];
37470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        Pack.longToBigEndian(atLength * 8, X, 0);
37570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        Pack.longToBigEndian(totalLength * 8, X, 8);
376c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
37770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        gHASHBlock(S, X);
378c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
379c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        // TODO Fix this if tagLength becomes configurable
380c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        // T = MSBt(GCTRk(J0,S))
381c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        byte[] tag = new byte[BLOCK_SIZE];
382c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        cipher.processBlock(J0, 0, tag, 0);
383c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        xor(tag, S);
384c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
385c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int resultLen = extra;
386c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
387c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        // We place into macBlock our calculated value for T
388c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this.macBlock = new byte[macSize];
389c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        System.arraycopy(tag, 0, macBlock, 0, macSize);
390c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
391c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (forEncryption)
392c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
393c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // Append T to the message
394c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            System.arraycopy(macBlock, 0, out, outOff + bufOff, macSize);
395c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            resultLen += macSize;
396c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
397c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        else
398c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
399c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // Retrieve the T value from the message and compare to calculated one
400c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            byte[] msgMac = new byte[macSize];
401c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            System.arraycopy(bufBlock, extra, msgMac, 0, macSize);
402c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (!Arrays.constantTimeAreEqual(this.macBlock, msgMac))
403c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
404c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                throw new InvalidCipherTextException("mac check in GCM failed");
405c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
406c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
407c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
408c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        reset(false);
409c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
410c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return resultLen;
411c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
412c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
413c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public void reset()
414c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
415c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        reset(true);
416c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
417c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
418c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private void reset(
419c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        boolean clearMac)
420c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
42170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        cipher.reset();
42270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
42370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        S = new byte[BLOCK_SIZE];
42470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        S_at = new byte[BLOCK_SIZE];
42570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        S_atPre = new byte[BLOCK_SIZE];
42670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        atBlock = new byte[BLOCK_SIZE];
42770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        atBlockPos = 0;
42870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        atLength = 0;
42970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        atLengthPre = 0;
430c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        counter = Arrays.clone(J0);
431c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        bufOff = 0;
432c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        totalLength = 0;
433c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
434c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (bufBlock != null)
435c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
436c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            Arrays.fill(bufBlock, (byte)0);
437c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
438c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
439c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (clearMac)
440c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
441c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            macBlock = null;
442c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
443c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
44470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        if (initialAssociatedText != null)
44570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
44670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            processAADBytes(initialAssociatedText, 0, initialAssociatedText.length);
44770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
44870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    }
44970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
45070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private void gCTRBlock(byte[] block, byte[] out, int outOff)
45170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    {
45270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        byte[] tmp = getNextCounterBlock();
45370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
45470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        xor(tmp, block);
45570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        System.arraycopy(tmp, 0, out, outOff, BLOCK_SIZE);
45670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
45770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        gHASHBlock(S, forEncryption ? tmp : block);
45870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
45970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        totalLength += BLOCK_SIZE;
46070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    }
46170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
46270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private void gCTRPartial(byte[] buf, int off, int len, byte[] out, int outOff)
46370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    {
46470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        byte[] tmp = getNextCounterBlock();
46570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
46670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        xor(tmp, buf, off, len);
46770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        System.arraycopy(tmp, 0, out, outOff, len);
46870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
46970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        gHASHPartial(S, forEncryption ? tmp : buf, 0, len);
47070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
47170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        totalLength += len;
47270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    }
47370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
47470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private void gHASH(byte[] Y, byte[] b, int len)
47570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    {
47670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        for (int pos = 0; pos < len; pos += BLOCK_SIZE)
47770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
47870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            int num = Math.min(len - pos, BLOCK_SIZE);
47970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            gHASHPartial(Y, b, pos, num);
48070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
48170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    }
48270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
48370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private void gHASHBlock(byte[] Y, byte[] b)
48470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    {
48570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        xor(Y, b);
48670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        multiplier.multiplyH(Y);
48770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    }
48870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
48970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private void gHASHPartial(byte[] Y, byte[] b, int off, int len)
49070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    {
49170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        xor(Y, b, off, len);
49270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        multiplier.multiplyH(Y);
493c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
494c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
49570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private byte[] getNextCounterBlock()
496c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
497c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        for (int i = 15; i >= 12; --i)
498c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
499c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            byte b = (byte)((counter[i] + 1) & 0xff);
500c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            counter[i] = b;
501c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
502c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (b != 0)
503c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
504c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                break;
505c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
506c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
507c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
508c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        byte[] tmp = new byte[BLOCK_SIZE];
50970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        // TODO Sure would be nice if ciphers could operate on int[]
510c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        cipher.processBlock(counter, 0, tmp, 0);
51170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        return tmp;
51270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    }
513c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
51470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private static void multiply(byte[] block, byte[] val)
51570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    {
51670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        byte[] tmp = Arrays.clone(block);
51770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        byte[] c = new byte[16];
518c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
51970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        for (int i = 0; i < 16; ++i)
520c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
52170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            byte bits = val[i];
52270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            for (int j = 7; j >= 0; --j)
52370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
52470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                if ((bits & (1 << j)) != 0)
52570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                {
52670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    xor(c, tmp);
52770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                }
528c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
52970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                boolean lsb = (tmp[15] & 1) != 0;
53070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                shiftRight(tmp);
53170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                if (lsb)
53270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                {
53370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    // R = new byte[]{ 0xe1, ... };
53470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom//                    xor(v, R);
53570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                    tmp[0] ^= (byte)0xe1;
53670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                }
53770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
53870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
539c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
54070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        System.arraycopy(c, 0, block, 0, 16);
541c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
542c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
54370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private static void shiftRight(byte[] block)
544c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
54570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        int i = 0;
54670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        int bit = 0;
54770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        for (;;)
548c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
54970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            int b = block[i] & 0xff;
55070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            block[i] = (byte) ((b >>> 1) | bit);
55170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            if (++i == 16)
55270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
55370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                break;
55470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
55570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            bit = (b & 1) << 7;
556c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
557c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
558c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
559c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private static void xor(byte[] block, byte[] val)
560c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
561c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        for (int i = 15; i >= 0; --i)
562c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
563c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            block[i] ^= val[i];
564c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
565c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
566c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
56770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom    private static void xor(byte[] block, byte[] val, int off, int len)
568c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
56970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        while (len-- > 0)
57070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
57170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            block[len] ^= val[off + len];
57270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
573c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
574c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom}
575