private IMac getMac(char[] password) throws MalformedKeyringException { if (!properties.containsKey("salt")) { throw new MalformedKeyringException("no salt"); } byte[] salt = Util.toBytesFromString(properties.get("salt")); IMac mac = MacFactory.getInstance(properties.get("mac")); if (mac == null) { throw new MalformedKeyringException("no such mac: " + properties.get("mac")); } int keylen = mac.macSize(); int maclen = 0; if (!properties.containsKey("maclen")) { throw new MalformedKeyringException("no MAC length"); } try { maclen = Integer.parseInt(properties.get("maclen")); } catch (NumberFormatException nfe) { throw new MalformedKeyringException("bad MAC length"); } HashMap pbAttr = new HashMap(); pbAttr.put(IPBE.PASSWORD, password); pbAttr.put(IPBE.SALT, salt); pbAttr.put(IPBE.ITERATION_COUNT, ITERATION_COUNT); IRandom kdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA"); kdf.init(pbAttr); byte[] dk = new byte[keylen]; try { kdf.nextBytes(dk, 0, keylen); } catch (LimitReachedException shouldNotHappen) { throw new Error(shouldNotHappen.toString()); } HashMap macAttr = new HashMap(); macAttr.put(IMac.MAC_KEY_MATERIAL, dk); macAttr.put(IMac.TRUNCATED_SIZE, new Integer(maclen)); try { mac.init(macAttr); } catch (InvalidKeyException shouldNotHappen) { throw new Error(shouldNotHappen.toString()); } return mac; }
/** * Initialise this instance with the designated set of attributes. * * <p>The possible attributes for a <code>UST</code> are: * * <ul> * <li>{@link #CONFIDENTIALITY}: a {@link java.lang.Boolean} that indicates if Confidentiality * Protection service is to be activated for messages processed with this instance. * <li>{@link #INTEGRITY}: a {@link java.lang.Boolean} that indicates if Integrity Protection * service is to be activated for messages processed with this instance. * <li>{@link #KEYSTREAM}: a {@link java.lang.String} that indicates the algorithm name of the * underlying keystream generators used with this instance. Currently the only allowed * values are: {@link Registry#UMAC_PRNG} and {@link Registry#ICM_PRNG}. * <li>{@link #INDEX_LENGTH}: a {@link java.lang.Integer} that is only needed if the {@link * Registry#ICM_PRNG} is chosen as the keystream generator algorithm. This value is the * count in bytes of the segment index portion of an <code>ICMGenerator</code>. * <li>{@link #CIPHER}: a {@link java.lang.String} that indicates the algorithm name of the * underlying symmetric key block cipher to use with the designated keystream generators. If * this value is undefined, then the default cipher algorithm for the selected keystream * generator algorithm shall be used (which is {@link Registry#RIJNDAEL_CIPHER} for both * keystream generator algorithms). * <li>{@link IBlockCipher#CIPHER_BLOCK_SIZE}: a {@link java.lang.Integer} that indicates the * block-size to use with the designated symmetric key block cipher algorithm. If this value * is undefined, then the default block size for the chosen cipher is used. * <li>{@link #TAG_LENGTH}: a {@link java.lang.Integer} that indicates the length of the * resulting authentication tag, if/when the Integrity Protection service is activated. * <li>{@link #KEY_MATERIAL}: a byte array containing the user-supplied key material needed to * seed the internal keystream generator. * </ul> * * @param attributes the map of attributes to use for this instance. */ public void init(Map attributes) { synchronized (lock) { String keystreamName = (String) attributes.get(KEYSTREAM); if (keystreamName == null) { throw new IllegalArgumentException(KEYSTREAM); } keystream = PRNGFactory.getInstance(keystreamName); kAttributes.clear(); // prepare for new values cpAttributes.clear(); ipAttributes.clear(); // find out which cipher algorithm to use String underlyingCipher = (String) attributes.get(CIPHER); if (underlyingCipher != null) { cpAttributes.put(ICMGenerator.CIPHER, underlyingCipher); ipAttributes.put(ICMGenerator.CIPHER, underlyingCipher); if (keystream instanceof ICMGenerator) { kAttributes.put(ICMGenerator.CIPHER, underlyingCipher); } else if (keystream instanceof UMacGenerator) { kAttributes.put(UMacGenerator.CIPHER, underlyingCipher); } else { throw new IllegalArgumentException(KEYSTREAM); } } // did she specify which block size to use it in? Integer blockSize = (Integer) attributes.get(IBlockCipher.CIPHER_BLOCK_SIZE); if (blockSize != null) { kAttributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, blockSize); cpAttributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, blockSize); ipAttributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, blockSize); } // get the key material. byte[] key = (byte[]) attributes.get(KEY_MATERIAL); if (key == null) { throw new IllegalArgumentException(KEY_MATERIAL); } keysize = key.length; if (keystream instanceof ICMGenerator) { // for an ICMGenerator-based UST, the key material is effectively // twice the underlying cipher's desired/needed key size: half of // these bytes is the key material per se for the cipher, and the // other half shall be used as the "offset" for the ICMGenerator. // ensure length is > 0 and is even int limit = key.length; if (limit < 2) { throw new IllegalArgumentException(KEY_MATERIAL); } else if ((limit & 0x01) != 0) { throw new IllegalArgumentException(KEY_MATERIAL); } limit /= 2; byte[] cipherKey = new byte[limit]; byte[] offset = new byte[limit]; System.arraycopy(key, 0, cipherKey, 0, limit); System.arraycopy(key, limit, offset, 0, limit); kAttributes.put(IBlockCipher.KEY_MATERIAL, cipherKey); kAttributes.put(ICMGenerator.OFFSET, offset); } else { // if we're here then it's a UMacGenerator and the key is used as is kAttributes.put(IBlockCipher.KEY_MATERIAL, key); } // get the index length. it only makes sense for the ICMGenerator // for the UMacGenerator it's always 1 Integer ndxLength = (Integer) attributes.get(INDEX_LENGTH); if (ndxLength != null) { if (keystream instanceof ICMGenerator) { kAttributes.put(ICMGenerator.SEGMENT_INDEX_LENGTH, ndxLength); // max index length is 2 ^ segment-length-in-bits - 1 maxIndex = BigInteger.valueOf(2L).pow(8 * ndxLength.intValue()).subtract(BigInteger.ONE); } else if (ndxLength.intValue() != 1) { throw new IllegalArgumentException(INDEX_LENGTH); } else { maxIndex = BigInteger.valueOf(255L); } } else if (keystream instanceof ICMGenerator) { // we need this value throw new IllegalArgumentException(INDEX_LENGTH); } else { maxIndex = BigInteger.valueOf(255L); } // the keystream with index 0 is our source for keying material // in this implementation we shall use index 0 to compute the key // material for the hash function if (keystream instanceof ICMGenerator) { kAttributes.put(ICMGenerator.SEGMENT_INDEX, BigInteger.ZERO); } else { kAttributes.put(UMacGenerator.INDEX, new Integer(0)); } // we have everything we need. init the internal keystream generator keystream.init(kAttributes); index = BigInteger.valueOf(-1L); // find out what security services to provide Boolean confidentiality = (Boolean) attributes.get(CONFIDENTIALITY); if (confidentiality == null) { // by default we dont provide it wantConfidentiality = false; } else { wantConfidentiality = confidentiality.booleanValue(); } if (wantConfidentiality) { cpStream = PRNGFactory.getInstance(keystreamName); } Boolean integrity = (Boolean) attributes.get(INTEGRITY); if (integrity == null) { // by default we do provide it wantIntegrity = true; } else { wantIntegrity = integrity.booleanValue(); } if (wantIntegrity) { // make sure we have the other generator to provide our prefix if (cpStream == null) { cpStream = PRNGFactory.getInstance(keystreamName); } ipStream = PRNGFactory.getInstance(keystreamName); // only when integrity protection service is desired do we look for // a tag length property Integer tagLength = (Integer) attributes.get(TAG_LENGTH); if (tagLength == null) { throw new IllegalArgumentException(TAG_LENGTH); } macAttributes.put(TMMH16.TAG_LENGTH, tagLength); macLength = tagLength.intValue(); } ready = false; } }