File indexing completed on 2024-09-15 04:15:56
0001 /* 0002 Copyright (C) 2003 Justin Karneges <justin@affinix.com> 0003 Copyright (C) 2005 Brad Hards <bradh@frogmouth.net> 0004 0005 Permission is hereby granted, free of charge, to any person obtaining a copy 0006 of this software and associated documentation files (the "Software"), to deal 0007 in the Software without restriction, including without limitation the rights 0008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 0009 copies of the Software, and to permit persons to whom the Software is 0010 furnished to do so, subject to the following conditions: 0011 0012 The above copyright notice and this permission notice shall be included in 0013 all copies or substantial portions of the Software. 0014 0015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 0018 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 0019 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 0020 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0021 */ 0022 0023 #include <QCoreApplication> 0024 #include <QtCrypto> 0025 0026 #include <iostream> 0027 0028 #ifdef QT_STATICPLUGIN 0029 #include "import_plugins.h" 0030 #endif 0031 0032 int main(int argc, char **argv) 0033 { 0034 // The Initializer object sets things up, and also 0035 // does cleanup when it goes out of scope 0036 QCA::Initializer init; 0037 0038 QCoreApplication app(argc, argv); 0039 0040 // we use the first argument if provided, or 0041 // use "hello" if no arguments 0042 QCA::SecureArray arg = (argc >= 2) ? argv[1] : "hello"; 0043 0044 // We demonstrate PEM usage here, so we need to test for 0045 // supportedIOTypes, not just supportedTypes 0046 if (!QCA::isSupported("pkey") || !QCA::PKey::supportedIOTypes().contains(QCA::PKey::RSA)) 0047 std::cout << "RSA not supported!\n"; 0048 else { 0049 // When creating a public / private key pair, you make the 0050 // private key, and then extract the public key component from it 0051 // Using RSA is very common, however DSA can provide equivalent 0052 // signature/verification. This example applies to DSA to the 0053 // extent that the operations work on that key type. 0054 0055 // QCA provides KeyGenerator as a convenient source of new keys, 0056 // however you could also import an existing key instead. 0057 QCA::PrivateKey seckey = QCA::KeyGenerator().createRSA(1024); 0058 if (seckey.isNull()) { 0059 std::cout << "Failed to make private RSA key" << std::endl; 0060 return 1; 0061 } 0062 0063 QCA::PublicKey pubkey = seckey.toPublicKey(); 0064 0065 // check if the key can encrypt 0066 if (!pubkey.canEncrypt()) { 0067 std::cout << "Error: this kind of key cannot encrypt" << std::endl; 0068 return 1; 0069 } 0070 0071 // encrypt some data - note that only the public key is required 0072 // you must also choose the algorithm to be used 0073 QCA::SecureArray result = pubkey.encrypt(arg, QCA::EME_PKCS1_OAEP); 0074 if (result.isEmpty()) { 0075 std::cout << "Error encrypting" << std::endl; 0076 return 1; 0077 } 0078 0079 // output the encrypted data 0080 QString rstr = QCA::arrayToHex(result.toByteArray()); 0081 std::cout << "\"" << arg.data() << "\" encrypted with RSA is \""; 0082 std::cout << qPrintable(rstr) << "\"" << std::endl; 0083 0084 // save the private key - in a real example, make sure this goes 0085 // somewhere secure and has a good pass phrase 0086 // You can use the same technique with the public key too. 0087 QCA::SecureArray passPhrase = "pass phrase"; 0088 seckey.toPEMFile(QStringLiteral("keyprivate.pem"), passPhrase); 0089 0090 // Read that key back in, checking if the read succeeded 0091 QCA::ConvertResult conversionResult; 0092 QCA::PrivateKey privateKey = 0093 QCA::PrivateKey::fromPEMFile(QStringLiteral("keyprivate.pem"), passPhrase, &conversionResult); 0094 if (!(QCA::ConvertGood == conversionResult)) { 0095 std::cout << "Private key read failed" << std::endl; 0096 } 0097 0098 // now decrypt that encrypted data using the private key that 0099 // we read in. The algorithm is the same. 0100 QCA::SecureArray decrypt; 0101 if (0 == privateKey.decrypt(result, &decrypt, QCA::EME_PKCS1_OAEP)) { 0102 std::cout << "Error decrypting.\n"; 0103 return 1; 0104 } 0105 0106 // output the resulting decrypted string 0107 std::cout << "\"" << qPrintable(rstr) << "\" decrypted with RSA is \""; 0108 std::cout << decrypt.data() << "\"" << std::endl; 0109 0110 // Some private keys can also be used for producing signatures 0111 if (!privateKey.canSign()) { 0112 std::cout << "Error: this kind of key cannot sign" << std::endl; 0113 return 1; 0114 } 0115 privateKey.startSign(QCA::EMSA3_MD5); 0116 privateKey.update(arg); // just reuse the same message 0117 QByteArray argSig = privateKey.signature(); 0118 0119 // instead of using the startSign(), update(), signature() calls, 0120 // you may be better doing the whole thing in one go, using the 0121 // signMessage call. Of course you need the whole message in one 0122 // hit, which may or may not be a problem 0123 0124 // output the resulting signature 0125 rstr = QCA::arrayToHex(argSig); 0126 std::cout << "Signature for \"" << arg.data() << "\" using RSA, is "; 0127 std::cout << "\"" << qPrintable(rstr) << "\"" << std::endl; 0128 0129 // to check a signature, we must check that the key is 0130 // appropriate 0131 if (pubkey.canVerify()) { 0132 pubkey.startVerify(QCA::EMSA3_MD5); 0133 pubkey.update(arg); 0134 if (pubkey.validSignature(argSig)) { 0135 std::cout << "Signature is valid" << std::endl; 0136 } else { 0137 std::cout << "Bad signature" << std::endl; 0138 } 0139 } 0140 0141 // We can also do the verification in a single step if we 0142 // have all the message 0143 if (pubkey.canVerify() && pubkey.verifyMessage(arg, argSig, QCA::EMSA3_MD5)) { 0144 std::cout << "Signature is valid" << std::endl; 0145 } else { 0146 std::cout << "Signature could not be verified" << std::endl; 0147 } 0148 } 0149 0150 return 0; 0151 }