• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 24053024312

06 Apr 2026 09:51PM UTC coverage: 91.831% (+2.4%) from 89.454%
24053024312

Pull #5521

github

web-flow
Merge 89fecf072 into 417709dd7
Pull Request #5521: Rollup of small fixes

108699 of 118368 relevant lines covered (91.83%)

11266117.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.25
/src/cli/pk_crypt.cpp
1
/*
2
* (C) 2018 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include "cli.h"
8

9
#if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_AEAD_MODES) && defined(BOTAN_HAS_EME_OAEP) && \
10
   defined(BOTAN_HAS_SHA2_32) && defined(BOTAN_HAS_PEM_CODEC) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
11

12
   #include <botan/aead.h>
13
   #include <botan/ber_dec.h>
14
   #include <botan/der_enc.h>
15
   #include <botan/pem.h>
16
   #include <botan/pkcs8.h>
17
   #include <botan/pubkey.h>
18
   #include <botan/rng.h>
19
   #include <botan/x509_key.h>
20

21
namespace Botan_CLI {
22

23
namespace {
24

25
class PK_Encrypt final : public Command {
26
   public:
27
      PK_Encrypt() : Command("pk_encrypt --aead=AES-256/GCM pubkey datafile") {}
4✔
28

29
      std::string group() const override { return "pubkey"; }
1✔
30

31
      std::string description() const override { return "Encrypt a file using a RSA public key"; }
1✔
32

33
      void go() override {
1✔
34
         auto key = Botan::X509::load_key(get_arg("pubkey"));
2✔
35
         if(!key) {
1✔
36
            throw CLI_Error("Unable to load public key");
×
37
         }
38

39
         if(key->algo_name() != "RSA") {
1✔
40
            throw CLI_Usage_Error("This function requires an RSA key");
×
41
         }
42

43
         const std::string OAEP_HASH = "SHA-256";
1✔
44
         const std::string aead_algo = get_arg("aead");
1✔
45

46
         std::unique_ptr<Botan::AEAD_Mode> aead = Botan::AEAD_Mode::create(aead_algo, Botan::Cipher_Dir::Encryption);
1✔
47

48
         if(!aead) {
1✔
49
            throw CLI_Usage_Error("The AEAD '" + aead_algo + "' is not available");
×
50
         }
51

52
         const Botan::OID aead_oid = Botan::OID::from_string(aead_algo);
1✔
53
         if(aead_oid.empty()) {
1✔
54
            throw CLI_Usage_Error("No OID defined for AEAD '" + aead_algo + "'");
×
55
         }
56

57
         Botan::secure_vector<uint8_t> data;
1✔
58
         auto insert_fn = [&](const uint8_t b[], size_t l) { data.insert(data.end(), b, b + l); };
1✔
59
         Command::read_file(get_arg("datafile"), insert_fn);
2✔
60

61
         const Botan::AlgorithmIdentifier hash_id(OAEP_HASH, Botan::AlgorithmIdentifier::USE_EMPTY_PARAM);
1✔
62
         const Botan::AlgorithmIdentifier pk_alg_id("RSA/OAEP", hash_id.BER_encode());
1✔
63

64
         const Botan::PK_Encryptor_EME enc(*key, rng(), "OAEP(" + OAEP_HASH + ")");
3✔
65

66
         const Botan::secure_vector<uint8_t> file_key = rng().random_vec(aead->key_spec().maximum_keylength());
1✔
67

68
         const std::vector<uint8_t> encrypted_key = enc.encrypt(file_key, rng());
1✔
69

70
         const Botan::secure_vector<uint8_t> nonce = rng().random_vec(aead->default_nonce_length());
1✔
71
         aead->set_key(file_key);
1✔
72
         aead->set_associated_data(encrypted_key);
1✔
73
         aead->start(nonce);
1✔
74

75
         aead->finish(data);
1✔
76

77
         std::vector<uint8_t> buf;
1✔
78
         Botan::DER_Encoder der(buf);
1✔
79

80
         der.start_sequence()
1✔
81
            .encode(pk_alg_id)
1✔
82
            .encode(encrypted_key, Botan::ASN1_Type::OctetString)
1✔
83
            .encode(aead_oid)
1✔
84
            .encode(nonce, Botan::ASN1_Type::OctetString)
1✔
85
            .encode(data, Botan::ASN1_Type::OctetString)
1✔
86
            .end_cons();
1✔
87

88
         output() << Botan::PEM_Code::encode(buf, "PUBKEY ENCRYPTED MESSAGE", 72);
1✔
89
      }
9✔
90
};
91

92
BOTAN_REGISTER_COMMAND("pk_encrypt", PK_Encrypt);
2✔
93

94
class PK_Decrypt final : public Command {
95
   public:
96
      PK_Decrypt() : Command("pk_decrypt privkey datafile") {}
4✔
97

98
      std::string group() const override { return "pubkey"; }
1✔
99

100
      std::string description() const override { return "Decrypt a file using a RSA private key"; }
1✔
101

102
      void go() override {
1✔
103
         Botan::DataSource_Stream input_stream(get_arg("privkey"));
2✔
104
         auto get_pass = [this]() { return get_passphrase("Password"); };
×
105
         std::unique_ptr<Botan::Private_Key> key = Botan::PKCS8::load_key(input_stream, get_pass);
1✔
106

107
         if(!key) {
1✔
108
            throw CLI_Error("Unable to load public key");
×
109
         }
110

111
         if(key->algo_name() != "RSA") {
1✔
112
            throw CLI_Usage_Error("This function requires an RSA key");
×
113
         }
114

115
         Botan::secure_vector<uint8_t> data;
1✔
116
         std::vector<uint8_t> encrypted_key;
1✔
117
         std::vector<uint8_t> nonce;
1✔
118
         Botan::AlgorithmIdentifier pk_alg_id;
1✔
119
         Botan::OID aead_oid;
1✔
120

121
         try {
1✔
122
            Botan::DataSource_Stream input(get_arg("datafile"));
2✔
123

124
            Botan::BER_Decoder(Botan::PEM_Code::decode_check_label(input, "PUBKEY ENCRYPTED MESSAGE"),
2✔
125
                               Botan::BER_Decoder::Limits::DER())
126
               .start_sequence()
1✔
127
               .decode(pk_alg_id)
1✔
128
               .decode(encrypted_key, Botan::ASN1_Type::OctetString)
1✔
129
               .decode(aead_oid)
1✔
130
               .decode(nonce, Botan::ASN1_Type::OctetString)
1✔
131
               .decode(data, Botan::ASN1_Type::OctetString)
1✔
132
               .end_cons();
1✔
133
         } catch(Botan::Decoding_Error&) {
1✔
134
            error_output() << "Parsing input file failed: invalid format?\n";
×
135
            return set_return_code(1);
×
136
         }
×
137

138
         const std::string aead_algo = aead_oid.human_name_or_empty();
1✔
139
         if(aead_algo.empty()) {
1✔
140
            error_output() << "Ciphertext was encrypted with an unknown algorithm";
×
141
            return set_return_code(1);
×
142
         }
143

144
         if(pk_alg_id.oid() != Botan::OID::from_string("RSA/OAEP")) {
1✔
145
            error_output() << "Ciphertext was encrypted with something other than RSA/OAEP";
×
146
            return set_return_code(1);
×
147
         }
148

149
         Botan::AlgorithmIdentifier oaep_hash_id;
1✔
150
         Botan::BER_Decoder(pk_alg_id.parameters(), Botan::BER_Decoder::Limits::DER()).decode(oaep_hash_id);
1✔
151

152
         const std::string oaep_hash = oaep_hash_id.oid().human_name_or_empty();
1✔
153

154
         if(oaep_hash.empty()) {
1✔
155
            error_output() << "Unknown hash function used with OAEP, OID " << oaep_hash_id.oid().to_string() << "\n";
×
156
            return set_return_code(1);
×
157
         }
158

159
         if(!oaep_hash_id.parameters().empty()) {
1✔
160
            error_output() << "Unknown OAEP parameters used\n";
×
161
            return set_return_code(1);
×
162
         }
163

164
         std::unique_ptr<Botan::AEAD_Mode> aead =
1✔
165
            Botan::AEAD_Mode::create_or_throw(aead_algo, Botan::Cipher_Dir::Decryption);
1✔
166

167
         const size_t expected_keylen = aead->key_spec().maximum_keylength();
1✔
168

169
         const Botan::PK_Decryptor_EME dec(*key, rng(), "OAEP(" + oaep_hash + ")");
3✔
170

171
         const Botan::secure_vector<uint8_t> file_key =
1✔
172
            dec.decrypt_or_random(encrypted_key.data(), encrypted_key.size(), expected_keylen, rng());
1✔
173

174
         aead->set_key(file_key);
1✔
175
         aead->set_associated_data(encrypted_key);
1✔
176
         aead->start(nonce);
1✔
177

178
         try {
1✔
179
            aead->finish(data);
1✔
180

181
            write_output(data);
1✔
182
         } catch(Botan::Integrity_Failure&) {
×
183
            error_output() << "Message authentication failure, possible ciphertext tampering\n";
×
184
            return set_return_code(1);
×
185
         }
×
186
      }
6✔
187
};
188

189
BOTAN_REGISTER_COMMAND("pk_decrypt", PK_Decrypt);
2✔
190

191
}  // namespace
192

193
}  // namespace Botan_CLI
194

195
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc