/* secure database * * This file is part of the CRYPTO BONE Project * File: initdatabase.c * Version : 1.5 (ALL-IN-ONE) * License : BSD * Date : 1. March 2023 * * Summary: * * Copyright (c) 2015-2023 * Ralf Senderek, Ireland. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Ralf Senderek. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *****************************************************/ #include #include #include #include #include #include #include "cryptlib.h" #include #include "armor.h" #define DEBUG 0 #define LARGE 1 #if LARGE #define MAXINPUT 250000 #define MAXWORD 66668 /* max number of bytes for a parameter through socket */ #else /* minimal, compatible with version 1.0.3*/ #define MAXINPUT 50000 #define MAXWORD 66668 /* max number of bytes for a parameter through socket */ #endif #define BYTE unsigned char #define DATABASEFILE "/usr/lib/cryptobone/database" #define DATABASEBACKUP "/usr/lib/cryptobone/database.back" #define INTERNAL_BUFFER_SIZE MAXINPUT+1024 #define MAXBUF 2*MAXINPUT #define KEYLEN 101 #define cryptUser CRYPT_UNUSED #define MAXBOOTSECONDS 120 unsigned char plaintext[MAXINPUT] ; unsigned char input[MAXBUF]; unsigned char output[MAXBUF*4/3]; /* output holds base64 encoded data and exceeds input */ unsigned char password[KEYLEN]; int passwordLength = 0; int status; int num; unsigned char *sptr = NULL; FILE *fp; /***************************************************************************************/ int get_masterkey(){ if (strlen(password) == 40) { return 0; } return -1; } /***************************************************************************************/ int aes_encrypt(){ /* * Reads from plaintext and writes the cryptogram to input and * base64-encoded to output. * output is stored in the database file */ FILE *fd; int newfd; if (get_masterkey() != 0){ printf("Error: no key, encryption failed."); return 4; } if (strlen(plaintext) >= MAXINPUT){ return 2; } int bytesCopied = 0; int plaintextLength = strlen(plaintext); if (plaintextLength == 0){ printf ("Error: plaintext is empty."); return 3; } CRYPT_ENVELOPE cryptEnvelope; status = cryptCreateEnvelope( &cryptEnvelope, cryptUser, CRYPT_FORMAT_CRYPTLIB ); if( status != CRYPT_OK ){ printf ("Error: Cryptlib enveloping."); return 3; } /* set internal buffer size */ status = cryptSetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_BUFFERSIZE, INTERNAL_BUFFER_SIZE ); /* Add the password */ passwordLength = strlen(password); if (passwordLength < 20){ printf ("Error: invalid key, encryption failed."); return 3; } if (passwordLength > 64){ printf ("Error: invalid key, encryption failed."); return 3; } if (DEBUG) printf("Using password of length %i\n",passwordLength); status = cryptSetAttributeString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD, password, passwordLength ); cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE, plaintextLength ); status = cryptPushData( cryptEnvelope, plaintext, plaintextLength, &bytesCopied ); status = cryptFlushData( cryptEnvelope ); /* create cryptogram in buffer input */ status = cryptPopData( cryptEnvelope, input, MAXBUF, &bytesCopied ); if (DEBUG) printf("encrypted Buffer has %i bytes\n", bytesCopied); if (status == CRYPT_OK){ status = base64encode(output, 2*MAXBUF, &num, input, bytesCopied, CRYPT_CERTTYPE_NONE); if (DEBUG) printf("base64 input %i bytes output %i bytes \n", bytesCopied, num); /* make backup of the database file */ fd = popen("/bin/touch /usr/lib/cryptobone/database", "r"); if (fd != NULL ){ pclose(fd); } fd = popen("/bin/cp /usr/lib/cryptobone/database /usr/lib/cryptobone/database.back", "r"); if (fd != NULL ){ pclose(fd); if (DEBUG) printf("backup created"); newfd = open(DATABASEBACKUP,O_RDWR); fchmod(newfd,S_IRUSR | S_IWUSR); close(newfd); } /* write result to file */ fp = fopen(DATABASEFILE,"w"); if (!fp){ printf("Error: database is not available"); return 5; } else { fputs(output,fp); fclose(fp); /* change file permissions to 0600 */ newfd = open(DATABASEFILE,O_RDWR); fchmod(newfd,S_IRUSR | S_IWUSR); close(newfd); } } status = cryptDestroyEnvelope( cryptEnvelope ); if( status != CRYPT_OK ){ printf("Error: Envelope cannot be destroyed."); return 4; } return 0; } /***************************************************************************************/ int this_is_boottime(){ char content[5]; /* read bootswitch file */ fp = fopen("/usr/lib/cryptobone/bootswitch","r"); if (!fp){ return -1; } else { sptr = fgets(content,5,fp); fclose(fp); if (atoi(content) < MAXBOOTSECONDS) { /* it's boot time */ return 0; } } return -1; } /*************************************************************************/ int main(void) { /* try to read the password if this is boot time */ if (this_is_boottime() == 0) { fp = fopen("/usr/lib/cryptobone/keys/master.key","r"); if (!fp){ printf ("Error: master key is not readable"); fclose(fp); exit(1); } else { sptr = fgets(password,41,fp); password[41] = '\0'; fclose(fp); printf ("Reading of master key succeeded\n"); /* check if the database exists, create a new one if not */ FILE *fptr = fopen(DATABASEFILE, "r"); if (! fptr) { printf ("Database INITIALISATION necessary!\n"); strlcpy(plaintext, "cryptobone:version 1.5\n", MAXINPUT); status = cryptInit(); cryptAddRandom( NULL, CRYPT_RANDOM_SLOWPOLL ); aes_encrypt(); status = cryptEnd(); printf ("Database INIT finished.\n"); } else { printf ("Database exists!\n"); fclose(fptr); } } } else { /* illegal start after boot time */ printf ("Error: boot time has elapsed. Terminating database init ... \n"); exit(6); } /* ZEROIZE password and plaintext */ for (int i=0; i < KEYLEN; i++){ password[i] = '\0'; } exit(0); }