RFC3394WrapEngine.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)package org.bouncycastle.crypto.engines;
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.bouncycastle.crypto.BlockCipher;
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.bouncycastle.crypto.CipherParameters;
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.bouncycastle.crypto.DataLengthException;
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.bouncycastle.crypto.InvalidCipherTextException;
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.bouncycastle.crypto.Wrapper;
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.bouncycastle.crypto.params.KeyParameter;
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.bouncycastle.crypto.params.ParametersWithIV;
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.bouncycastle.crypto.params.ParametersWithRandom;
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import org.bouncycastle.util.Arrays;
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)/**
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * an implementation of the AES Key Wrapper from the NIST Key Wrap
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * Specification as described in RFC 3394.
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * <p>
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * For further details see: <a href="http://www.ietf.org/rfc/rfc3394.txt">http://www.ietf.org/rfc/rfc3394.txt</a>
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * and  <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>.
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) */
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)public class RFC3394WrapEngine
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    implements Wrapper
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles){
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private BlockCipher     engine;
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private KeyParameter    param;
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private boolean         forWrapping;
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    private byte[]          iv = {
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6,
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                              (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6 };
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    public RFC3394WrapEngine(BlockCipher engine)
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    {
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        this.engine = engine;
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    public void init(
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        boolean             forWrapping,
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        CipherParameters    param)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    {
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        this.forWrapping = forWrapping;
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (param instanceof ParametersWithRandom)
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        {
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            param = ((ParametersWithRandom) param).getParameters();
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (param instanceof KeyParameter)
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        {
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            this.param = (KeyParameter)param;
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        else if (param instanceof ParametersWithIV)
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        {
53            this.iv = ((ParametersWithIV)param).getIV();
54            this.param = (KeyParameter)((ParametersWithIV) param).getParameters();
55            if (this.iv.length != 8)
56            {
57               throw new IllegalArgumentException("IV not equal to 8");
58            }
59        }
60    }
61
62    public String getAlgorithmName()
63    {
64        return engine.getAlgorithmName();
65    }
66
67    public byte[] wrap(
68        byte[]  in,
69        int     inOff,
70        int     inLen)
71    {
72        if (!forWrapping)
73        {
74            throw new IllegalStateException("not set for wrapping");
75        }
76
77        int     n = inLen / 8;
78
79        if ((n * 8) != inLen)
80        {
81            throw new DataLengthException("wrap data must be a multiple of 8 bytes");
82        }
83
84        byte[]  block = new byte[inLen + iv.length];
85        byte[]  buf = new byte[8 + iv.length];
86
87        System.arraycopy(iv, 0, block, 0, iv.length);
88        System.arraycopy(in, 0, block, iv.length, inLen);
89
90        engine.init(true, param);
91
92        for (int j = 0; j != 6; j++)
93        {
94            for (int i = 1; i <= n; i++)
95            {
96                System.arraycopy(block, 0, buf, 0, iv.length);
97                System.arraycopy(block, 8 * i, buf, iv.length, 8);
98                engine.processBlock(buf, 0, buf, 0);
99
100                int t = n * j + i;
101                for (int k = 1; t != 0; k++)
102                {
103                    byte    v = (byte)t;
104
105                    buf[iv.length - k] ^= v;
106
107                    t >>>= 8;
108                }
109
110                System.arraycopy(buf, 0, block, 0, 8);
111                System.arraycopy(buf, 8, block, 8 * i, 8);
112            }
113        }
114
115        return block;
116    }
117
118    public byte[] unwrap(
119        byte[]  in,
120        int     inOff,
121        int     inLen)
122        throws InvalidCipherTextException
123    {
124        if (forWrapping)
125        {
126            throw new IllegalStateException("not set for unwrapping");
127        }
128
129        int     n = inLen / 8;
130
131        if ((n * 8) != inLen)
132        {
133            throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes");
134        }
135
136        byte[]  block = new byte[inLen - iv.length];
137        byte[]  a = new byte[iv.length];
138        byte[]  buf = new byte[8 + iv.length];
139
140        System.arraycopy(in, 0, a, 0, iv.length);
141        System.arraycopy(in, iv.length, block, 0, inLen - iv.length);
142
143        engine.init(false, param);
144
145        n = n - 1;
146
147        for (int j = 5; j >= 0; j--)
148        {
149            for (int i = n; i >= 1; i--)
150            {
151                System.arraycopy(a, 0, buf, 0, iv.length);
152                System.arraycopy(block, 8 * (i - 1), buf, iv.length, 8);
153
154                int t = n * j + i;
155                for (int k = 1; t != 0; k++)
156                {
157                    byte    v = (byte)t;
158
159                    buf[iv.length - k] ^= v;
160
161                    t >>>= 8;
162                }
163
164                engine.processBlock(buf, 0, buf, 0);
165                System.arraycopy(buf, 0, a, 0, 8);
166                System.arraycopy(buf, 8, block, 8 * (i - 1), 8);
167            }
168        }
169
170        if (!Arrays.constantTimeAreEqual(a, iv))
171        {
172            throw new InvalidCipherTextException("checksum failed");
173        }
174
175        return block;
176    }
177}
178