

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of CMSDK version 2.0.0.170915_Beta4 (15 September 2017)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2017
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  and is released under the following
//_/_/  
//_/_/  EXTENDED BSD License
//_/_/
//_/_/  Redistribution and use in source and binary forms, with or without
//_/_/  modification, is permitted provided that the following conditions 
//_/_/  are met:
//_/_/
//_/_/  - Redistributions of source code must retain the above copyright 
//_/_/    and collaboration notice, this list of conditions and the following 
//_/_/    disclaimer.
//_/_/
//_/_/  - Redistributions in binary form must reproduce the above copyright 
//_/_/    notice, this list of conditions and the following disclaimer in the 
//_/_/    documentation and/or other materials provided with the distribution.
//_/_/
//_/_/  - Neither the name of its copyright holders nor the names of its 
//_/_/    contributors may be used to endorse or promote products derived from 
//_/_/    this software without specific prior written permission.
//_/_/
//_/_/  - CADIA Clause: The license granted in and to the software under this 
//_/_/    agreement is a limited-use license. The software may not be used in 
//_/_/    furtherance of: (i) intentionally causing bodily injury or severe 
//_/_/    emotional harm to any person; (ii) invading the personal privacy or 
//_/_/    violating the human rights of any person; or (iii) committing or 
//_/_/    preparing for any act of war. 
//_/_/
//_/_/  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//_/_/  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//_/_/  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
//_/_/  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
//_/_/  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
//_/_/  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
//_/_/  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//_/_/  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
//_/_/  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
//_/_/  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
//_/_/  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
// //////////////////////////////////////////////////////////
// digest.cpp
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
// see http://create.stephan-brumme.com/disclaimer.html
//

// g++ -O3 digest.cpp crc32.cpp md5.cpp sha1.cpp sha256.cpp keccak.cpp sha3.cpp -o digest

#include "crc32.h"
#include "md5.h"
#include "sha1.h"
#include "sha256.h"
#include "keccak.h"
#include "sha3.h"

#include <iostream>
#include <fstream>


int main(int argc, char** argv)
{
  // syntax check
  if (argc < 2 || argc > 3)
  {
    std::cout << "./digest filename [--crc|--md5|--sha1|--sha256|--keccak|--sha3]" << std::endl;
    return 1;
  }

  // parameters
  std::string filename  = argv[1];
  std::string algorithm = argc == 3 ? argv[2] : "";
  bool computeCrc32     = algorithm.empty() || algorithm == "--crc";
  bool computeMd5       = algorithm.empty() || algorithm == "--md5";
  bool computeSha1      = algorithm.empty() || algorithm == "--sha1";
  bool computeSha2      = algorithm.empty() || algorithm == "--sha2" || algorithm == "--sha256";
  bool computeKeccak    = algorithm.empty() || algorithm == "--keccak";
  bool computeSha3      = algorithm.empty() || algorithm == "--sha3";

  CRC32  digestCrc32;
  MD5    digestMd5;
  SHA1   digestSha1;
  SHA256 digestSha2;
  Keccak digestKeccak(Keccak::Keccak256);
  SHA3   digestSha3  (SHA3  ::Bits256);

  // each cycle processes about 1 MByte (divisible by 144 => improves Keccak/SHA3 performance)
  const size_t BufferSize = 144*7*1024;
  char* buffer = new char[BufferSize];

  // select input source: either file or standard-in
  std::ifstream file;
  std::istream* input = NULL;
  // accept std::cin, syntax will be: "./digest - --sha3 < data"
  if (filename == "-")
  {
    input = &std::cin;
  }
  else
  {
    // open file
    file.open(filename.c_str(), std::ios::in | std::ios::binary);
    if (!file)
    {
      std::cerr << "Can't open '" << filename << "'" << std::endl;
      return 2;
    }

    input = &file;
  }

  // process file
  while (*input)
  {
    input->read(buffer, BufferSize);
    std::size_t numBytesRead = size_t(input->gcount());

    if (computeCrc32)
      digestCrc32 .add(buffer, numBytesRead);
    if (computeMd5)
      digestMd5   .add(buffer, numBytesRead);
    if (computeSha1)
      digestSha1  .add(buffer, numBytesRead);
    if (computeSha2)
      digestSha2  .add(buffer, numBytesRead);
    if (computeKeccak)
      digestKeccak.add(buffer, numBytesRead);
    if (computeSha3)
      digestSha3  .add(buffer, numBytesRead);
  }

  // clean up
  file.close();
  delete[] buffer;

  // show results
  if (computeCrc32)
    std::cout << "CRC32:      " << digestCrc32 .getHash() << std::endl;
  if (computeMd5)
    std::cout << "MD5:        " << digestMd5   .getHash() << std::endl;
  if (computeSha1)
    std::cout << "SHA1:       " << digestSha1  .getHash() << std::endl;
  if (computeSha2)
    std::cout << "SHA2/256:   " << digestSha2  .getHash() << std::endl;
  if (computeKeccak)
    std::cout << "Keccak/256: " << digestKeccak.getHash() << std::endl;
  if (computeSha3)
    std::cout << "SHA3/256:   " << digestSha3  .getHash() << std::endl;

  return 0;
}
