File indexing completed on 2024-05-05 04:49:51
0001 /**************************************************************************************** 0002 * Copyright (c) 2009 Jakob Kummerow <jakob.kummerow@gmail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #include "signer.h" 0018 0019 #include "../../shared/ScriptUpdaterStatic.h" 0020 0021 #include <QFile> 0022 #include <QTimer> 0023 #include <iostream> 0024 0025 #include <pwd.h> 0026 0027 signer::signer() 0028 { 0029 } 0030 0031 signer::~signer() 0032 {} 0033 0034 bool signer::setParams(int argc, char** argv) 0035 { 0036 if (argc > 1) { 0037 0038 // first code block: generate key pair and save to local files 0039 if ( strcmp( argv[1], "keygen" ) == 0 ) { 0040 QTimer::singleShot( 0, this, SLOT(keygen()) ); 0041 return 1; 0042 0043 // second code block: sign a given file 0044 } else if ( strcmp( argv[1], "sign" ) == 0 ) { 0045 m_privkeyFilename = argv[2]; 0046 QTimer::singleShot( 0, this, SLOT(signFile()) ); 0047 0048 return 1; 0049 // third code block: check a given file 0050 } else if ( strcmp( argv[1], "check" ) == 0 ) { 0051 m_pubkeyFilename = argv[2]; 0052 QTimer::singleShot( 0, this, SLOT(checkSignature()) ); 0053 return 1; 0054 } 0055 } 0056 std::cout << "Usage: \n" 0057 "\"" << argv[0] << " keygen\" to create a new key pair and store it in the \n" 0058 "\tcurrent directory\n" 0059 0060 "\"" << argv[0] << " sign <privateKey>\" to create a signature for both \n" 0061 "\t'" << archiveFilename.toLatin1().data() << "' and '" << versionFilename.toLatin1().data() << "' and store it as '" << signatureFilename.toLatin1().data() << "', using \n" 0062 "\tthe private key file <privateKey>.\n" 0063 0064 "\"" << argv[0] << " check <publicKey>\" to check if the signature found in \n" 0065 "\tthe file '" << signatureFilename.toLatin1().data() << "' matches both '" << archiveFilename.toLatin1().data() << "' and '" << versionFilename.toLatin1().data() << "', \n" 0066 "\tusing the public key file <publicKey>\n"; 0067 return false; 0068 } 0069 0070 void 0071 signer::keygen() 0072 { 0073 QCA::Initializer init; 0074 // only start this "loop" so that we can jump to the end of it using "continue" 0075 for ( int temp = 0; temp < 1; temp++ ) { 0076 if( !QCA::isSupported( "pkey" ) || !QCA::PKey::supportedIOTypes().contains( QCA::PKey::RSA ) ) 0077 { 0078 std::cout << "RSA not supported on this system!\n"; 0079 continue; 0080 } 0081 QCA::PrivateKey seckey = QCA::KeyGenerator().createRSA( 2048 ); 0082 if( seckey.isNull() ) { 0083 std::cout << "Failed to make private RSA key!\n"; 0084 continue; 0085 } 0086 QCA::PublicKey pubkey = seckey.toPublicKey(); 0087 QCA::SecureArray passPhrase( getpass( "Please enter a passphrase for the new private key: " ) ); 0088 QCA::SecureArray passPhraseConfirm( getpass( "Please confirm the passphrase: " ) ); 0089 if ( passPhrase != passPhraseConfirm ) 0090 { 0091 std::cout << "Passphrases do not match, aborting.\n"; 0092 continue; 0093 } 0094 seckey.toPEMFile( "privkey.pem", passPhrase ); 0095 pubkey.toPEMFile( "pubkey.pem" ); 0096 std::cout << "Keys generated and saved to file; have fun!\n"; 0097 } 0098 this->thread()->quit(); 0099 } 0100 0101 void 0102 signer::signFile() 0103 { 0104 std::cout << "signing file " << archiveFilename.toLatin1().data() << "...\n"; 0105 QCA::Initializer init; 0106 // only start this "loop" so that we can jump to the end of it using "continue" 0107 for ( int temp = 0; temp < 1; temp++ ) { 0108 QCA::SecureArray passPhrase( getpass("Please enter the passphrase for the private key: ") ); 0109 QCA::ConvertResult conversionResult; 0110 QCA::PrivateKey seckey = QCA::PrivateKey::fromPEMFile( m_privkeyFilename, passPhrase, &conversionResult ); 0111 if (! ( QCA::ConvertGood == conversionResult ) ) { 0112 std::cout << "Failed to read private key!\n"; 0113 continue; 0114 } 0115 QFile file( archiveFilename ); 0116 if ( !file.open( QIODevice::ReadOnly ) ) { 0117 std::cout << "Failed to open archive file for reading!\n"; 0118 continue; 0119 } 0120 QCA::Hash hash( "sha1" ); 0121 hash.update( &file ); 0122 file.close(); 0123 QFile versionFile( versionFilename ); 0124 if ( !versionFile.open( QIODevice::ReadOnly ) ) { 0125 std::cout << "failed to open version file for reading!\n"; 0126 continue; 0127 } 0128 QCA::Hash versionHash( "sha1" ); 0129 versionHash.update( &versionFile ); 0130 versionFile.close(); 0131 seckey.startSign( QCA::EMSA3_SHA1 ); 0132 seckey.update( hash.final() ); 0133 seckey.update( versionHash.final() ); 0134 QByteArray signature = seckey.signature(); 0135 QFile sigFile( signatureFilename ); 0136 if ( !sigFile.open(QIODevice::WriteOnly) ) { 0137 std::cout << "Failed to open signature file for writing!\n"; 0138 continue; 0139 } 0140 sigFile.write( signature.toBase64() ); 0141 sigFile.close(); 0142 std::cout << "Signature written to " << sigFile.fileName().toLatin1().data() << "\n"; 0143 } 0144 this->thread()->quit(); 0145 } 0146 0147 void 0148 signer::checkSignature() 0149 { 0150 std::cout << "checking file " << archiveFilename.toLatin1().data() << "...\n"; 0151 QCA::Initializer init; 0152 // only start this "loop" so that we can jump to the end of it using "continue" 0153 for ( int temp = 0; temp < 1; temp++ ) { 0154 QFile pubkeyfile( m_pubkeyFilename ); 0155 if ( !pubkeyfile.open( QIODevice::ReadOnly ) ) 0156 { 0157 std::cout << "Failed to open public key file!\n"; 0158 continue; 0159 } 0160 QString pubkeystring = pubkeyfile.readAll(); 0161 pubkeyfile.close(); 0162 QCA::ConvertResult conversionResult; 0163 QCA::PublicKey pubkey = QCA::PublicKey::fromPEM( pubkeystring, &conversionResult ); 0164 if ( !( QCA::ConvertGood == conversionResult ) ) 0165 { 0166 std::cout << "Failed to read public key!\n"; 0167 continue; 0168 } 0169 QFile file( archiveFilename ); 0170 if ( !file.open( QIODevice::ReadOnly ) ) { 0171 std::cout << "Failed to open archive file for reading!\n"; 0172 continue; 0173 } 0174 QCA::Hash hash( "sha1" ); 0175 hash.update( &file ); 0176 file.close(); 0177 QFile versionFile( versionFilename ); 0178 if ( !versionFile.open( QIODevice::ReadOnly ) ) { 0179 std::cout << "Failed to open version file for reading!\n"; 0180 continue; 0181 } 0182 QCA::Hash versionHash( "sha1" ); 0183 versionHash.update( &versionFile ); 0184 versionFile.close(); 0185 QFile sigFile( signatureFilename ); 0186 if ( !sigFile.open( QIODevice::ReadOnly ) ) 0187 { 0188 std::cout << "Failed to open signature file for reading!\n"; 0189 continue; 0190 } 0191 QByteArray signature = QByteArray::fromBase64( sigFile.readAll() ); 0192 pubkey.startVerify( QCA::EMSA3_SHA1 ); 0193 pubkey.update( hash.final() ); 0194 pubkey.update( versionHash.final() ); 0195 if ( !pubkey.validSignature( signature ) ) 0196 { 0197 std::cout << "Invalid signature!\n"; 0198 continue; 0199 } 0200 std::cout << "Signature verified :-)\n"; 0201 } 0202 this->thread()->quit(); 0203 } 0204