#!/usr/bin/python3 # protects a private key file with random data from the entropy file. # the selection of random data depends on the user provided passphrase """ * File : pcp2-protect-privatekey [ part of the Pure Crypto Project ] * * Version : 2.0 * Date : 7 Jan 2025 * License : BSD * * Copyright (c) 2003 - 2025 * 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. * """ import sys, os # default intallation path for pcp modules sys.path.append("/usr/share/pcp2") import pure EOL = "\n" PASS = "" MinPassLength = 10 # characters ASKPASS = "/usr/bin/systemd-ask-password" if not os.path.isfile(ASKPASS) : print ("Error: Please install " + ASKPASS + " to ensure safe password input") ASKPASS = "" #-----------------------------------------------------------# def change_Privatekey_Encryption(P): # calculate PAD for otp method Hash = pure.hash256(pure.Line(pure.toBytes(P))) ProtectedPrivatekey = 0 ProtectedPrivatekey = pure.unlock_privatekey(Hash) Hash = pure.Modulus # burning of sensitive information pure.print_securityhash(True) if ProtectedPrivatekey : # write to file sys.argv[2] KeyData = "" KeyData = KeyData + "Modulus = " + str(pure.Modulus) + EOL KeyData = KeyData + "Encryption = " + str(pure.Encryption) + EOL KeyData = KeyData + "Decryption = " + str(ProtectedPrivatekey) + EOL ProtectedPrivatekey = pure.Modulus # burning KeyData = KeyData + "Hashmodulus = " + str(pure.HashModulus) + EOL KeyData = KeyData + "Generator = " + str(pure.Generator) + EOL KeyData = KeyData + pure.toString(pure.UserID) + EOL KeyData = KeyData + "Securityhash = " + str(pure.Securityhash) + EOL KeyData = KeyData + "Protection = " + pure.protected + EOL pure.burn_privatekey() print (EOL + "New key data: " + EOL) print (KeyData) try: FILE = open(sys.argv[2], "w") FILE.write(KeyData) FILE.close() # restrict file permissions to -rw------- os.system("chmod 600 " + sys.argv[2]) print("You can now replace your RSA key " + pure.Home + Keyfilename + " with the content of the file "+ sys.argv[2] + "." ) print() print("Please check the differences with: diff "+ pure.Home + Keyfilename + " " + sys.argv[2]) except: print ("Unable to write the protected key data to file.") sys.exit(3) #-----------------------------------------------------------# if len(sys.argv) != 3: print ("usage: pcp2-protect-privatekey \"encryptionkey\" | \"signingkey\" outfile") sys.exit(3) pure.print_banner() if sys.argv[1] == "encryptionkey" : Keyfilename = "encryptionkey" print ("Reading data from "+ pure.Home + Keyfilename) elif sys.argv[1] == "signingkey" : Keyfilename = "signingkey" print ("Reading data from " + pure.Home + "signingkey") else: print ("Cannot read data from either signingkey or encryptionkey") sys.exit(2) pure.read_cryptosystem(Keyfilename,True) print () print ("The protection of your private key is : " ,pure.toString(pure.protected)) print () print ("****************************************") print ("Modulus = " + str(pure.Modulus)) print ("Encryption = " + str(pure.Encryption)) print ("Hashmodulus = " + str(pure.HashModulus)) print ("Generator = " + str(pure.Generator)) print (pure.toString(pure.UserID)) print ("Securityhash = " + str(pure.Securityhash)) print ("****************************************") PASS = "yes" PASS2 = "no" if pure.protected == b'otp' : pure.load_privatekey() print("Trying to protect your RSA private key with a passphrase ...") print ("Your new passphrase must be at least ",MinPassLength , " characters long.") pure.protected = "otp" if ASKPASS : while PASS2 != PASS : print("Please enter your new passphrase to protect your private key : ") PASS = pure.unix(ASKPASS) print () print("Please enter your new passphrase twice : ") PASS2 = pure.unix(ASKPASS) else: if pure.OS == "unix": while PASS2 != PASS : os.system("stty -echo") print () PASS = input("Please enter your new passphrase to protect your private key : ") print () PASS2 = input("Please enter your new passphrase twice : ") os.system("stty echo") if len(PASS) > MinPassLength : print () change_Privatekey_Encryption(PASS) else: print (EOL+EOL + "Your new passphrase is too short. The private key remains unchanged." + EOL) sys.exit(3) sys.exit (0) #-----------------------------------------------------------# # Copyright 2003 - 2025, Ralf Senderek, Ireland # #-----------------------------------------------------------#