Skip to content
Snippets Groups Projects
Select Git revision
  • 6eb7b302f02d06a77e3d22f93fafbc5e317b9d1b
  • master default protected
  • v20181004
  • v20180420
4 results

sha512.c

Blame
  • sha512.c 3.88 KiB
    /*
    
    Copyright (C) 2018 Anders Blomdell <anders.blomdell@control.lth.se>
    
    This file is part of hashtoc.
    
    Hashtoc is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, version 3.
    
    This program is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
    
      You should have received a copy of the GNU General Public License
      along with this program. If not, see <https://www.gnu.org/licenses/>.
    
    */
    
    #include <stdio.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/xattr.h>
    #include <fcntl.h>
    #include <time.h>
    #include <unistd.h>
    #include <openssl/sha.h>
    #include <errno.h>
    #include <limits.h>
    #include <stdint.h>
    #include "sha512toc.h"
    
    #define BLOCKSIZE 4096
    #define XATTR_SHA512HASH "trusted.sha512.control.lth.se"
    
    
    struct __attribute__((__packed__)) hash_attr {
      time_t hash_time;
      time_t mtime;
      uint32_t mtime_nsec;
      uint8_t hash[SHA512_DIGEST_LENGTH];
    };
    
    void hash_sha512_buf(char *buf,
                        size_t length,
                        unsigned char *hash)
    {
      SHA512_CTX ctx;
      
      SHA512_Init(&ctx);
      SHA512_Update(&ctx, buf, length);
      SHA512_Final(hash, &ctx);
    }
    
    int hash_sha512_file(char *filename,
                      time_t mtime,
                      int64_t mtime_nsec,
                      int flags,
                      time_t maxage,
                      unsigned char *hash)
    {
      int fd;
      int result = 0, recalc = 1;
      struct hash_attr hash_attr;
    
      if (flags & FLAGS_CLEAR_XATTR) {
        if (removexattr(filename, XATTR_SHA512HASH) != 0) {
          if (errno != ENODATA) {
            result = -1;
            fprintf(stderr, "Failed to remove xattr '%s'\n", filename);
            goto out;
          } else if ((flags & FLAGS_VERBOSE_MASK) > FLAGS_VERBOSE2) {
            fprintf(stderr, "No xattr for '%s'\n", filename);
          }
        } else {
          if ((flags & FLAGS_VERBOSE_MASK) > FLAGS_VERBOSE2) {
            fprintf(stderr, "Removed xattr for '%s'\n", filename);
          }
        }
      }
      if (flags & FLAGS_NO_CALC_HASH) {
        // We should not calculate hash
        goto out;
      }
    
      if (flags & FLAGS_READ_XATTR) {
        int err;
    
        err = getxattr(filename, XATTR_SHA512HASH, &hash_attr, sizeof(hash_attr));
        if (err < 0 && errno != ENODATA) {
          result = -1;
          goto out;
        }
        if (err != sizeof(hash_attr)) {
          recalc = 1;
        } else if (le64toh(hash_attr.mtime) != mtime) {
          recalc = 1;
        } else if (le32toh(hash_attr.mtime_nsec) != mtime_nsec) {
          recalc = 1;
        } else if (flags & FLAGS_MAX_AGE && le64toh(hash_attr.hash_time) < maxage) {
          recalc = 1;
        } else {
          recalc = 0;
          memcpy(hash, hash_attr.hash, SHA512_DIGEST_LENGTH);
        }
      }
    
      if (recalc == 0) {
        goto out;
      }
      
      fd = open (filename, O_RDONLY);
      if (fd < 0) {
        result = -1;
        goto out;
      } else {
        SHA512_CTX ctx;
        unsigned char buffer[BLOCKSIZE];
        int count;
        time_t now;
          
        time(&now);
        SHA512_Init(&ctx);
        while ((count = read(fd, buffer, BLOCKSIZE)) > 0) {
          SHA512_Update(&ctx, buffer, count);
        }
        SHA512_Final(hash, &ctx);
    
        if (count < 0) {
          result = -1;
          fremovexattr(fd, XATTR_SHA512HASH);
          goto out_close;
        }
    
        if (flags & FLAGS_WRITE_XATTR) {
          int err;
    
          hash_attr.hash_time = htole64(now);
          hash_attr.mtime = htole64(mtime);
          hash_attr.mtime_nsec = htole32(mtime_nsec);
          memcpy(hash_attr.hash, hash, SHA512_DIGEST_LENGTH);
          err = fsetxattr(fd, XATTR_SHA512HASH, &hash_attr, sizeof(hash_attr), 0);
          if (err < 0) {
            result = -1;
            fremovexattr(fd, XATTR_SHA512HASH);
            goto out_close;
          }
        } else if (flags & FLAGS_READ_XATTR) {
          fremovexattr(fd, XATTR_SHA512HASH);
        }
      }
    out_close:
      close(fd);
    out:
      return result;
    }