index.rst (7164B)
1 .. _mozilla_projects_nss_nss_sample_code_sample1: 2 3 sample1 4 ======= 5 6 .. container:: 7 8 1. A program to compute the hash of a file and save it to another file. 9 10 .. code:: c 11 12 /* NSPR Headers */ 13 #include <prprf.h> 14 #include <prtypes.h> 15 #include <plgetopt.h> 16 #include <prio.h> 17 #include <prprf.h> 18 19 /* NSS headers */ 20 #include <secoid.h> 21 #include <secmodt.h> 22 #include <sechash.h> 23 24 typedef struct { 25 const char *hashName; 26 SECOidTag oid; 27 } NameTagPair; 28 29 /* The hash algorithms supported */ 30 static const NameTagPair HASH_NAMES[] = { 31 { "MD2", SEC_OID_MD2 }, 32 { "MD5", SEC_OID_MD5 }, 33 { "SHA1", SEC_OID_SHA1 }, 34 { "SHA256", SEC_OID_SHA256 }, 35 { "SHA384", SEC_OID_SHA384 }, 36 { "SHA512", SEC_OID_SHA512 } 37 }; 38 39 /* Maps a hash name to a SECOidTag. 40 * Returns NULL if the name is not a supported algorithm 41 */ 42 static SECOidTag HashNameToOIDTag(const char *hashName) 43 { 44 int i, nhashes = sizeof(HASH_NAMES); 45 SECOidTag hashtag = SEC_OID_UNKNOWN; 46 47 for (i = 0; i < nhashes; i++) { 48 if (PORT_Strcasecmp(hashName, HASH_NAMES[i].hashName) == 0) { 49 hashtag = HASH_NAMES[i].oid; 50 break; 51 } 52 } 53 return hashtag; 54 } 55 56 /* Newline */ 57 static void Newline(PRFileDesc* out) 58 { 59 PR_fprintf(out, "\n"); 60 } 61 62 /* PrintAsHex */ 63 void PrintAsHex(PRFileDesc* out, unsigned char *data, unsigned int len) 64 { 65 unsigned i; 66 int column; 67 unsigned int limit = 15; 68 unsigned int level = 1; 69 70 column = level; 71 if (!len) { 72 PR_fprintf(out, "(empty)\n"); 73 return; 74 } 75 76 for (i = 0; i < len; i++) { 77 if (i != len - 1) { 78 PR_fprintf(out, "%02x:", data[i]); 79 column += 3; 80 } else { 81 PR_fprintf(out, "%02x", data[i]); 82 column += 2; 83 break; 84 } 85 if (column > 76 || (i % 16 == limit)) { 86 Newline(out); 87 column = level; 88 limit = i % 16; 89 } 90 } 91 if (column != level) { 92 Newline(out); 93 } 94 } 95 96 97 /* Prints a usage message and exits */ 98 static void Usage(const char *progName) 99 { 100 int htype; 101 int HASH_AlgTOTAL = sizeof(HASH_NAMES) / sizeof(HASH_NAMES[0]); 102 103 fprintf(stderr, "Usage: %s -t type [ < input ] [ > output ]\n", progName); 104 fprintf(stderr, "%-20s Specify the digest method (must be one of\n", 105 "-t type"); 106 fprintf(stderr, "%-20s ", ""); 107 for (htype = 0; htype < HASH_AlgTOTAL; htype++) { 108 fprintf(stderr, HASH_NAMES[htype].hashName); 109 if (htype == (HASH_AlgTOTAL - 2)) 110 fprintf(stderr, " or "); 111 else if (htype != (HASH_AlgTOTAL - 1)) 112 fprintf(stderr, ", "); 113 } 114 fprintf(stderr, " (case ignored))\n"); 115 fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", 116 "< input"); 117 fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", 118 "> output"); 119 exit(-1); 120 } 121 122 /* Check for the missing arguments */ 123 static void 124 PrintMsgAndExit(const char *progName, char opt) 125 { 126 fprintf(stderr, "%s: option -%c requires an argument\n", progName, opt); 127 Usage(progName); 128 } 129 130 #define REQUIRE_ARG(opt,value) if (!(value)) PrintMsgAndExit(progName, opt) 131 132 /* Digests a file according to the specified algorithm. 133 * It writes out the digest as a hexadecimal string. 134 */ 135 static int 136 DigestFile(PRFileDesc *outFile, PRFileDesc *inFile, SECOidTag hashOIDTag) 137 { 138 unsigned int nb; 139 unsigned char ibuf[4096]; 140 unsigned char digest[64]; 141 unsigned int len; 142 unsigned int digestLen; 143 HASH_HashType hashType; 144 HASHContext *hashContext = NULL; 145 146 hashType = HASH_GetHashTypeByOidTag(hashOIDTag); 147 hashContext = HASH_Create(hashType); 148 if (hashContext == NULL) { 149 return SECFailure; 150 } 151 152 do { 153 HASH_Begin(hashContext); 154 155 /* Incrementally hash the file contents */ 156 while ((nb = PR_Read(inFile, ibuf, sizeof(ibuf))) > 0) { 157 HASH_Update(hashContext, ibuf, nb); 158 } 159 160 HASH_End(hashContext, digest, &len, 64); 161 162 /* Normally we would write it out in binary with 163 * nb = PR_Write(outFile, digest, len); 164 * but for illustration let's print it in hex. 165 */ 166 PrintAsHex(outFile, digest, len); 167 168 } while (0); 169 170 /* cleanup */ 171 if (hashContext != NULL) 172 HASH_Destroy(hashContext); 173 174 return SECSuccess; 175 } 176 177 /* 178 * This sample computes the hash of a file and saves it to another file. It illustrates the use of NSS message APIs. 179 */ 180 int main(int argc, char **argv) 181 { 182 SECOidTag hashOIDTag; 183 PLOptState *optstate; 184 PLOptStatus status; 185 SECStatus rv; 186 char *hashName = NULL; 187 char *progName = strrchr(argv[0], '/'); 188 189 progName = progName ? progName + 1 : argv[0]; 190 191 rv = NSS_NoDB_Init("/tmp"); 192 if (rv != SECSuccess) { 193 fprintf(stderr, "%s: NSS_Init failed in directory %s\n", progName, "/tmp"); 194 return -1; 195 } 196 197 /* Parse command line arguments */ 198 optstate = PL_CreateOptState(argc, argv, "t:"); 199 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { 200 switch (optstate->option) { 201 case 't': 202 REQUIRE_ARG(optstate->option, optstate->value); 203 hashName = strdup(optstate->value); 204 break; 205 } 206 } 207 208 if (!hashName) 209 Usage(progName); 210 211 /* convert and validate */ 212 hashOIDTag = HashNameToOIDTag(hashName); 213 if (hashOIDTag == SEC_OID_UNKNOWN) { 214 fprintf(stderr, "%s: invalid digest type - %s\n", progName, hashName); 215 Usage(progName); 216 } 217 218 /* Digest it and print the result */ 219 rv = DigestFile(PR_STDOUT, PR_STDIN, hashOIDTag); 220 if (rv != SECSuccess) { 221 fprintf(stderr, "%s: problem digesting data (%d)\n", progName, PORT_GetError()); 222 } 223 224 rv = NSS_Shutdown(); 225 if (rv != SECSuccess) { 226 exit(-1); 227 } 228 229 return 0; 230 }