1c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrompackage org.bouncycastle.crypto.engines;
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;
7c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.Wrapper;
8c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.params.KeyParameter;
9c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.params.ParametersWithIV;
10c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.crypto.params.ParametersWithRandom;
11c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.util.Arrays;
12c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
13c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom/**
14c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom * an implementation of the AES Key Wrapper from the NIST Key Wrap
15c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom * Specification as described in RFC 3394.
16c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom * <p>
17c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom * For further details see: <a href="http://www.ietf.org/rfc/rfc3394.txt">http://www.ietf.org/rfc/rfc3394.txt</a>
18c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom * and  <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>.
19c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom */
20c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrompublic class RFC3394WrapEngine
21c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    implements Wrapper
22c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom{
23c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private BlockCipher     engine;
24c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private KeyParameter    param;
25c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private boolean         forWrapping;
26c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
27c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private byte[]          iv = {
28c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                              (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6,
29c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                              (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6 };
30c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
31c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public RFC3394WrapEngine(BlockCipher engine)
32c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
33c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this.engine = engine;
34c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
35c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
36c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public void init(
37c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        boolean             forWrapping,
38c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        CipherParameters    param)
39c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
40c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        this.forWrapping = forWrapping;
41c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
42c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (param instanceof ParametersWithRandom)
43c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
44c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            param = ((ParametersWithRandom) param).getParameters();
45c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
46c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
47c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (param instanceof KeyParameter)
48c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
49c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            this.param = (KeyParameter)param;
50c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
51c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        else if (param instanceof ParametersWithIV)
52c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
53c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            this.iv = ((ParametersWithIV)param).getIV();
54c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            this.param = (KeyParameter)((ParametersWithIV) param).getParameters();
55c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (this.iv.length != 8)
56c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
57c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom               throw new IllegalArgumentException("IV not equal to 8");
58c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
59c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
60c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
61c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
62c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public String getAlgorithmName()
63c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
64c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return engine.getAlgorithmName();
65c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
66c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
67c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public byte[] wrap(
68c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        byte[]  in,
69c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int     inOff,
70c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int     inLen)
71c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
72c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (!forWrapping)
73c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
74c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            throw new IllegalStateException("not set for wrapping");
75c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
76c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
77c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int     n = inLen / 8;
78c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
79c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if ((n * 8) != inLen)
80c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
81c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            throw new DataLengthException("wrap data must be a multiple of 8 bytes");
82c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
83c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
84c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        byte[]  block = new byte[inLen + iv.length];
85c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        byte[]  buf = new byte[8 + iv.length];
86c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
87c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        System.arraycopy(iv, 0, block, 0, iv.length);
885db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        System.arraycopy(in, inOff, block, iv.length, inLen);
89c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
90c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        engine.init(true, param);
91c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
92c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        for (int j = 0; j != 6; j++)
93c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
94c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            for (int i = 1; i <= n; i++)
95c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
96c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                System.arraycopy(block, 0, buf, 0, iv.length);
97c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                System.arraycopy(block, 8 * i, buf, iv.length, 8);
98c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                engine.processBlock(buf, 0, buf, 0);
99c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
100c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                int t = n * j + i;
101c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                for (int k = 1; t != 0; k++)
102c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                {
103c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                    byte    v = (byte)t;
104c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
105c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                    buf[iv.length - k] ^= v;
106c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
107c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                    t >>>= 8;
108c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                }
109c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
110c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                System.arraycopy(buf, 0, block, 0, 8);
111c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                System.arraycopy(buf, 8, block, 8 * i, 8);
112c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
113c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
114c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
115c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return block;
116c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
117c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
118c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public byte[] unwrap(
119c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        byte[]  in,
120c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int     inOff,
121c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int     inLen)
122c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        throws InvalidCipherTextException
123c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
124c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (forWrapping)
125c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
126c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            throw new IllegalStateException("not set for unwrapping");
127c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
128c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
129c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int     n = inLen / 8;
130c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
131c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if ((n * 8) != inLen)
132c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
133c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes");
134c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
135c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
136c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        byte[]  block = new byte[inLen - iv.length];
137c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        byte[]  a = new byte[iv.length];
138c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        byte[]  buf = new byte[8 + iv.length];
139c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
1405db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        System.arraycopy(in, inOff, a, 0, iv.length);
1415db505e1f6a68c8d5dfdb0fed0b8607dea7bed96Kenny Root        System.arraycopy(in, inOff + iv.length, block, 0, inLen - iv.length);
142c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
143c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        engine.init(false, param);
144c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
145c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        n = n - 1;
146c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
147c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        for (int j = 5; j >= 0; j--)
148c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
149c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            for (int i = n; i >= 1; i--)
150c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
151c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                System.arraycopy(a, 0, buf, 0, iv.length);
152c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                System.arraycopy(block, 8 * (i - 1), buf, iv.length, 8);
153c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
154c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                int t = n * j + i;
155c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                for (int k = 1; t != 0; k++)
156c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                {
157c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                    byte    v = (byte)t;
158c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
159c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                    buf[iv.length - k] ^= v;
160c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
161c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                    t >>>= 8;
162c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                }
163c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
164c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                engine.processBlock(buf, 0, buf, 0);
165c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                System.arraycopy(buf, 0, a, 0, 8);
166c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                System.arraycopy(buf, 8, block, 8 * (i - 1), 8);
167c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
168c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
169c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
170c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (!Arrays.constantTimeAreEqual(a, iv))
171c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
172c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            throw new InvalidCipherTextException("checksum failed");
173c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
174c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
175c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return block;
176c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
177c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom}
178