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 < {@link #PARAM_TYPE_MESSAGE} are processed before 185 * the message content, parameters with type > {@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