<?php
/*
 * Copyright 2008-2010 GuardTime AS
 *
 * This file is part of the GuardTime PHP SDK.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @package tsp
 */

/**
 * Hash algorithm object used to calculate data hashes.
 *
 * The currently supported algorithms are:
 *
 * <pre>
 * ------------------------------------------------------------------
 * Name         | ASN.1 OID                 | GTID  | Digest size   |
 * ------------------------------------------------------------------
 * RIPEMD160    | 1.3.36.3.2.1              | 2     | 20 bytes      |
 * SHA1         | 1.3.14.3.2.26             | 0     | 20 bytes      |
 * SHA224       | 2.16.840.1.101.3.4.2.4    | 3     | 28 bytes      |
 * SHA256       | 2.16.840.1.101.3.4.2.1    | 1     | 32 bytes      |
 * SHA384       | 2.16.840.1.101.3.4.2.2    | 4     | 48 bytes      |
 * SHA512       | 2.16.840.1.101.3.4.2.3    | 5     | 64 bytes      |
 *-------------------------------------------------------------------
 * </pre>
 *
 * To create a hash algorithm object, use one of these methods
 * (examples given for SHA-256):

 * <code>
 * $algorithm1 = GTHashAlgorithm::getByName('SHA256');
 * $algorithm2 = GTHashAlgorithm::getByOid('2.16.840.1.101.3.4.2.1');
 * $algorithm3 = GTHashAlgorithm::getByGtid(1);
 * </code>
 *
 * @see GTDataHash
 *
 * @package tsp
 */
class GTHashAlgorithm {

    private $name;
    private $oid;
    private $gtid;
    private $length;

    /**
     * Construct a new instance of GTHashAlgorithm.
     *
     * @param  string $name algorithm name
     * @param  string $oid algorithm oid
     * @param  int $gtid algorithm GuardTime ID
     * @param  int $length message digest (hash value) length
     */
    private function __construct($name, $oid, $gtid, $length) {

        $this->name = $name;
        $this->oid = $oid;
        $this->gtid = $gtid;
        $this->length = $length;

    }

    /**
     * Returns the name of this hash algorithm.
     *
     * Name is an upper case string with no dashes, e.g. {@code SHA256}.
     *
     * @return string hash algorithm name
     */
    public function getName() {
        return $this->name;
    }

    /**
     * Returns the ASN.1 object identifier (OID) of this hash algorithm.
     *
     * @return string hash algorithm OID
     */
    public function getOid() {
        return $this->oid;
    }

    /**
     * Returns the GuardTime identifier (GTID) of this hash algorithm.
     *
     * @return int hash algorithm GTID.
     */
    public function getGtid() {
        return $this->gtid;
    }

    /**
     * Returns the length (in bytes) of message digest (hash value) produced by this hash algorithm.
     *
     * @return int message digest length in bytes
     */
    public function getLength() {
        return $this->length;
    }

    /**
     * Retrieves the hash algorithm with the given name.
     *
     * This method is case- and dash-insensitive
     * e.g. 'SHA256', 'sha256', 'SHA-256' and 'sha-256' all will be accepted.
     *
     * @static
     * @param string $name algorithm name
     * @throws GTException if there is no algorithm with the given name.
     * @return GTHashAlgorithm hash algorithm object with the given name.
     */
    public static function getByName($name) {

        if (empty($name)) {
            throw new GTException("parameter name must not be empty");
        }

        $name = str_replace('-', '', $name);
        $name = strtoupper($name);

        if ($name === 'DEFAULT') {
            return GTHashAlgorithm::getByName('SHA256');
        }

        foreach (GTHashAlgorithm::getSupportedAlgorithms() as $algorithm) {
            if ($algorithm->getName() === $name) {
                return $algorithm;
            }
        }

        throw new GTException("Unsupported hash algorithm name: {$name}");

    }

    /**
     * Retrieves the hash algorithm with the given object identifier (OID).
     *
     * @static
     * @throws GTException if there is no algorithm with the given OID
     * @param  string $oid algorithm OID.
     * @return GTHashAlgorithm hash algorithm object with the given OID.
     */
    public static function getByOid($oid) {

        if (empty($oid)) {
            throw new GTException("parameter oid must not be empty");
        }

        foreach (GTHashAlgorithm::getSupportedAlgorithms() as $algorithm) {
            if ($algorithm->getOid() === $oid) {
                return $algorithm;
            }
        }

        throw new GTException("Unsupported hash algorithm oid: {$oid}");

    }

    /**
     * Retrieves the hash algorithm with the given GuardTime ID (GTID).
     *
     * @static
     * @throws GTException if there is no algorithm with the given GTID.
     * @param  int $gtid algorithm GTID
     * @return GTHashAlgorithm hash algorithm object with the given GTID.
     */
    public static function getByGtid($gtid) {

        if (!is_integer($gtid)) {
            $gtid = (int) $gtid;
        }

        foreach (GTHashAlgorithm::getSupportedAlgorithms() as $algorithm) {
            if ($algorithm->getGtid() === $gtid) {
                return $algorithm;
            }
        }

        throw new GTException("Unsupported hash algorithm gtid: {$gtid}");

    }

    /**
     * Gets all supported hash algorithms.
     *
     * @static
     * @return array array of all supported hash algorithms
     */
    private static function getSupportedAlgorithms() {

        return array(
            new GTHashAlgorithm("RIPEMD160", "1.3.36.3.2.1", 2, 20),
            new GTHashAlgorithm("SHA1", "1.3.14.3.2.26", 0, 20),
            new GTHashAlgorithm("SHA224", "2.16.840.1.101.3.4.2.4", 3, 28),
            new GTHashAlgorithm("SHA256", "2.16.840.1.101.3.4.2.1", 1, 32),
            new GTHashAlgorithm("SHA384", "2.16.840.1.101.3.4.2.2", 4, 48),
            new GTHashAlgorithm("SHA512", "2.16.840.1.101.3.4.2.3", 5, 64)
        );

    }
}

?>
