1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package javax.crypto.spec;
19
20import java.security.spec.AlgorithmParameterSpec;
21import java.util.Arrays;
22
23/**
24 * The algorithm parameter specification for the <a
25 * href="http://www.ietf.org/rfc/rfc2040.txt">RC5</a> algorithm.
26 */
27public class RC5ParameterSpec implements AlgorithmParameterSpec {
28
29    private final int version;
30    private final int rounds;
31    private final int wordSize;
32    private final byte[] iv;
33
34    /**
35     * Creates a new <code>RC5ParameterSpec</code> instance with the specified
36     * version, round count an word size (in bits).
37     *
38     * @param version
39     *            the version.
40     * @param rounds
41     *            the round count.
42     * @param wordSize
43     *            the word size (in bits).
44     */
45    public RC5ParameterSpec(int version, int rounds, int wordSize) {
46        this.version = version;
47        this.rounds = rounds;
48        this.wordSize = wordSize;
49        this.iv = null;
50    }
51
52    /**
53     * Creates a new <code>RC5ParameterSpec</code> instance with the specified
54     * version, round count, word size (in bits) and an <i>initialization
55     * vector</i>.
56     * <p>
57     * The size of the <i>initialization vector</i> must be at least
58     * <code>2 * (wordSize / 8)</code> bytes which are copied to protect them
59     * against modification.
60     *
61     * @param version
62     *            the version.
63     * @param rounds
64     *            the round count.
65     * @param wordSize
66     *            the word size (in bits).
67     * @param iv
68     *            the initialization vector.
69     * @throws IllegalArgumentException
70     *             if the initialization vector is null or shorter than <code>2
71     *             * (wordSize / 8)</code>.
72     */
73    public RC5ParameterSpec(int version, int rounds, int wordSize, byte[] iv) {
74        if (iv == null) {
75            throw new IllegalArgumentException("iv == null");
76        }
77        if (iv.length < 2 * (wordSize / 8)) {
78            throw new IllegalArgumentException("iv.length < 2 * (wordSize / 8)");
79        }
80        this.version = version;
81        this.rounds = rounds;
82        this.wordSize = wordSize;
83        this.iv = new byte[2*(wordSize/8)];
84        System.arraycopy(iv, 0, this.iv, 0, 2*(wordSize/8));
85    }
86
87    /**
88     * Creates a new <code>RC5ParameterSpec</code> instance with the specified
89     * version, round count, wordSize (in bits), an <i>initialization vector</i>
90     * and an offset.
91     * <p>
92     * The size of the <i>initialization vector</i> must be at least
93     * <code>offset + (2 * (wordSize / 8))</code> bytes. The bytes starting at
94     * <code>offset</code> are copied to protect them against modification.
95     *
96     * @param version
97     *            the version.
98     * @param rounds
99     *            the round count.
100     * @param wordSize
101     *            the word size (in bits).
102     * @param iv
103     *            the initialization vector.
104     * @param offset
105     *            the offset in the initialization vector.
106     * @throws IllegalArgumentException
107     *             if the initialization vector is null of shorter than
108     *             <code>offset + (2 * (wordSize / 8))</code>.
109     * @throws ArrayIndexOutOfBoundsException
110     *             if <code>offset</code> is negative.
111     */
112    public RC5ParameterSpec(int version, int rounds, int wordSize, byte[] iv, int offset) {
113        if (iv == null) {
114            throw new IllegalArgumentException("iv == null");
115        }
116        if (offset < 0) {
117            throw new ArrayIndexOutOfBoundsException("offset < 0: " + offset);
118        }
119        if (iv.length - offset < 2 * (wordSize / 8)) {
120            throw new IllegalArgumentException("iv.length - offset < 2 * (wordSize / 8)");
121        }
122        this.version = version;
123        this.rounds = rounds;
124        this.wordSize = wordSize;
125        this.iv = new byte[offset+2*(wordSize/8)];
126        System.arraycopy(iv, offset, this.iv, 0, 2*(wordSize/8));
127    }
128
129    /**
130     * Returns the version.
131     *
132     * @return the version.
133     */
134    public int getVersion() {
135        return version;
136    }
137
138    /**
139     * Returns the round count.
140     *
141     * @return the round count.
142     */
143    public int getRounds() {
144        return rounds;
145    }
146
147    /**
148     * Returns the word size (in bits).
149     *
150     * @return the word size (in bits).
151     */
152    public int getWordSize() {
153        return wordSize;
154    }
155
156    /**
157     * Returns a copy of the initialization vector.
158     *
159     * @return a copy of the initialization vector, or null if none specified.
160     */
161    public byte[] getIV() {
162        if (iv == null) {
163            return null;
164        }
165        byte[] result = new byte[iv.length];
166        System.arraycopy(iv, 0, result, 0, iv.length);
167        return result;
168    }
169
170    /**
171     * Compares the specified object with this <code>RC5ParameterSpec</code>
172     * instance.
173     *
174     * @param obj
175     *            the object to compare.
176     * @return true if version, round count, word size and initializaion vector
177     *         of both objects are equal, otherwise false.
178     */
179    @Override
180    public boolean equals(Object obj) {
181        if (obj == this) {
182            return true;
183        }
184        if (!(obj instanceof RC5ParameterSpec)) {
185            return false;
186        }
187        RC5ParameterSpec ps = (RC5ParameterSpec) obj;
188        return (version == ps.version)
189            && (rounds == ps.rounds)
190            && (wordSize == ps.wordSize)
191            && (Arrays.equals(iv, ps.iv));
192    }
193
194    /**
195     * Returns the hash code of this <code>RC5ParameterSpec</code> instance.
196     *
197     * @return the hash code.
198     */
199    @Override
200    public int hashCode() {
201        int result = version + rounds + wordSize;
202        if (iv == null) {
203            return result;
204        }
205        for (byte element : iv) {
206            result += element & 0xFF;
207        }
208        return result;
209    }
210}
211