1 package org.bouncycastle.crypto.params;
2 
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
5 import java.io.OutputStreamWriter;
6 import java.text.DateFormat;
7 import java.text.SimpleDateFormat;
8 import java.util.Date;
9 import java.util.Enumeration;
10 import java.util.Hashtable;
11 import java.util.Locale;
12 
13 import org.bouncycastle.crypto.CipherParameters;
14 import org.bouncycastle.crypto.digests.SkeinDigest;
15 import org.bouncycastle.crypto.digests.SkeinEngine;
16 import org.bouncycastle.crypto.macs.SkeinMac;
17 import org.bouncycastle.util.Integers;
18 
19 /**
20  * Parameters for the Skein hash function - a series of byte[] strings identified by integer tags.
21  * <p>
22  * Parameterised Skein can be used for:
23  * <ul>
24  * <li>MAC generation, by providing a {@link SkeinParameters.Builder#setKey(byte[]) key}.</li>
25  * <li>Randomised hashing, by providing a {@link SkeinParameters.Builder#setNonce(byte[]) nonce}.</li>
26  * <li>A hash function for digital signatures, associating a
27  * {@link SkeinParameters.Builder#setPublicKey(byte[]) public key} with the message digest.</li>
28  * <li>A key derivation function, by providing a
29  * {@link SkeinParameters.Builder#setKeyIdentifier(byte[]) key identifier}.</li>
30  * <li>Personalised hashing, by providing a
31  * {@link SkeinParameters.Builder#setPersonalisation(Date, String, String) recommended format} or
32  * {@link SkeinParameters.Builder#setPersonalisation(byte[]) arbitrary} personalisation string.</li>
33  * </ul>
34  *
35  * @see SkeinEngine
36  * @see SkeinDigest
37  * @see SkeinMac
38  */
39 public class SkeinParameters
40     implements CipherParameters
41 {
42     /**
43      * The parameter type for a secret key, supporting MAC or KDF functions: {@value
44      * #PARAM_TYPE_KEY}.
45      */
46     public static final int PARAM_TYPE_KEY = 0;
47 
48     /**
49      * The parameter type for the Skein configuration block: {@value #PARAM_TYPE_CONFIG}.
50      */
51     public static final int PARAM_TYPE_CONFIG = 4;
52 
53     /**
54      * The parameter type for a personalisation string: {@value #PARAM_TYPE_PERSONALISATION}.
55      */
56     public static final int PARAM_TYPE_PERSONALISATION = 8;
57 
58     /**
59      * The parameter type for a public key: {@value #PARAM_TYPE_PUBLIC_KEY}.
60      */
61     public static final int PARAM_TYPE_PUBLIC_KEY = 12;
62 
63     /**
64      * The parameter type for a key identifier string: {@value #PARAM_TYPE_KEY_IDENTIFIER}.
65      */
66     public static final int PARAM_TYPE_KEY_IDENTIFIER = 16;
67 
68     /**
69      * The parameter type for a nonce: {@value #PARAM_TYPE_NONCE}.
70      */
71     public static final int PARAM_TYPE_NONCE = 20;
72 
73     /**
74      * The parameter type for the message: {@value #PARAM_TYPE_MESSAGE}.
75      */
76     public static final int PARAM_TYPE_MESSAGE = 48;
77 
78     /**
79      * The parameter type for the output transformation: {@value #PARAM_TYPE_OUTPUT}.
80      */
81     public static final int PARAM_TYPE_OUTPUT = 63;
82 
83     private Hashtable parameters;
84 
SkeinParameters()85     public SkeinParameters()
86     {
87         this(new Hashtable());
88     }
89 
SkeinParameters(final Hashtable parameters)90     private SkeinParameters(final Hashtable parameters)
91     {
92         this.parameters = parameters;
93     }
94 
95     /**
96      * Obtains a map of type (Integer) to value (byte[]) for the parameters tracked in this object.
97      */
getParameters()98     public Hashtable getParameters()
99     {
100         return parameters;
101     }
102 
103     /**
104      * Obtains the value of the {@link #PARAM_TYPE_KEY key parameter}, or <code>null</code> if not
105      * set.
106      */
getKey()107     public byte[] getKey()
108     {
109         return (byte[])parameters.get(Integers.valueOf(PARAM_TYPE_KEY));
110     }
111 
112     /**
113      * Obtains the value of the {@link #PARAM_TYPE_PERSONALISATION personalisation parameter}, or
114      * <code>null</code> if not set.
115      */
getPersonalisation()116     public byte[] getPersonalisation()
117     {
118         return (byte[])parameters.get(Integers.valueOf(PARAM_TYPE_PERSONALISATION));
119     }
120 
121     /**
122      * Obtains the value of the {@link #PARAM_TYPE_PUBLIC_KEY public key parameter}, or
123      * <code>null</code> if not set.
124      */
getPublicKey()125     public byte[] getPublicKey()
126     {
127         return (byte[])parameters.get(Integers.valueOf(PARAM_TYPE_PUBLIC_KEY));
128     }
129 
130     /**
131      * Obtains the value of the {@link #PARAM_TYPE_KEY_IDENTIFIER key identifier parameter}, or
132      * <code>null</code> if not set.
133      */
getKeyIdentifier()134     public byte[] getKeyIdentifier()
135     {
136         return (byte[])parameters.get(Integers.valueOf(PARAM_TYPE_KEY_IDENTIFIER));
137     }
138 
139     /**
140      * Obtains the value of the {@link #PARAM_TYPE_NONCE nonce parameter}, or <code>null</code> if
141      * not set.
142      */
getNonce()143     public byte[] getNonce()
144     {
145         return (byte[])parameters.get(Integers.valueOf(PARAM_TYPE_NONCE));
146     }
147 
148     /**
149      * A builder for {@link SkeinParameters}.
150      */
151     public static class Builder
152     {
153         private Hashtable parameters = new Hashtable();
154 
Builder()155         public Builder()
156         {
157         }
158 
Builder(Hashtable paramsMap)159         public Builder(Hashtable paramsMap)
160         {
161             Enumeration keys = paramsMap.keys();
162             while (keys.hasMoreElements())
163             {
164                 Integer key = (Integer)keys.nextElement();
165                 parameters.put(key, paramsMap.get(key));
166             }
167         }
168 
Builder(SkeinParameters params)169         public Builder(SkeinParameters params)
170         {
171             Enumeration keys = params.parameters.keys();
172             while (keys.hasMoreElements())
173             {
174                 Integer key = (Integer)keys.nextElement();
175                 parameters.put(key, params.parameters.get(key));
176             }
177         }
178 
179         /**
180          * Sets a parameters to apply to the Skein hash function.<br>
181          * Parameter types must be in the range 0,5..62, and cannot use the value {@link
182          * #PARAM_TYPE_MESSAGE} (reserved for message body).
183          * <p>
184          * Parameters with type &lt; {@link #PARAM_TYPE_MESSAGE} are processed before
185          * the message content, parameters with type &gt; {@link #PARAM_TYPE_MESSAGE}
186          * are processed after the message and prior to output.
187          *
188          * @param type  the type of the parameter, in the range 5..62.
189          * @param value the byte sequence of the parameter.
190          * @return the current builder instance.
191          */
set(int type, byte[] value)192         public Builder set(int type, byte[] value)
193         {
194             if (value == null)
195             {
196                 throw new IllegalArgumentException("Parameter value must not be null.");
197             }
198             if ((type != PARAM_TYPE_KEY)
199                 && (type < PARAM_TYPE_CONFIG || type >= PARAM_TYPE_OUTPUT || type == PARAM_TYPE_MESSAGE))
200             {
201                 throw new IllegalArgumentException("Parameter types must be in the range 0,5..47,49..62.");
202             }
203             if (type == PARAM_TYPE_CONFIG)
204             {
205                 throw new IllegalArgumentException("Parameter type " + PARAM_TYPE_CONFIG
206                     + " is reserved for internal use.");
207             }
208             this.parameters.put(Integers.valueOf(type), value);
209             return this;
210         }
211 
212         /**
213          * Sets the {@link #PARAM_TYPE_KEY} parameter.
214          */
setKey(byte[] key)215         public Builder setKey(byte[] key)
216         {
217             return set(PARAM_TYPE_KEY, key);
218         }
219 
220         /**
221          * Sets the {@link #PARAM_TYPE_PERSONALISATION} parameter.
222          */
setPersonalisation(byte[] personalisation)223         public Builder setPersonalisation(byte[] personalisation)
224         {
225             return set(PARAM_TYPE_PERSONALISATION, personalisation);
226         }
227 
228         /**
229          * Implements the recommended personalisation format for Skein defined in Section 4.11 of
230          * the Skein 1.3 specification.
231          * <p>
232          * The format is <code>YYYYMMDD email@address distinguisher</code>, encoded to a byte
233          * sequence using UTF-8 encoding.
234          *
235          * @param date          the date the personalised application of the Skein was defined.
236          * @param emailAddress  the email address of the creation of the personalised application.
237          * @param distinguisher an arbitrary personalisation string distinguishing the application.
238          * @return the current builder.
239          */
setPersonalisation(Date date, String emailAddress, String distinguisher)240         public Builder setPersonalisation(Date date, String emailAddress, String distinguisher)
241         {
242             try
243             {
244                 final ByteArrayOutputStream bout = new ByteArrayOutputStream();
245                 final OutputStreamWriter out = new OutputStreamWriter(bout, "UTF-8");
246                 final DateFormat format = new SimpleDateFormat("YYYYMMDD");
247                 out.write(format.format(date));
248                 out.write(" ");
249                 out.write(emailAddress);
250                 out.write(" ");
251                 out.write(distinguisher);
252                 out.close();
253                 return set(PARAM_TYPE_PERSONALISATION, bout.toByteArray());
254             }
255             catch (IOException e)
256             {
257                 throw new IllegalStateException("Byte I/O failed: " + e);
258             }
259         }
260 
261         /**
262           * Implements the recommended personalisation format for Skein defined in Section 4.11 of
263           * the Skein 1.3 specification. You may need to use this method if the default locale
264           * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible implementations.
265           * <p>
266           * The format is <code>YYYYMMDD email@address distinguisher</code>, encoded to a byte
267           * sequence using UTF-8 encoding.
268           *
269           * @param date          the date the personalised application of the Skein was defined.
270           * @param dateLocale    locale to be used for date interpretation.
271           * @param emailAddress  the email address of the creation of the personalised application.
272           * @param distinguisher an arbitrary personalisation string distinguishing the application.
273           * @return the current builder.
274           */
setPersonalisation(Date date, Locale dateLocale, String emailAddress, String distinguisher)275          public Builder setPersonalisation(Date date, Locale dateLocale, String emailAddress, String distinguisher)
276          {
277              try
278              {
279                  final ByteArrayOutputStream bout = new ByteArrayOutputStream();
280                  final OutputStreamWriter out = new OutputStreamWriter(bout, "UTF-8");
281                  final DateFormat format = new SimpleDateFormat("YYYYMMDD", dateLocale);
282                  out.write(format.format(date));
283                  out.write(" ");
284                  out.write(emailAddress);
285                  out.write(" ");
286                  out.write(distinguisher);
287                  out.close();
288                  return set(PARAM_TYPE_PERSONALISATION, bout.toByteArray());
289              }
290              catch (IOException e)
291              {
292                  throw new IllegalStateException("Byte I/O failed: " + e);
293              }
294          }
295 
296         /**
297          * Sets the {@link SkeinParameters#PARAM_TYPE_KEY_IDENTIFIER} parameter.
298          */
setPublicKey(byte[] publicKey)299         public Builder setPublicKey(byte[] publicKey)
300         {
301             return set(PARAM_TYPE_PUBLIC_KEY, publicKey);
302         }
303 
304         /**
305          * Sets the {@link SkeinParameters#PARAM_TYPE_KEY_IDENTIFIER} parameter.
306          */
setKeyIdentifier(byte[] keyIdentifier)307         public Builder setKeyIdentifier(byte[] keyIdentifier)
308         {
309             return set(PARAM_TYPE_KEY_IDENTIFIER, keyIdentifier);
310         }
311 
312         /**
313          * Sets the {@link SkeinParameters#PARAM_TYPE_NONCE} parameter.
314          */
setNonce(byte[] nonce)315         public Builder setNonce(byte[] nonce)
316         {
317             return set(PARAM_TYPE_NONCE, nonce);
318         }
319 
320         /**
321          * Constructs a new {@link SkeinParameters} instance with the parameters provided to this
322          * builder.
323          */
build()324         public SkeinParameters build()
325         {
326             return new SkeinParameters(parameters);
327         }
328     }
329 }
330