#!/usr/bin/bash

if [ $(/usr/bin/id -u) != 0 ]; then echo "only root can do that"; exit 2; fi

#***************************************************************************
# This file is part of the CRYPTO BONE
# File     : createmasterkey
# Version  : 2.0 (ALL-IN-ONE)
# License  : BSD-3-Clause
# Date     : 24 May 2025
# Contact  : Please send enquiries and bug-reports to innovation@senderek.ie
#
#
# Copyright (c) 2015-2015
#	Ralf Senderek, Ireland.  All rights reserved. (https://senderek.ie)
#
# 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 ``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 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.
#****************************************************************************

# The existence of the link /usr/lib/cryptobone/masterkey signals whether the necessary 
# files that enable secure storage of secrets have been created or not.
# On first use, a 32 byte random key is stored in the directory /lib/cryptobone/keys in 
# OS file system base64 encoded. This key is stored in a file with a random name in a random
# directory, called $KEYS/$DIR/$FILE, and is used to encrypt a small filesystem with cryptsetup.
# (boot.fs)
#
# This key is accessible by the root user until the cryptobone daemon has been started during
# the boot process, and another filesystem (permanent.fs) has been mounted on the directory
# /lib/cryptobone/keys to replace the boot.fs.
# The boot.fs is filled with two secret pieces of information, the master.key used to encrypt
# the database file and the local.key, identifying the client machine and both sha256 fingerprints.
# Another unencrypted file system (permanent.fs) is generated that stores only the local.key and
# both sha256 fingerprints but not the master.key.


if [ ! -L /usr/lib/cryptobone/masterkey ]
then
          SELINUXMODE=$(sestatus | grep "Current mode:" | cut -c33-)
	  echo " Creating new masterkey ... "
	  KEYS="/usr/lib/cryptobone/keys"
               
	  # umount $KEYS,  if mounted. This should never happen!
          /bin/umount $KEYS 2> /dev/null > /dev/null

	  # this code is run at boot time!
	  RNDKEY=$KEYS/random
	       
	  # create and mount a boot.fs
	  if [ ! -f $RNDKEY ]
	  then
               /bin/dd if=/dev/urandom bs=1 count=32 2> /dev/null | base64 >  $RNDKEY
	       /bin/chmod 600 $RNDKEY
	       DIR=$(echo -n $(cat $KEYS/random) $(stat -c "directory %i" $KEYS) | sha256sum | cut -c-64)
	       /bin/mkdir $KEYS/$DIR
	       /bin/chmod 700 $KEYS/$DIR
	       FILE=$(echo -n $DIR $(stat -c "file %i"  $KEYS/random) | sha256sum | cut -c-64)
               /bin/dd if=/dev/urandom bs=1 count=32 2> /dev/null | /usr/bin/sha1sum | /usr/bin/cut -c-40 >  $KEYS/$DIR/$FILE
               # fill the new file system with (pseudo) random numbers
	       /bin/chmod 600 $KEYS/$DIR/$FILE
	       /bin/dd if=/dev/urandom of=$KEYS/boot.fs bs=1K count=300 2> /dev/null
	       /bin/chmod 600 $KEYS/boot.fs
	       L=$(losetup -f)
	       losetup $L $KEYS/boot.fs
	       cat $KEYS/$DIR/$FILE | cryptsetup create cryptobone $L
	       # create a small (32 inodes) file system
	       /usr/sbin/mkfs -t ext4 -N 32 /dev/mapper/cryptobone > /dev/null 2> /dev/null
	       /bin/umount /dev/mapper/cryptobone
	       cryptsetup remove cryptobone
	       losetup -d $L
          fi
	  if [ -f $KEYS/boot.fs ]
	  then
	       L=$(losetup -f)
	       losetup $L $KEYS/boot.fs
	       DIR=$(echo -n $(cat $KEYS/random) $(stat -c "directory %i" $KEYS) | sha256sum | cut -c-64)
	       FILE=$(echo -n $DIR $(stat -c "file %i"  $KEYS/random) | sha256sum | cut -c-64)
	       cat $KEYS/$DIR/$FILE | cryptsetup create cryptobone $L
	       if mount /dev/mapper/cryptobone $KEYS
	       then
	            touch $KEYS/BOOT
                    # Copy masterkey to /usr/lib/cryptobone/keys directory
		    if [ ! -r $KEYS/master.key ]
		    then
                         /bin/dd if=/dev/urandom bs=1 count=32 2> /dev/null | /usr/bin/sha1sum | /usr/bin/cut -c-40 >  $KEYS/master.key
                         /bin/chmod 600 $KEYS/master.key
	                 /usr/bin/sha256sum $KEYS/master.key | /usr/bin/cut -c-64 > $KEYS/master.key.sha256
	                 /bin/chmod 600 $KEYS/master.key $KEYS/master.key.sha256
                    fi
		    typeset -i NUM=3
                    if [ -r $KEYS/local.key ] ; then
		         NUM=$(wc -c $KEYS/local.key  | cut -f1 -d' ')
                    fi
		    if [ $NUM -lt 40 ]
		    then
                         /bin/dd if=/dev/urandom bs=1 count=32 2> /dev/null | /usr/bin/sha1sum | /usr/bin/cut -c-40 > $KEYS/local.key
	                 /usr/bin/sha256sum $KEYS/local.key | /usr/bin/cut -c-64 > $KEYS/local.key.sha256
	                 /bin/chmod 600 $KEYS/local.key $KEYS/local.key.sha256
	                 cd /usr/lib/cryptobone
	                 tar cpzf /usr/lib/cryptobone/keys.tgz keys/local.key keys/*256
		         /bin/chmod 400 /usr/lib/cryptobone/keys.tgz
		    fi
	            if [ -r $KEYS/master.key ] && [ -r $KEYS/local.key ] && [ -r /usr/lib/cryptobone/keys.tgz ]
                    then
                          # on success create link in /usr/lib/cryptobone
                         /bin/ln -s /tmp/masterkey /usr/lib/cryptobone/masterkey
                    fi
               fi
	       /bin/umount /dev/mapper/cryptobone
	       cryptsetup remove cryptobone
	       losetup -d $L

	       # now create a permanent.fs 
               /bin/dd if=/dev/urandom of=$KEYS/permanent.fs bs=1K count=300 2> /dev/null
	       /bin/chmod 600 $KEYS/permanent.fs
	       L=$(losetup -f)
	       losetup $L $KEYS/permanent.fs
	       /usr/sbin/mkfs -t ext4 -N 32 $L > /dev/null 2> /dev/null
	       
	       # mount permanent.fs temporarily
	       if /bin/mount $L $KEYS
               then
	            # copy all fingerprint files and the local key to permanent.fs
                    cd /usr/lib/cryptobone
	            tar xpzf keys.tgz
	            touch $KEYS/PERMANENT
		    /bin/sync
		    /bin/umount $L
                    losetup -d $L
	       fi
	       /bin/sync

	  fi
	  /bin/sync
	  exit 0
fi
