public void authenticate(char[] password) throws IOException { if (isMasked()) { throw new IllegalStateException("entry is masked"); } byte[] salt = new byte[8]; PRNG.nextBytes(salt, 0, salt.length); properties.put("salt", Util.toString(salt)); IMac m = getMac(password); ByteArrayOutputStream bout = new ByteArrayOutputStream(1024); MacOutputStream macout = new MacOutputStream(bout, m); DataOutputStream out2 = new DataOutputStream(macout); for (Iterator it = entries.iterator(); it.hasNext(); ) { Entry entry = (Entry) it.next(); entry.encode(out2); } bout.write(m.digest()); payload = bout.toByteArray(); }
public static PasswordAuthenticatedEntry decode(DataInputStream in, char[] password) throws IOException { PasswordAuthenticatedEntry entry = new PasswordAuthenticatedEntry(); entry.properties.decode(in); IMac mac = entry.getMac(password); int len = in.readInt() - mac.macSize(); MeteredInputStream min = new MeteredInputStream(in, len); MacInputStream macin = new MacInputStream(min, mac); DataInputStream in2 = new DataInputStream(macin); entry.setMasked(false); entry.decodeEnvelope(in2); byte[] macValue = new byte[mac.macSize()]; in.readFully(macValue); if (!Arrays.equals(macValue, mac.digest())) { throw new MalformedKeyringException("MAC verification failed"); } return entry; }
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; }
public void verify(char[] password) { if (!isMasked() || payload == null) { return; } IMac m = null; try { m = getMac(password); } catch (Exception x) { throw new IllegalArgumentException(x.toString()); } m.update(payload, 0, payload.length - m.macSize()); byte[] macValue = new byte[m.macSize()]; System.arraycopy(payload, payload.length - macValue.length, macValue, 0, macValue.length); if (!Arrays.equals(macValue, m.digest())) { throw new IllegalArgumentException("MAC verification failed"); } try { DataInputStream in = new DataInputStream(new ByteArrayInputStream(payload, 0, payload.length - m.macSize())); decodeEnvelope(in); } catch (IOException ioe) { throw new IllegalArgumentException("malformed keyring fragment"); } setMasked(false); payload = null; }
public void init(Map attributes) { HashMap sha_attr = new HashMap(); HashMap md5_attr = new HashMap(); byte[] secret = (byte[]) attributes.get(SECRET); if (secret != null) { int l = (secret.length >>> 1) + (secret.length & 1); byte[] s1 = Util.trim(secret, 0, l); byte[] s2 = Util.trim(secret, secret.length - l, l); md5_attr.put(IMac.MAC_KEY_MATERIAL, s1); sha_attr.put(IMac.MAC_KEY_MATERIAL, s2); try { hmac_md5.init(md5_attr); hmac_sha.init(sha_attr); } catch (InvalidKeyException ike) { throw new Error(ike.toString()); } } else if (!init) { throw new IllegalArgumentException("no secret supplied"); } // else re-use byte[] seeed = (byte[]) attributes.get(SEED); if (seeed != null) { seed = (byte[]) seeed.clone(); } else if (!init) { throw new IllegalArgumentException("no seed supplied"); } // else re-use // A(0) is the seed, A(1) = HMAC_hash(secret, A(0)). hmac_md5.update(seed, 0, seed.length); md5_a = hmac_md5.digest(); hmac_md5.reset(); hmac_sha.update(seed, 0, seed.length); sha_a = hmac_sha.digest(); hmac_sha.reset(); fillBuffer(); init = true; }
/* * The PRF is defined as: * * PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR * P_SHA-1(S2, label + seed); * * P_hash is defined as: * * P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + * HMAC_hash(secret, A(2) + seed) + * HMAC_hash(secret, A(3) + seed) + ... * * And A() is defined as: * * A(0) = seed * A(i) = HMAC_hash(secret, A(i-1)) * * For simplicity, we compute an 80-byte block on each call, which * corresponds to five iterations of MD5, and four of SHA-1. */ private synchronized void fillBuffer() { int len = hmac_md5.macSize(); for (int i = 0; i < buffer.length; i += len) { hmac_md5.update(md5_a, 0, md5_a.length); hmac_md5.update(seed, 0, seed.length); byte[] b = hmac_md5.digest(); hmac_md5.reset(); System.arraycopy(b, 0, buffer, i, len); hmac_md5.update(md5_a, 0, md5_a.length); md5_a = hmac_md5.digest(); hmac_md5.reset(); } len = hmac_sha.macSize(); for (int i = 0; i < buffer.length; i += len) { hmac_sha.update(sha_a, 0, sha_a.length); hmac_sha.update(seed, 0, seed.length); byte[] b = hmac_sha.digest(); hmac_sha.reset(); for (int j = 0; j < len; j++) { buffer[j + i] ^= b[j]; } hmac_sha.update(sha_a, 0, sha_a.length); sha_a = hmac_sha.digest(); hmac_sha.reset(); } idx = 0; }
public void test(TestHarness harness) { harness.checkPoint("TestOfTMMH16"); /* KEY_LENGTH: 10 TAG_LENGTH: 2 key: { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc } message: { 0xca, 0xfe, 0xba, 0xbe, 0xba, 0xde } output: { 0x9d, 0x6a } */ try { attributes.clear(); keystream = new DummyKeystream(); keystream.init(null); output = new byte[] {(byte) 0x9d, (byte) 0x6a}; mac = new TMMH16(); attributes.put(TMMH16.KEYSTREAM, keystream); attributes.put(TMMH16.TAG_LENGTH, new Integer(2)); mac.init(attributes); message = new byte[] {(byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, (byte) 0xba, (byte) 0xde}; for (int i = 0; i < message.length; i++) { mac.update(message[i]); } result = mac.digest(); harness.check(Arrays.equals(result, output), "testVector1"); } catch (Exception x) { harness.debug(x); harness.fail("TestOfTMMH16.testVector1"); } /* KEY_LENGTH: 10 TAG_LENGTH: 2 key: { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc } message: { 0xca, 0xfe, 0xba } output: { 0xc8, 0x8e } */ try { attributes.clear(); keystream = new DummyKeystream(); keystream.init(null); output = new byte[] {(byte) 0xc8, (byte) 0x8e}; mac = new TMMH16(); attributes.put(TMMH16.KEYSTREAM, keystream); attributes.put(TMMH16.TAG_LENGTH, new Integer(2)); mac.init(attributes); message = new byte[] {(byte) 0xca, (byte) 0xfe, (byte) 0xba}; for (int i = 0; i < message.length; i++) { mac.update(message[i]); } result = mac.digest(); harness.check(Arrays.equals(result, output), "testVector2"); } catch (Exception x) { harness.debug(x); harness.fail("TestOfTMMH16.testVector2"); } /* KEY_LENGTH: 10 TAG_LENGTH: 4 key: { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc } message: { 0xca, 0xfe, 0xba, 0xbe, 0xba, 0xde } output: { 0x9d, 0x6a, 0xc0, 0xd3 } */ try { attributes.clear(); keystream = new DummyKeystream(); keystream.init(null); output = new byte[] {(byte) 0x9d, (byte) 0x6a, (byte) 0xc0, (byte) 0xd3}; mac = new TMMH16(); attributes.put(TMMH16.KEYSTREAM, keystream); attributes.put(TMMH16.TAG_LENGTH, new Integer(4)); mac.init(attributes); message = new byte[] {(byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, (byte) 0xba, (byte) 0xde}; for (int i = 0; i < message.length; i++) { mac.update(message[i]); } result = mac.digest(); harness.check(Arrays.equals(result, output), "testVector3"); } catch (Exception x) { harness.debug(x); harness.fail("TestOfTMMH16.testVector3"); } }