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