/**************************************************************** * * * Copyright 2009, 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "main_pragma.h" #include #include #include #include #include #include #include #include #ifdef USE_OPENSSL # include # include #elif defined USE_GCRYPT # include #else # error "Unsupported encryption library. Reference implementation currently supports openssl and gcrypt" #endif #include #define MAX_LEN 512 #define FSTR_LEN 7 /* %2048s */ #define GTM_PATH_MAX 1024 #define GTM_DIST "gtm_dist" #define HASH_LENGTH 64 /* 512 bits = 64 bytes */ struct termios old_tty, no_echo_tty; #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define HEX(a, b, len) \ { \ int i; \ for (i = 0; i < len; i+=2) \ sprintf(b + i, "%02X", (unsigned char)a[i/2]); \ } static void maskpass(char passwd[], size_t password_len, char hash[], size_t hash_length) { size_t i; for (i = 0; i < password_len; i++) passwd[i] = passwd[i] ^ hash[i % hash_length]; } static int echo_off() { int fd, status; fd = fileno(stdin); /* Save current TTY settings */ status = tcgetattr(fd, &old_tty); if (0 != status) return 1; no_echo_tty = old_tty; no_echo_tty.c_lflag &= ~ECHO; /* Turn off echo */ status = tcsetattr(fd, TCSAFLUSH, &no_echo_tty); return status; } static int echo_on() { int fd, status; fd = fileno(stdin); status = tcsetattr(fd, TCSAFLUSH, &old_tty); return status; } static void prompt_passwd(char passwd[]) { char fstr[FSTR_LEN]; char tmp[MAX_LEN + 1]; /* +1 for \n from fgets */ char *fgets_ret; int echo_off_status; memset(tmp, 0, MAX_LEN + 1); printf("Enter Password: "); echo_off_status = echo_off(); fgets_ret = fgets(tmp, MAX_LEN + 1, stdin); tmp[strlen(tmp) - 1] = '\0'; /* remove the /n that fgets gives */ strncpy(passwd, tmp, MAX_LEN); /* Since echo_on depends on whether echo_off succeeded or not, do echo_on only if echo_off went fine */ if (0 == echo_off_status) echo_on(); } static int get_hash_via_env_var(char *hash) { int fd; char *ob_key; struct stat stat_info; char *p; if (NULL == (ob_key = (char *) getenv("gtm_obfuscation_key"))) return 1; fd = open(ob_key, O_RDONLY); if (fd == -1) return 1; if (fstat(fd, &stat_info) == -1) return 1; if (!S_ISREG(stat_info.st_mode)) return 1; p = mmap(0, stat_info.st_size, PROT_READ, MAP_SHARED, fd, 0); if (MAP_FAILED == p) return 1; if (-1 == close(fd)) return 1; # ifdef USE_OPENSSL EVP_Digest(p, stat_info.st_size, (unsigned char *)hash, NULL, EVP_sha512(), NULL); # elif defined USE_GCRYPT gcry_md_hash_buffer(GCRY_MD_SHA512, hash, p, stat_info.st_size ); # endif /* Since we have what we want no need to check the status of the munmap */ munmap(p, stat_info.st_size); return 0; } static int get_hash_via_username_and_inode(char *hash, char *passwd, size_t *passwd_len) { char tmp[MAX_LEN], tobehashed[MAX_LEN]; char mumps_ex[GTM_PATH_MAX], *user_ptr, *dist_ptr; size_t ilen; struct stat stat_info; memset(tobehashed, 0, MAX_LEN); memset(mumps_ex, 0, GTM_PATH_MAX); /* We need $USER and $gtm_dist to be defined to do the proper masking */ if (NULL == (user_ptr = (char *)getenv("USER"))) { printf("Environment variable USER not defined.\n"); return 1; } if (NULL == (dist_ptr = (char *)getenv(GTM_DIST))) { printf("Enivronment variable gtm_dist not defined.\n"); return 1; } snprintf(mumps_ex, GTM_PATH_MAX, "%s/%s", dist_ptr, "mumps"); if (0 != stat(mumps_ex, &stat_info)) { printf("Cannot stat %s\n", mumps_ex); return 1; } prompt_passwd(passwd); *passwd_len = strlen(passwd); strncpy(tobehashed, user_ptr, MIN(*passwd_len, MAX_LEN)); snprintf(tmp, MAX_LEN, "%ld", stat_info.st_ino); ilen = strlen(tmp); /* a potential simplification is to just concatenate the userid and inode */ if (ilen < *passwd_len) strncpy(tobehashed + (*passwd_len - ilen), tmp, ilen); else strncpy(tobehashed, tmp, *passwd_len); # ifdef USE_OPENSSL EVP_Digest(tobehashed, *passwd_len, (unsigned char *)hash, NULL, EVP_sha512(), NULL); # elif defined USE_GCRYPT gcry_md_hash_buffer(GCRY_MD_SHA512, hash, tobehashed, *passwd_len ); # endif return 0; } int main() { char passwd[MAX_LEN], hash[HASH_LENGTH], out[MAX_LEN * 2]; size_t passwd_len; # ifdef USE_GCRYPT gcry_error_t err; /* Initialize libgcrypt so it does not put warning messages in the syslog. */ if (!gcry_check_version(GCRYPT_VERSION)) { printf("libgcrypt version mismatch. %s or higher is required.\n", GCRYPT_VERSION); exit(1); } /* Since we will just be hashing, secure memory is not needed. */ if (!(err = gcry_control(GCRYCTL_DISABLE_SECMEM,0))) err = gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); if (GPG_ERR_NO_ERROR != err) { printf("Libgcrypt error: %s\n", gcry_strerror(err)); exit(1); } # endif passwd_len = -1; memset(passwd, 0, MAX_LEN); memset(out, 0, MAX_LEN * 2); if (get_hash_via_env_var(hash)) if (get_hash_via_username_and_inode(hash, passwd, &passwd_len)) exit(1); if (-1 == passwd_len) { prompt_passwd(passwd); passwd_len = strlen(passwd); } maskpass(passwd, passwd_len, hash, HASH_LENGTH); HEX(passwd, out, passwd_len * 2); printf("%s\n", out); return 0; }