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