xref: /aosp_15_r20/external/boringssl/src/tool/digest.cc (revision 8fb009dc861624b67b6cdb62ea21f0f22d0c584b)
1*8fb009dcSAndroid Build Coastguard Worker /* Copyright (c) 2014, Google Inc.
2*8fb009dcSAndroid Build Coastguard Worker  *
3*8fb009dcSAndroid Build Coastguard Worker  * Permission to use, copy, modify, and/or distribute this software for any
4*8fb009dcSAndroid Build Coastguard Worker  * purpose with or without fee is hereby granted, provided that the above
5*8fb009dcSAndroid Build Coastguard Worker  * copyright notice and this permission notice appear in all copies.
6*8fb009dcSAndroid Build Coastguard Worker  *
7*8fb009dcSAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8*8fb009dcSAndroid Build Coastguard Worker  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9*8fb009dcSAndroid Build Coastguard Worker  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10*8fb009dcSAndroid Build Coastguard Worker  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11*8fb009dcSAndroid Build Coastguard Worker  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12*8fb009dcSAndroid Build Coastguard Worker  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13*8fb009dcSAndroid Build Coastguard Worker  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14*8fb009dcSAndroid Build Coastguard Worker 
15*8fb009dcSAndroid Build Coastguard Worker #include <openssl/base.h>
16*8fb009dcSAndroid Build Coastguard Worker 
17*8fb009dcSAndroid Build Coastguard Worker #include <memory>
18*8fb009dcSAndroid Build Coastguard Worker #include <string>
19*8fb009dcSAndroid Build Coastguard Worker #include <vector>
20*8fb009dcSAndroid Build Coastguard Worker 
21*8fb009dcSAndroid Build Coastguard Worker #include <errno.h>
22*8fb009dcSAndroid Build Coastguard Worker #include <fcntl.h>
23*8fb009dcSAndroid Build Coastguard Worker #include <limits.h>
24*8fb009dcSAndroid Build Coastguard Worker #include <stdio.h>
25*8fb009dcSAndroid Build Coastguard Worker #include <sys/stat.h>
26*8fb009dcSAndroid Build Coastguard Worker #include <sys/types.h>
27*8fb009dcSAndroid Build Coastguard Worker 
28*8fb009dcSAndroid Build Coastguard Worker #if !defined(OPENSSL_WINDOWS)
29*8fb009dcSAndroid Build Coastguard Worker #include <string.h>
30*8fb009dcSAndroid Build Coastguard Worker #include <unistd.h>
31*8fb009dcSAndroid Build Coastguard Worker #if !defined(O_BINARY)
32*8fb009dcSAndroid Build Coastguard Worker #define O_BINARY 0
33*8fb009dcSAndroid Build Coastguard Worker #endif
34*8fb009dcSAndroid Build Coastguard Worker #else
35*8fb009dcSAndroid Build Coastguard Worker OPENSSL_MSVC_PRAGMA(warning(push, 3))
36*8fb009dcSAndroid Build Coastguard Worker #include <windows.h>
37*8fb009dcSAndroid Build Coastguard Worker OPENSSL_MSVC_PRAGMA(warning(pop))
38*8fb009dcSAndroid Build Coastguard Worker #include <io.h>
39*8fb009dcSAndroid Build Coastguard Worker #if !defined(PATH_MAX)
40*8fb009dcSAndroid Build Coastguard Worker #define PATH_MAX MAX_PATH
41*8fb009dcSAndroid Build Coastguard Worker #endif
42*8fb009dcSAndroid Build Coastguard Worker #endif
43*8fb009dcSAndroid Build Coastguard Worker 
44*8fb009dcSAndroid Build Coastguard Worker #include <openssl/digest.h>
45*8fb009dcSAndroid Build Coastguard Worker 
46*8fb009dcSAndroid Build Coastguard Worker #include "internal.h"
47*8fb009dcSAndroid Build Coastguard Worker 
48*8fb009dcSAndroid Build Coastguard Worker 
49*8fb009dcSAndroid Build Coastguard Worker // Source is an awkward expression of a union type in C++: Stdin | File filename.
50*8fb009dcSAndroid Build Coastguard Worker struct Source {
51*8fb009dcSAndroid Build Coastguard Worker   enum Type {
52*8fb009dcSAndroid Build Coastguard Worker     STDIN,
53*8fb009dcSAndroid Build Coastguard Worker   };
54*8fb009dcSAndroid Build Coastguard Worker 
SourceSource55*8fb009dcSAndroid Build Coastguard Worker   Source() : is_stdin_(false) {}
SourceSource56*8fb009dcSAndroid Build Coastguard Worker   explicit Source(Type) : is_stdin_(true) {}
SourceSource57*8fb009dcSAndroid Build Coastguard Worker   explicit Source(const std::string &name)
58*8fb009dcSAndroid Build Coastguard Worker       : is_stdin_(false), filename_(name) {}
59*8fb009dcSAndroid Build Coastguard Worker 
is_stdinSource60*8fb009dcSAndroid Build Coastguard Worker   bool is_stdin() const { return is_stdin_; }
filenameSource61*8fb009dcSAndroid Build Coastguard Worker   const std::string &filename() const { return filename_; }
62*8fb009dcSAndroid Build Coastguard Worker 
63*8fb009dcSAndroid Build Coastguard Worker  private:
64*8fb009dcSAndroid Build Coastguard Worker   bool is_stdin_;
65*8fb009dcSAndroid Build Coastguard Worker   std::string filename_;
66*8fb009dcSAndroid Build Coastguard Worker };
67*8fb009dcSAndroid Build Coastguard Worker 
68*8fb009dcSAndroid Build Coastguard Worker static const char kStdinName[] = "standard input";
69*8fb009dcSAndroid Build Coastguard Worker 
70*8fb009dcSAndroid Build Coastguard Worker // OpenFile opens the regular file named |filename| and returns a file
71*8fb009dcSAndroid Build Coastguard Worker // descriptor to it.
OpenFile(const std::string & filename)72*8fb009dcSAndroid Build Coastguard Worker static ScopedFD OpenFile(const std::string &filename) {
73*8fb009dcSAndroid Build Coastguard Worker   ScopedFD fd = OpenFD(filename.c_str(), O_RDONLY | O_BINARY);
74*8fb009dcSAndroid Build Coastguard Worker   if (!fd) {
75*8fb009dcSAndroid Build Coastguard Worker     fprintf(stderr, "Failed to open input file '%s': %s\n", filename.c_str(),
76*8fb009dcSAndroid Build Coastguard Worker             strerror(errno));
77*8fb009dcSAndroid Build Coastguard Worker     return ScopedFD();
78*8fb009dcSAndroid Build Coastguard Worker   }
79*8fb009dcSAndroid Build Coastguard Worker 
80*8fb009dcSAndroid Build Coastguard Worker #if !defined(OPENSSL_WINDOWS)
81*8fb009dcSAndroid Build Coastguard Worker   struct stat st;
82*8fb009dcSAndroid Build Coastguard Worker   if (fstat(fd.get(), &st)) {
83*8fb009dcSAndroid Build Coastguard Worker     fprintf(stderr, "Failed to stat input file '%s': %s\n", filename.c_str(),
84*8fb009dcSAndroid Build Coastguard Worker             strerror(errno));
85*8fb009dcSAndroid Build Coastguard Worker     return ScopedFD();
86*8fb009dcSAndroid Build Coastguard Worker   }
87*8fb009dcSAndroid Build Coastguard Worker 
88*8fb009dcSAndroid Build Coastguard Worker   if (!S_ISREG(st.st_mode)) {
89*8fb009dcSAndroid Build Coastguard Worker     fprintf(stderr, "%s: not a regular file\n", filename.c_str());
90*8fb009dcSAndroid Build Coastguard Worker     return ScopedFD();
91*8fb009dcSAndroid Build Coastguard Worker   }
92*8fb009dcSAndroid Build Coastguard Worker #endif
93*8fb009dcSAndroid Build Coastguard Worker 
94*8fb009dcSAndroid Build Coastguard Worker   return fd;
95*8fb009dcSAndroid Build Coastguard Worker }
96*8fb009dcSAndroid Build Coastguard Worker 
97*8fb009dcSAndroid Build Coastguard Worker // SumFile hashes the contents of |source| with |md| and sets |*out_hex| to the
98*8fb009dcSAndroid Build Coastguard Worker // hex-encoded result.
99*8fb009dcSAndroid Build Coastguard Worker //
100*8fb009dcSAndroid Build Coastguard Worker // It returns true on success or prints an error to stderr and returns false on
101*8fb009dcSAndroid Build Coastguard Worker // error.
SumFile(std::string * out_hex,const EVP_MD * md,const Source & source)102*8fb009dcSAndroid Build Coastguard Worker static bool SumFile(std::string *out_hex, const EVP_MD *md,
103*8fb009dcSAndroid Build Coastguard Worker                     const Source &source) {
104*8fb009dcSAndroid Build Coastguard Worker   ScopedFD scoped_fd;
105*8fb009dcSAndroid Build Coastguard Worker   int fd;
106*8fb009dcSAndroid Build Coastguard Worker 
107*8fb009dcSAndroid Build Coastguard Worker   if (source.is_stdin()) {
108*8fb009dcSAndroid Build Coastguard Worker     fd = 0;
109*8fb009dcSAndroid Build Coastguard Worker   } else {
110*8fb009dcSAndroid Build Coastguard Worker     scoped_fd = OpenFile(source.filename());
111*8fb009dcSAndroid Build Coastguard Worker     if (!scoped_fd) {
112*8fb009dcSAndroid Build Coastguard Worker       return false;
113*8fb009dcSAndroid Build Coastguard Worker     }
114*8fb009dcSAndroid Build Coastguard Worker     fd = scoped_fd.get();
115*8fb009dcSAndroid Build Coastguard Worker   }
116*8fb009dcSAndroid Build Coastguard Worker 
117*8fb009dcSAndroid Build Coastguard Worker   static const size_t kBufSize = 8192;
118*8fb009dcSAndroid Build Coastguard Worker   auto buf = std::make_unique<uint8_t[]>(kBufSize);
119*8fb009dcSAndroid Build Coastguard Worker 
120*8fb009dcSAndroid Build Coastguard Worker   bssl::ScopedEVP_MD_CTX ctx;
121*8fb009dcSAndroid Build Coastguard Worker   if (!EVP_DigestInit_ex(ctx.get(), md, NULL)) {
122*8fb009dcSAndroid Build Coastguard Worker     fprintf(stderr, "Failed to initialize EVP_MD_CTX.\n");
123*8fb009dcSAndroid Build Coastguard Worker     return false;
124*8fb009dcSAndroid Build Coastguard Worker   }
125*8fb009dcSAndroid Build Coastguard Worker 
126*8fb009dcSAndroid Build Coastguard Worker   for (;;) {
127*8fb009dcSAndroid Build Coastguard Worker     size_t n;
128*8fb009dcSAndroid Build Coastguard Worker     if (!ReadFromFD(fd, &n, buf.get(), kBufSize)) {
129*8fb009dcSAndroid Build Coastguard Worker       fprintf(stderr, "Failed to read from %s: %s\n",
130*8fb009dcSAndroid Build Coastguard Worker               source.is_stdin() ? kStdinName : source.filename().c_str(),
131*8fb009dcSAndroid Build Coastguard Worker               strerror(errno));
132*8fb009dcSAndroid Build Coastguard Worker       return false;
133*8fb009dcSAndroid Build Coastguard Worker     }
134*8fb009dcSAndroid Build Coastguard Worker 
135*8fb009dcSAndroid Build Coastguard Worker     if (n == 0) {
136*8fb009dcSAndroid Build Coastguard Worker       break;
137*8fb009dcSAndroid Build Coastguard Worker     }
138*8fb009dcSAndroid Build Coastguard Worker 
139*8fb009dcSAndroid Build Coastguard Worker     if (!EVP_DigestUpdate(ctx.get(), buf.get(), n)) {
140*8fb009dcSAndroid Build Coastguard Worker       fprintf(stderr, "Failed to update hash.\n");
141*8fb009dcSAndroid Build Coastguard Worker       return false;
142*8fb009dcSAndroid Build Coastguard Worker     }
143*8fb009dcSAndroid Build Coastguard Worker   }
144*8fb009dcSAndroid Build Coastguard Worker 
145*8fb009dcSAndroid Build Coastguard Worker   uint8_t digest[EVP_MAX_MD_SIZE];
146*8fb009dcSAndroid Build Coastguard Worker   unsigned digest_len;
147*8fb009dcSAndroid Build Coastguard Worker   if (!EVP_DigestFinal_ex(ctx.get(), digest, &digest_len)) {
148*8fb009dcSAndroid Build Coastguard Worker     fprintf(stderr, "Failed to finish hash.\n");
149*8fb009dcSAndroid Build Coastguard Worker     return false;
150*8fb009dcSAndroid Build Coastguard Worker   }
151*8fb009dcSAndroid Build Coastguard Worker 
152*8fb009dcSAndroid Build Coastguard Worker   char hex_digest[EVP_MAX_MD_SIZE * 2];
153*8fb009dcSAndroid Build Coastguard Worker   static const char kHextable[] = "0123456789abcdef";
154*8fb009dcSAndroid Build Coastguard Worker   for (unsigned i = 0; i < digest_len; i++) {
155*8fb009dcSAndroid Build Coastguard Worker     const uint8_t b = digest[i];
156*8fb009dcSAndroid Build Coastguard Worker     hex_digest[i * 2] = kHextable[b >> 4];
157*8fb009dcSAndroid Build Coastguard Worker     hex_digest[i * 2 + 1] = kHextable[b & 0xf];
158*8fb009dcSAndroid Build Coastguard Worker   }
159*8fb009dcSAndroid Build Coastguard Worker   *out_hex = std::string(hex_digest, digest_len * 2);
160*8fb009dcSAndroid Build Coastguard Worker 
161*8fb009dcSAndroid Build Coastguard Worker   return true;
162*8fb009dcSAndroid Build Coastguard Worker }
163*8fb009dcSAndroid Build Coastguard Worker 
164*8fb009dcSAndroid Build Coastguard Worker // PrintFileSum hashes |source| with |md| and prints a line to stdout in the
165*8fb009dcSAndroid Build Coastguard Worker // format of the coreutils *sum utilities. It returns true on success or prints
166*8fb009dcSAndroid Build Coastguard Worker // an error to stderr and returns false on error.
PrintFileSum(const EVP_MD * md,const Source & source)167*8fb009dcSAndroid Build Coastguard Worker static bool PrintFileSum(const EVP_MD *md, const Source &source) {
168*8fb009dcSAndroid Build Coastguard Worker   std::string hex_digest;
169*8fb009dcSAndroid Build Coastguard Worker   if (!SumFile(&hex_digest, md, source)) {
170*8fb009dcSAndroid Build Coastguard Worker     return false;
171*8fb009dcSAndroid Build Coastguard Worker   }
172*8fb009dcSAndroid Build Coastguard Worker 
173*8fb009dcSAndroid Build Coastguard Worker   // TODO: When given "--binary" or "-b", we should print " *" instead of "  "
174*8fb009dcSAndroid Build Coastguard Worker   // between the digest and the filename.
175*8fb009dcSAndroid Build Coastguard Worker   //
176*8fb009dcSAndroid Build Coastguard Worker   // MSYS and Cygwin md5sum default to binary mode by default, whereas other
177*8fb009dcSAndroid Build Coastguard Worker   // platforms' tools default to text mode by default. We default to text mode
178*8fb009dcSAndroid Build Coastguard Worker   // by default and consider text mode equivalent to binary mode (i.e. we
179*8fb009dcSAndroid Build Coastguard Worker   // always use Unix semantics, even on Windows), which means that our default
180*8fb009dcSAndroid Build Coastguard Worker   // output will differ from the MSYS and Cygwin tools' default output.
181*8fb009dcSAndroid Build Coastguard Worker   printf("%s  %s\n", hex_digest.c_str(),
182*8fb009dcSAndroid Build Coastguard Worker          source.is_stdin() ? "-" : source.filename().c_str());
183*8fb009dcSAndroid Build Coastguard Worker   return true;
184*8fb009dcSAndroid Build Coastguard Worker }
185*8fb009dcSAndroid Build Coastguard Worker 
186*8fb009dcSAndroid Build Coastguard Worker // CheckModeArguments contains arguments for the check mode. See the
187*8fb009dcSAndroid Build Coastguard Worker // sha256sum(1) man page for details.
188*8fb009dcSAndroid Build Coastguard Worker struct CheckModeArguments {
189*8fb009dcSAndroid Build Coastguard Worker   bool quiet = false;
190*8fb009dcSAndroid Build Coastguard Worker   bool status = false;
191*8fb009dcSAndroid Build Coastguard Worker   bool warn = false;
192*8fb009dcSAndroid Build Coastguard Worker   bool strict = false;
193*8fb009dcSAndroid Build Coastguard Worker };
194*8fb009dcSAndroid Build Coastguard Worker 
195*8fb009dcSAndroid Build Coastguard Worker // Check reads lines from |source| where each line is in the format of the
196*8fb009dcSAndroid Build Coastguard Worker // coreutils *sum utilities. It attempts to verify each hash by reading the
197*8fb009dcSAndroid Build Coastguard Worker // file named in the line.
198*8fb009dcSAndroid Build Coastguard Worker //
199*8fb009dcSAndroid Build Coastguard Worker // It returns true if all files were verified and, if |args.strict|, no input
200*8fb009dcSAndroid Build Coastguard Worker // lines had formatting errors. Otherwise it prints errors to stderr and
201*8fb009dcSAndroid Build Coastguard Worker // returns false.
Check(const CheckModeArguments & args,const EVP_MD * md,const Source & source)202*8fb009dcSAndroid Build Coastguard Worker static bool Check(const CheckModeArguments &args, const EVP_MD *md,
203*8fb009dcSAndroid Build Coastguard Worker                   const Source &source) {
204*8fb009dcSAndroid Build Coastguard Worker   FILE *file;
205*8fb009dcSAndroid Build Coastguard Worker   ScopedFILE scoped_file;
206*8fb009dcSAndroid Build Coastguard Worker 
207*8fb009dcSAndroid Build Coastguard Worker   if (source.is_stdin()) {
208*8fb009dcSAndroid Build Coastguard Worker     file = stdin;
209*8fb009dcSAndroid Build Coastguard Worker   } else {
210*8fb009dcSAndroid Build Coastguard Worker     ScopedFD fd = OpenFile(source.filename());
211*8fb009dcSAndroid Build Coastguard Worker     if (!fd) {
212*8fb009dcSAndroid Build Coastguard Worker       return false;
213*8fb009dcSAndroid Build Coastguard Worker     }
214*8fb009dcSAndroid Build Coastguard Worker 
215*8fb009dcSAndroid Build Coastguard Worker     scoped_file = FDToFILE(std::move(fd), "rb");
216*8fb009dcSAndroid Build Coastguard Worker     if (!scoped_file) {
217*8fb009dcSAndroid Build Coastguard Worker       perror("fdopen");
218*8fb009dcSAndroid Build Coastguard Worker       return false;
219*8fb009dcSAndroid Build Coastguard Worker     }
220*8fb009dcSAndroid Build Coastguard Worker     file = scoped_file.get();
221*8fb009dcSAndroid Build Coastguard Worker   }
222*8fb009dcSAndroid Build Coastguard Worker 
223*8fb009dcSAndroid Build Coastguard Worker   const size_t hex_size = EVP_MD_size(md) * 2;
224*8fb009dcSAndroid Build Coastguard Worker   char line[EVP_MAX_MD_SIZE * 2 + 2 /* spaces */ + PATH_MAX + 1 /* newline */ +
225*8fb009dcSAndroid Build Coastguard Worker             1 /* NUL */];
226*8fb009dcSAndroid Build Coastguard Worker   unsigned bad_lines = 0;
227*8fb009dcSAndroid Build Coastguard Worker   unsigned parsed_lines = 0;
228*8fb009dcSAndroid Build Coastguard Worker   unsigned error_lines = 0;
229*8fb009dcSAndroid Build Coastguard Worker   unsigned line_no = 0;
230*8fb009dcSAndroid Build Coastguard Worker   bool ok = true;
231*8fb009dcSAndroid Build Coastguard Worker   bool draining_overlong_line = false;
232*8fb009dcSAndroid Build Coastguard Worker 
233*8fb009dcSAndroid Build Coastguard Worker   for (;;) {
234*8fb009dcSAndroid Build Coastguard Worker     line_no++;
235*8fb009dcSAndroid Build Coastguard Worker 
236*8fb009dcSAndroid Build Coastguard Worker     if (fgets(line, sizeof(line), file) == nullptr) {
237*8fb009dcSAndroid Build Coastguard Worker       if (feof(file)) {
238*8fb009dcSAndroid Build Coastguard Worker         break;
239*8fb009dcSAndroid Build Coastguard Worker       }
240*8fb009dcSAndroid Build Coastguard Worker       fprintf(stderr, "Error reading from input.\n");
241*8fb009dcSAndroid Build Coastguard Worker       return false;
242*8fb009dcSAndroid Build Coastguard Worker     }
243*8fb009dcSAndroid Build Coastguard Worker 
244*8fb009dcSAndroid Build Coastguard Worker     size_t len = strlen(line);
245*8fb009dcSAndroid Build Coastguard Worker 
246*8fb009dcSAndroid Build Coastguard Worker     if (draining_overlong_line) {
247*8fb009dcSAndroid Build Coastguard Worker       if (line[len - 1] == '\n') {
248*8fb009dcSAndroid Build Coastguard Worker         draining_overlong_line = false;
249*8fb009dcSAndroid Build Coastguard Worker       }
250*8fb009dcSAndroid Build Coastguard Worker       continue;
251*8fb009dcSAndroid Build Coastguard Worker     }
252*8fb009dcSAndroid Build Coastguard Worker 
253*8fb009dcSAndroid Build Coastguard Worker     const bool overlong = line[len - 1] != '\n' && !feof(file);
254*8fb009dcSAndroid Build Coastguard Worker 
255*8fb009dcSAndroid Build Coastguard Worker     if (len < hex_size + 2 /* spaces */ + 1 /* filename */ ||
256*8fb009dcSAndroid Build Coastguard Worker         line[hex_size] != ' ' ||
257*8fb009dcSAndroid Build Coastguard Worker         line[hex_size + 1] != ' ' ||
258*8fb009dcSAndroid Build Coastguard Worker         overlong) {
259*8fb009dcSAndroid Build Coastguard Worker       bad_lines++;
260*8fb009dcSAndroid Build Coastguard Worker       if (args.warn) {
261*8fb009dcSAndroid Build Coastguard Worker         fprintf(stderr, "%s: %u: improperly formatted line\n",
262*8fb009dcSAndroid Build Coastguard Worker                 source.is_stdin() ? kStdinName : source.filename().c_str(), line_no);
263*8fb009dcSAndroid Build Coastguard Worker       }
264*8fb009dcSAndroid Build Coastguard Worker       if (args.strict) {
265*8fb009dcSAndroid Build Coastguard Worker         ok = false;
266*8fb009dcSAndroid Build Coastguard Worker       }
267*8fb009dcSAndroid Build Coastguard Worker       if (overlong) {
268*8fb009dcSAndroid Build Coastguard Worker         draining_overlong_line = true;
269*8fb009dcSAndroid Build Coastguard Worker       }
270*8fb009dcSAndroid Build Coastguard Worker       continue;
271*8fb009dcSAndroid Build Coastguard Worker     }
272*8fb009dcSAndroid Build Coastguard Worker 
273*8fb009dcSAndroid Build Coastguard Worker     if (line[len - 1] == '\n') {
274*8fb009dcSAndroid Build Coastguard Worker       line[len - 1] = 0;
275*8fb009dcSAndroid Build Coastguard Worker       len--;
276*8fb009dcSAndroid Build Coastguard Worker     }
277*8fb009dcSAndroid Build Coastguard Worker 
278*8fb009dcSAndroid Build Coastguard Worker     parsed_lines++;
279*8fb009dcSAndroid Build Coastguard Worker 
280*8fb009dcSAndroid Build Coastguard Worker     // coreutils does not attempt to restrict relative or absolute paths in the
281*8fb009dcSAndroid Build Coastguard Worker     // input so nor does this code.
282*8fb009dcSAndroid Build Coastguard Worker     std::string calculated_hex_digest;
283*8fb009dcSAndroid Build Coastguard Worker     const std::string target_filename(&line[hex_size + 2]);
284*8fb009dcSAndroid Build Coastguard Worker     Source target_source;
285*8fb009dcSAndroid Build Coastguard Worker     if (target_filename == "-") {
286*8fb009dcSAndroid Build Coastguard Worker       // coreutils reads from stdin if the filename is "-".
287*8fb009dcSAndroid Build Coastguard Worker       target_source = Source(Source::STDIN);
288*8fb009dcSAndroid Build Coastguard Worker     } else {
289*8fb009dcSAndroid Build Coastguard Worker       target_source = Source(target_filename);
290*8fb009dcSAndroid Build Coastguard Worker     }
291*8fb009dcSAndroid Build Coastguard Worker 
292*8fb009dcSAndroid Build Coastguard Worker     if (!SumFile(&calculated_hex_digest, md, target_source)) {
293*8fb009dcSAndroid Build Coastguard Worker       error_lines++;
294*8fb009dcSAndroid Build Coastguard Worker       ok = false;
295*8fb009dcSAndroid Build Coastguard Worker       continue;
296*8fb009dcSAndroid Build Coastguard Worker     }
297*8fb009dcSAndroid Build Coastguard Worker 
298*8fb009dcSAndroid Build Coastguard Worker     if (calculated_hex_digest != std::string(line, hex_size)) {
299*8fb009dcSAndroid Build Coastguard Worker       if (!args.status) {
300*8fb009dcSAndroid Build Coastguard Worker         printf("%s: FAILED\n", target_filename.c_str());
301*8fb009dcSAndroid Build Coastguard Worker       }
302*8fb009dcSAndroid Build Coastguard Worker       ok = false;
303*8fb009dcSAndroid Build Coastguard Worker       continue;
304*8fb009dcSAndroid Build Coastguard Worker     }
305*8fb009dcSAndroid Build Coastguard Worker 
306*8fb009dcSAndroid Build Coastguard Worker     if (!args.quiet) {
307*8fb009dcSAndroid Build Coastguard Worker       printf("%s: OK\n", target_filename.c_str());
308*8fb009dcSAndroid Build Coastguard Worker     }
309*8fb009dcSAndroid Build Coastguard Worker   }
310*8fb009dcSAndroid Build Coastguard Worker 
311*8fb009dcSAndroid Build Coastguard Worker   if (!args.status) {
312*8fb009dcSAndroid Build Coastguard Worker     if (bad_lines > 0 && parsed_lines > 0) {
313*8fb009dcSAndroid Build Coastguard Worker       fprintf(stderr, "WARNING: %u line%s improperly formatted\n", bad_lines,
314*8fb009dcSAndroid Build Coastguard Worker               bad_lines == 1 ? " is" : "s are");
315*8fb009dcSAndroid Build Coastguard Worker     }
316*8fb009dcSAndroid Build Coastguard Worker     if (error_lines > 0) {
317*8fb009dcSAndroid Build Coastguard Worker       fprintf(stderr, "WARNING: %u computed checksum(s) did NOT match\n",
318*8fb009dcSAndroid Build Coastguard Worker               error_lines);
319*8fb009dcSAndroid Build Coastguard Worker     }
320*8fb009dcSAndroid Build Coastguard Worker   }
321*8fb009dcSAndroid Build Coastguard Worker 
322*8fb009dcSAndroid Build Coastguard Worker   if (parsed_lines == 0) {
323*8fb009dcSAndroid Build Coastguard Worker     fprintf(stderr, "%s: no properly formatted checksum lines found.\n",
324*8fb009dcSAndroid Build Coastguard Worker             source.is_stdin() ? kStdinName : source.filename().c_str());
325*8fb009dcSAndroid Build Coastguard Worker     ok = false;
326*8fb009dcSAndroid Build Coastguard Worker   }
327*8fb009dcSAndroid Build Coastguard Worker 
328*8fb009dcSAndroid Build Coastguard Worker   return ok;
329*8fb009dcSAndroid Build Coastguard Worker }
330*8fb009dcSAndroid Build Coastguard Worker 
331*8fb009dcSAndroid Build Coastguard Worker // DigestSum acts like the coreutils *sum utilites, with the given hash
332*8fb009dcSAndroid Build Coastguard Worker // function.
DigestSum(const EVP_MD * md,const std::vector<std::string> & args)333*8fb009dcSAndroid Build Coastguard Worker static bool DigestSum(const EVP_MD *md,
334*8fb009dcSAndroid Build Coastguard Worker                       const std::vector<std::string> &args) {
335*8fb009dcSAndroid Build Coastguard Worker   bool check_mode = false;
336*8fb009dcSAndroid Build Coastguard Worker   CheckModeArguments check_args;
337*8fb009dcSAndroid Build Coastguard Worker   bool check_mode_args_given = false;
338*8fb009dcSAndroid Build Coastguard Worker   std::vector<Source> sources;
339*8fb009dcSAndroid Build Coastguard Worker 
340*8fb009dcSAndroid Build Coastguard Worker   auto it = args.begin();
341*8fb009dcSAndroid Build Coastguard Worker   while (it != args.end()) {
342*8fb009dcSAndroid Build Coastguard Worker     const std::string &arg = *it;
343*8fb009dcSAndroid Build Coastguard Worker     if (!arg.empty() && arg[0] != '-') {
344*8fb009dcSAndroid Build Coastguard Worker       break;
345*8fb009dcSAndroid Build Coastguard Worker     }
346*8fb009dcSAndroid Build Coastguard Worker 
347*8fb009dcSAndroid Build Coastguard Worker     it++;
348*8fb009dcSAndroid Build Coastguard Worker 
349*8fb009dcSAndroid Build Coastguard Worker     if (arg == "--") {
350*8fb009dcSAndroid Build Coastguard Worker       break;
351*8fb009dcSAndroid Build Coastguard Worker     }
352*8fb009dcSAndroid Build Coastguard Worker 
353*8fb009dcSAndroid Build Coastguard Worker     if (arg == "-") {
354*8fb009dcSAndroid Build Coastguard Worker       // "-" ends the argument list and indicates that stdin should be used.
355*8fb009dcSAndroid Build Coastguard Worker       sources.push_back(Source(Source::STDIN));
356*8fb009dcSAndroid Build Coastguard Worker       break;
357*8fb009dcSAndroid Build Coastguard Worker     }
358*8fb009dcSAndroid Build Coastguard Worker 
359*8fb009dcSAndroid Build Coastguard Worker     if (arg.size() >= 2 && arg[0] == '-' && arg[1] != '-') {
360*8fb009dcSAndroid Build Coastguard Worker       for (size_t i = 1; i < arg.size(); i++) {
361*8fb009dcSAndroid Build Coastguard Worker         switch (arg[i]) {
362*8fb009dcSAndroid Build Coastguard Worker           case 'b':
363*8fb009dcSAndroid Build Coastguard Worker           case 't':
364*8fb009dcSAndroid Build Coastguard Worker             // Binary/text mode – irrelevent, even on Windows.
365*8fb009dcSAndroid Build Coastguard Worker             break;
366*8fb009dcSAndroid Build Coastguard Worker           case 'c':
367*8fb009dcSAndroid Build Coastguard Worker             check_mode = true;
368*8fb009dcSAndroid Build Coastguard Worker             break;
369*8fb009dcSAndroid Build Coastguard Worker           case 'w':
370*8fb009dcSAndroid Build Coastguard Worker             check_mode_args_given = true;
371*8fb009dcSAndroid Build Coastguard Worker             check_args.warn = true;
372*8fb009dcSAndroid Build Coastguard Worker             break;
373*8fb009dcSAndroid Build Coastguard Worker           default:
374*8fb009dcSAndroid Build Coastguard Worker             fprintf(stderr, "Unknown option '%c'.\n", arg[i]);
375*8fb009dcSAndroid Build Coastguard Worker             return false;
376*8fb009dcSAndroid Build Coastguard Worker         }
377*8fb009dcSAndroid Build Coastguard Worker       }
378*8fb009dcSAndroid Build Coastguard Worker     } else if (arg == "--binary" || arg == "--text") {
379*8fb009dcSAndroid Build Coastguard Worker       // Binary/text mode – irrelevent, even on Windows.
380*8fb009dcSAndroid Build Coastguard Worker     } else if (arg == "--check") {
381*8fb009dcSAndroid Build Coastguard Worker       check_mode = true;
382*8fb009dcSAndroid Build Coastguard Worker     } else if (arg == "--quiet") {
383*8fb009dcSAndroid Build Coastguard Worker       check_mode_args_given = true;
384*8fb009dcSAndroid Build Coastguard Worker       check_args.quiet = true;
385*8fb009dcSAndroid Build Coastguard Worker     } else if (arg == "--status") {
386*8fb009dcSAndroid Build Coastguard Worker       check_mode_args_given = true;
387*8fb009dcSAndroid Build Coastguard Worker       check_args.status = true;
388*8fb009dcSAndroid Build Coastguard Worker     } else if (arg == "--warn") {
389*8fb009dcSAndroid Build Coastguard Worker       check_mode_args_given = true;
390*8fb009dcSAndroid Build Coastguard Worker       check_args.warn = true;
391*8fb009dcSAndroid Build Coastguard Worker     } else if (arg == "--strict") {
392*8fb009dcSAndroid Build Coastguard Worker       check_mode_args_given = true;
393*8fb009dcSAndroid Build Coastguard Worker       check_args.strict = true;
394*8fb009dcSAndroid Build Coastguard Worker     } else {
395*8fb009dcSAndroid Build Coastguard Worker       fprintf(stderr, "Unknown option '%s'.\n", arg.c_str());
396*8fb009dcSAndroid Build Coastguard Worker       return false;
397*8fb009dcSAndroid Build Coastguard Worker     }
398*8fb009dcSAndroid Build Coastguard Worker   }
399*8fb009dcSAndroid Build Coastguard Worker 
400*8fb009dcSAndroid Build Coastguard Worker   if (check_mode_args_given && !check_mode) {
401*8fb009dcSAndroid Build Coastguard Worker     fprintf(
402*8fb009dcSAndroid Build Coastguard Worker         stderr,
403*8fb009dcSAndroid Build Coastguard Worker         "Check mode arguments are only meaningful when verifying checksums.\n");
404*8fb009dcSAndroid Build Coastguard Worker     return false;
405*8fb009dcSAndroid Build Coastguard Worker   }
406*8fb009dcSAndroid Build Coastguard Worker 
407*8fb009dcSAndroid Build Coastguard Worker   for (; it != args.end(); it++) {
408*8fb009dcSAndroid Build Coastguard Worker     sources.push_back(Source(*it));
409*8fb009dcSAndroid Build Coastguard Worker   }
410*8fb009dcSAndroid Build Coastguard Worker 
411*8fb009dcSAndroid Build Coastguard Worker   if (sources.empty()) {
412*8fb009dcSAndroid Build Coastguard Worker     sources.push_back(Source(Source::STDIN));
413*8fb009dcSAndroid Build Coastguard Worker   }
414*8fb009dcSAndroid Build Coastguard Worker 
415*8fb009dcSAndroid Build Coastguard Worker   bool ok = true;
416*8fb009dcSAndroid Build Coastguard Worker 
417*8fb009dcSAndroid Build Coastguard Worker   if (check_mode) {
418*8fb009dcSAndroid Build Coastguard Worker     for (auto &source : sources) {
419*8fb009dcSAndroid Build Coastguard Worker       ok &= Check(check_args, md, source);
420*8fb009dcSAndroid Build Coastguard Worker     }
421*8fb009dcSAndroid Build Coastguard Worker   } else {
422*8fb009dcSAndroid Build Coastguard Worker     for (auto &source : sources) {
423*8fb009dcSAndroid Build Coastguard Worker       ok &= PrintFileSum(md, source);
424*8fb009dcSAndroid Build Coastguard Worker     }
425*8fb009dcSAndroid Build Coastguard Worker   }
426*8fb009dcSAndroid Build Coastguard Worker 
427*8fb009dcSAndroid Build Coastguard Worker   return ok;
428*8fb009dcSAndroid Build Coastguard Worker }
429*8fb009dcSAndroid Build Coastguard Worker 
MD5Sum(const std::vector<std::string> & args)430*8fb009dcSAndroid Build Coastguard Worker bool MD5Sum(const std::vector<std::string> &args) {
431*8fb009dcSAndroid Build Coastguard Worker   return DigestSum(EVP_md5(), args);
432*8fb009dcSAndroid Build Coastguard Worker }
433*8fb009dcSAndroid Build Coastguard Worker 
SHA1Sum(const std::vector<std::string> & args)434*8fb009dcSAndroid Build Coastguard Worker bool SHA1Sum(const std::vector<std::string> &args) {
435*8fb009dcSAndroid Build Coastguard Worker   return DigestSum(EVP_sha1(), args);
436*8fb009dcSAndroid Build Coastguard Worker }
437*8fb009dcSAndroid Build Coastguard Worker 
SHA224Sum(const std::vector<std::string> & args)438*8fb009dcSAndroid Build Coastguard Worker bool SHA224Sum(const std::vector<std::string> &args) {
439*8fb009dcSAndroid Build Coastguard Worker   return DigestSum(EVP_sha224(), args);
440*8fb009dcSAndroid Build Coastguard Worker }
441*8fb009dcSAndroid Build Coastguard Worker 
SHA256Sum(const std::vector<std::string> & args)442*8fb009dcSAndroid Build Coastguard Worker bool SHA256Sum(const std::vector<std::string> &args) {
443*8fb009dcSAndroid Build Coastguard Worker   return DigestSum(EVP_sha256(), args);
444*8fb009dcSAndroid Build Coastguard Worker }
445*8fb009dcSAndroid Build Coastguard Worker 
SHA384Sum(const std::vector<std::string> & args)446*8fb009dcSAndroid Build Coastguard Worker bool SHA384Sum(const std::vector<std::string> &args) {
447*8fb009dcSAndroid Build Coastguard Worker   return DigestSum(EVP_sha384(), args);
448*8fb009dcSAndroid Build Coastguard Worker }
449*8fb009dcSAndroid Build Coastguard Worker 
SHA512Sum(const std::vector<std::string> & args)450*8fb009dcSAndroid Build Coastguard Worker bool SHA512Sum(const std::vector<std::string> &args) {
451*8fb009dcSAndroid Build Coastguard Worker   return DigestSum(EVP_sha512(), args);
452*8fb009dcSAndroid Build Coastguard Worker }
453*8fb009dcSAndroid Build Coastguard Worker 
SHA512256Sum(const std::vector<std::string> & args)454*8fb009dcSAndroid Build Coastguard Worker bool SHA512256Sum(const std::vector<std::string> &args) {
455*8fb009dcSAndroid Build Coastguard Worker   return DigestSum(EVP_sha512_256(), args);
456*8fb009dcSAndroid Build Coastguard Worker }
457