1//
2// genrsakey.cpp
3//
4// This sample demonstrates the XYZ class.
5//
6// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
7// and Contributors.
8//
9// SPDX-License-Identifier: BSL-1.0
10//
11
12
13#include "Poco/Util/Application.h"
14#include "Poco/Util/Option.h"
15#include "Poco/Util/OptionException.h"
16#include "Poco/Util/OptionSet.h"
17#include "Poco/Util/HelpFormatter.h"
18#include "Poco/Util/AbstractConfiguration.h"
19#include "Poco/AutoPtr.h"
20#include "Poco/NumberFormatter.h"
21#include "Poco/NumberParser.h"
22#include "Poco/String.h"
23#include "Poco/Crypto/RSAKey.h"
24#include <iostream>
25
26
27using Poco::Util::Application;
28using Poco::Util::Option;
29using Poco::Util::OptionSet;
30using Poco::Util::HelpFormatter;
31using Poco::Util::AbstractConfiguration;
32using Poco::Util::OptionCallback;
33using Poco::AutoPtr;
34using Poco::NumberParser;
35using Poco::Crypto::RSAKey;
36
37
38class RSAApp: public Application
39 /// This sample demonstrates some of the features of the Util::Application class,
40 /// such as configuration file handling and command line arguments processing.
41 ///
42 /// Try genrsakey --help (on Unix platforms) or genrsakey /help (elsewhere) for
43 /// more information.
44{
45public:
46 RSAApp():
47 _helpRequested(false),
48 _length(RSAKey::KL_1024),
49 _exp(RSAKey::EXP_LARGE),
50 _name(),
51 _pwd()
52 {
53 Poco::Crypto::initializeCrypto();
54 }
55
56 ~RSAApp()
57 {
58 Poco::Crypto::uninitializeCrypto();
59 }
60
61protected:
62 void initialize(Application& self)
63 {
64 loadConfiguration(); // load default configuration files, if present
65 Application::initialize(self);
66 }
67
68 void uninitialize()
69 {
70 Application::uninitialize();
71 }
72
73 void reinitialize(Application& self)
74 {
75 Application::reinitialize(self);
76 }
77
78 void defineOptions(OptionSet& options)
79 {
80 Application::defineOptions(options);
81
82 options.addOption(
83 Option("help", "h", "display help information on command line arguments")
84 .required(false)
85 .repeatable(false)
86 .callback(OptionCallback<RSAApp>(this, &RSAApp::handleHelp)));
87
88 options.addOption(
89 Option("?", "?", "display help information on command line arguments")
90 .required(false)
91 .repeatable(false)
92 .callback(OptionCallback<RSAApp>(this, &RSAApp::handleHelp)));
93
94 options.addOption(
95 Option("key", "k", "define the key length")
96 .required(false)
97 .repeatable(false)
98 .argument("512|1024|2048|4096")
99 .callback(OptionCallback<RSAApp>(this, &RSAApp::handleKeyLength)));
100
101 options.addOption(
102 Option("exponent", "e", "defines the exponent of the key")
103 .required(false)
104 .repeatable(false)
105 .argument("small|large")
106 .callback(OptionCallback<RSAApp>(this, &RSAApp::handleExponent)));
107
108 options.addOption(
109 Option("file", "f", "defines the file base name. creates a file.pub and a file.priv")
110 .required(true)
111 .repeatable(false)
112 .argument("filebasename")
113 .callback(OptionCallback<RSAApp>(this, &RSAApp::handleFilePrefix)));
114
115 options.addOption(
116 Option("password", "p", "defines the password used to encrypt the private key file. If not defined user will be asked via stdin to provide in")
117 .required(false)
118 .repeatable(false)
119 .argument("pwd")
120 .callback(OptionCallback<RSAApp>(this, &RSAApp::handlePassword)));
121 }
122
123 void handleHelp(const std::string& name, const std::string& value)
124 {
125 _helpRequested = true;
126 displayHelp();
127 stopOptionsProcessing();
128 }
129
130 void handleKeyLength(const std::string& name, const std::string& value)
131 {
132 int keyLen = Poco::NumberParser::parse(value);
133 if (keyLen == 512 || keyLen == 1024 || keyLen == 2048 || keyLen == 4096)
134 _length = (RSAKey::KeyLength)keyLen;
135 else
136 throw Poco::Util::IncompatibleOptionsException("Illegal key length value");
137 }
138
139 void handleExponent(const std::string& name, const std::string& value)
140 {
141 if (Poco::icompare(value, "small") == 0)
142 _exp = RSAKey::EXP_SMALL;
143 else
144 _exp = RSAKey::EXP_LARGE;
145 }
146
147 void handleFilePrefix(const std::string& name, const std::string& value)
148 {
149 if (value.empty())
150 throw Poco::Util::IncompatibleOptionsException("Empty file prefix forbidden");
151 _name = value;
152 }
153
154 void handlePassword(const std::string& name, const std::string& value)
155 {
156 _pwd = value;
157 }
158
159 void displayHelp()
160 {
161 HelpFormatter helpFormatter(options());
162 helpFormatter.setCommand(commandName());
163 helpFormatter.setUsage("OPTIONS");
164 helpFormatter.setHeader("Application for generating RSA public/private key pairs.");
165 helpFormatter.format(std::cout);
166 }
167
168 int main(const std::vector<std::string>& args)
169 {
170 if (!_helpRequested)
171 {
172 logger().information("Generating key with length " + Poco::NumberFormatter::format((int)_length));
173 logger().information(std::string("Exponent is ") + ((_exp == RSAKey::EXP_SMALL)?"small":"large"));
174 logger().information("Generating key");
175 RSAKey key(_length, _exp);
176 logger().information("Generating key: DONE");
177 std::string pubFile(_name + ".pub");
178 std::string privFile(_name + ".priv");
179
180 logger().information("Saving key to " + pubFile + " and " + privFile);
181 key.save(pubFile, privFile, _pwd);
182 logger().information("Key saved");
183 }
184 return Application::EXIT_OK;
185 }
186
187private:
188 bool _helpRequested;
189 RSAKey::KeyLength _length;
190 RSAKey::Exponent _exp;
191 std::string _name;
192 std::string _pwd;
193};
194
195
196POCO_APP_MAIN(RSAApp)
197