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