digesttool.cc (4267B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "digesttool.h" 6 #include "argparse.h" 7 #include "nss_scoped_ptrs.h" 8 #include "util.h" 9 10 #include <algorithm> 11 #include <fstream> 12 #include <iomanip> 13 #include <iostream> 14 15 #include <hasht.h> // contains supported digest types 16 #include <nss.h> 17 #include <pk11pub.h> 18 #include <prio.h> 19 20 static SECOidData* HashTypeToOID(HASH_HashType hashtype) { 21 SECOidTag hashtag; 22 23 if (hashtype <= HASH_AlgNULL || hashtype >= HASH_AlgTOTAL) { 24 return nullptr; 25 } 26 27 switch (hashtype) { 28 case HASH_AlgMD5: 29 hashtag = SEC_OID_MD5; 30 break; 31 case HASH_AlgSHA1: 32 hashtag = SEC_OID_SHA1; 33 break; 34 case HASH_AlgSHA224: 35 hashtag = SEC_OID_SHA224; 36 break; 37 case HASH_AlgSHA256: 38 hashtag = SEC_OID_SHA256; 39 break; 40 case HASH_AlgSHA384: 41 hashtag = SEC_OID_SHA384; 42 break; 43 case HASH_AlgSHA512: 44 hashtag = SEC_OID_SHA512; 45 break; 46 default: 47 return nullptr; 48 } 49 50 return SECOID_FindOIDByTag(hashtag); 51 } 52 53 static SECOidData* HashNameToOID(const std::string& hashName) { 54 for (size_t htype = HASH_AlgNULL + 1; htype < HASH_AlgTOTAL; htype++) { 55 SECOidData* hashOID = HashTypeToOID(static_cast<HASH_HashType>(htype)); 56 if (hashOID && std::string(hashOID->desc) == hashName) { 57 return hashOID; 58 } 59 } 60 61 return nullptr; 62 } 63 64 static bool Digest(const ArgParser& parser, SECOidData* hashOID); 65 static bool ComputeDigest(std::istream& is, ScopedPK11Context& hashCtx); 66 67 bool DigestTool::Run(const std::vector<std::string>& arguments) { 68 ArgParser parser(arguments); 69 70 if (parser.GetPositionalArgumentCount() != 1) { 71 Usage(); 72 return false; 73 } 74 75 // no need for a db for the digest tool 76 SECStatus rv = NSS_NoDB_Init("."); 77 if (rv != SECSuccess) { 78 std::cerr << "NSS init failed!" << std::endl; 79 return false; 80 } 81 82 std::string hashName = parser.GetPositionalArgument(0); 83 std::transform(hashName.begin(), hashName.end(), hashName.begin(), ::toupper); 84 SECOidData* hashOID = HashNameToOID(hashName); 85 if (hashOID == nullptr) { 86 std::cerr << "Error: Unknown digest type " 87 << parser.GetPositionalArgument(0) << "." << std::endl; 88 return false; 89 } 90 91 bool ret = Digest(parser, hashOID); 92 93 // shutdown nss 94 if (NSS_Shutdown() != SECSuccess) { 95 std::cerr << "NSS Shutdown failed!" << std::endl; 96 return false; 97 } 98 99 return ret; 100 } 101 102 void DigestTool::Usage() { 103 std::cerr << "Usage: nss digest md5|sha-1|sha-224|sha-256|sha-384|sha-512 " 104 "[--infile <path>]" 105 << std::endl; 106 } 107 108 static bool Digest(const ArgParser& parser, SECOidData* hashOID) { 109 std::string inputFile; 110 if (parser.Has("--infile")) { 111 inputFile = parser.Get("--infile"); 112 } 113 114 ScopedPK11Context hashCtx(PK11_CreateDigestContext(hashOID->offset)); 115 if (hashCtx == nullptr) { 116 std::cerr << "Creating digest context failed." << std::endl; 117 return false; 118 } 119 PK11_DigestBegin(hashCtx.get()); 120 121 std::ifstream fis; 122 std::istream& is = GetStreamFromFileOrStdin(inputFile, fis); 123 if (!is.good() || !ComputeDigest(is, hashCtx)) { 124 return false; 125 } 126 127 unsigned char digest[HASH_LENGTH_MAX]; 128 unsigned int len; 129 SECStatus rv = PK11_DigestFinal(hashCtx.get(), digest, &len, HASH_LENGTH_MAX); 130 if (rv != SECSuccess || len == 0) { 131 std::cerr << "Calculating final hash value failed." << std::endl; 132 return false; 133 } 134 135 // human readable output 136 for (size_t i = 0; i < len; i++) { 137 std::cout << std::setw(2) << std::setfill('0') << std::hex 138 << static_cast<int>(digest[i]); 139 } 140 std::cout << std::endl; 141 142 return true; 143 } 144 145 static bool ComputeDigest(std::istream& is, ScopedPK11Context& hashCtx) { 146 while (is) { 147 unsigned char buf[4096]; 148 is.read(reinterpret_cast<char*>(buf), sizeof(buf)); 149 if (is.fail() && !is.eof()) { 150 std::cerr << "Error reading from input stream." << std::endl; 151 return false; 152 } 153 SECStatus rv = PK11_DigestOp(hashCtx.get(), buf, is.gcount()); 154 if (rv != SECSuccess) { 155 std::cerr << "PK11_DigestOp failed." << std::endl; 156 return false; 157 } 158 } 159 160 return true; 161 }