/*
 * Copyright (C) 2017, Google Inc. and others
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0 which is available at
 * https://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

package org.eclipse.jgit.util.sha1;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.util.IO;
import org.junit.Test;

public class SHA1Test {
	private static final String TEST1 = "abc";

	private static final String TEST2a = "abcdbcdecdefdefgefghfghighijhi";
	private static final String TEST2b = "jkijkljklmklmnlmnomnopnopq";
	private static final String TEST2 = TEST2a + TEST2b;

	@Test
	public void test0() throws NoSuchAlgorithmException {
		ObjectId exp = ObjectId
				.fromString("da39a3ee5e6b4b0d3255bfef95601890afd80709");

		MessageDigest m = MessageDigest.getInstance("SHA-1");
		m.update(new byte[] {});
		ObjectId m1 = ObjectId.fromRaw(m.digest());

		SHA1 s = SHA1.newInstance();
		s.update(new byte[] {});
		ObjectId s1 = ObjectId.fromRaw(s.digest());

		s.reset();
		s.update(new byte[] {});
		ObjectId s2 = s.toObjectId();

		assertEquals(m1, s1);
		assertEquals(exp, s1);
		assertEquals(exp, s2);
	}

	@Test
	public void test1() throws NoSuchAlgorithmException {
		ObjectId exp = ObjectId
				.fromString("a9993e364706816aba3e25717850c26c9cd0d89d");

		MessageDigest m = MessageDigest.getInstance("SHA-1");
		m.update(TEST1.getBytes(UTF_8));
		ObjectId m1 = ObjectId.fromRaw(m.digest());

		SHA1 s = SHA1.newInstance();
		s.update(TEST1.getBytes(UTF_8));
		ObjectId s1 = ObjectId.fromRaw(s.digest());

		s.reset();
		s.update(TEST1.getBytes(UTF_8));
		ObjectId s2 = s.toObjectId();

		assertEquals(m1, s1);
		assertEquals(exp, s1);
		assertEquals(exp, s2);
	}

	@Test
	public void test2() throws NoSuchAlgorithmException {
		ObjectId exp = ObjectId
				.fromString("84983e441c3bd26ebaae4aa1f95129e5e54670f1");

		MessageDigest m = MessageDigest.getInstance("SHA-1");
		m.update(TEST2.getBytes(UTF_8));
		ObjectId m1 = ObjectId.fromRaw(m.digest());

		SHA1 s = SHA1.newInstance();
		s.update(TEST2.getBytes(UTF_8));
		ObjectId s1 = ObjectId.fromRaw(s.digest());

		s.reset();
		s.update(TEST2.getBytes(UTF_8));
		ObjectId s2 = s.toObjectId();

		assertEquals(m1, s1);
		assertEquals(exp, s1);
		assertEquals(exp, s2);
	}

	@Test
	public void shatteredCollision()
			throws IOException, NoSuchAlgorithmException {
		byte[] pdf1 = read("shattered-1.pdf", 422435);
		byte[] pdf2 = read("shattered-2.pdf", 422435);
		MessageDigest md;
		SHA1 s;

		// SHAttered attack generated these PDFs to have identical SHA-1.
		ObjectId bad = ObjectId
				.fromString("38762cf7f55934b34d179ae6a4c80cadccbb7f0a");
		md = MessageDigest.getInstance("SHA-1");
		md.update(pdf1);
		assertEquals("shattered-1 collides", bad,
				ObjectId.fromRaw(md.digest()));
		s = SHA1.newInstance().setDetectCollision(false);
		s.update(pdf1);
		assertEquals("shattered-1 collides", bad, s.toObjectId());

		md = MessageDigest.getInstance("SHA-1");
		md.update(pdf2);
		assertEquals("shattered-2 collides", bad,
				ObjectId.fromRaw(md.digest()));
		s = SHA1.newInstance().setDetectCollision(false);
		s.update(pdf2);
		assertEquals("shattered-2 collides", bad, s.toObjectId());

		// SHA1 with detectCollision shouldn't be fooled.
		s = SHA1.newInstance().setDetectCollision(true);
		s.update(pdf1);
		try {
			s.digest();
			fail("expected " + Sha1CollisionException.class.getSimpleName());
		} catch (Sha1CollisionException e) {
			assertEquals(e.getMessage(),
					"SHA-1 collision detected on " + bad.name());
		}

		s = SHA1.newInstance().setDetectCollision(true);
		s.update(pdf2);
		try {
			s.digest();
			fail("expected " + Sha1CollisionException.class.getSimpleName());
		} catch (Sha1CollisionException e) {
			assertEquals(e.getMessage(),
					"SHA-1 collision detected on " + bad.name());
		}
	}

	@Test
	public void shatteredStoredInGitBlob() throws IOException {
		byte[] pdf1 = read("shattered-1.pdf", 422435);
		byte[] pdf2 = read("shattered-2.pdf", 422435);

		// Although the prior test detects the chance of a collision, adding
		// the Git blob header permutes the data enough for this specific
		// attack example to not be detected as a collision. (A different file
		// pair that takes the Git header into account however, would.)
		ObjectId id1 = blob(pdf1, SHA1.newInstance().setDetectCollision(true));
		ObjectId id2 = blob(pdf2, SHA1.newInstance().setDetectCollision(true));

		assertEquals(
				ObjectId.fromString("ba9aaa145ccd24ef760cf31c74d8f7ca1a2e47b0"),
				id1);
		assertEquals(
				ObjectId.fromString("b621eeccd5c7edac9b7dcba35a8d5afd075e24f2"),
				id2);
	}

	@Test
	public void detectsShatteredByDefault() throws IOException {
		assumeTrue(System.getProperty("org.eclipse.jgit.util.sha1.detectCollision") == null);
		assumeTrue(System.getProperty("org.eclipse.jgit.util.sha1.safeHash") == null);

		byte[] pdf1 = read("shattered-1.pdf", 422435);
		SHA1 s = SHA1.newInstance();
		s.update(pdf1);
		try {
			s.digest();
			fail("expected " + Sha1CollisionException.class.getSimpleName());
		} catch (Sha1CollisionException e) {
			assertTrue("shattered-1 detected", true);
		}
	}

	private static ObjectId blob(byte[] pdf1, SHA1 s) {
		s.update(Constants.encodedTypeString(Constants.OBJ_BLOB));
		s.update((byte) ' ');
		s.update(Constants.encodeASCII(pdf1.length));
		s.update((byte) 0);
		s.update(pdf1);
		return s.toObjectId();
	}

	private byte[] read(String name, int sizeHint) throws IOException {
		try (InputStream in = getClass().getResourceAsStream(name)) {
			ByteBuffer buf = IO.readWholeStream(in, sizeHint);
			byte[] r = new byte[buf.remaining()];
			buf.get(r);
			return r;
		}
	}
}
