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

randombit / botan / 5079590438

25 May 2023 12:28PM UTC coverage: 92.228% (+0.5%) from 91.723%
5079590438

Pull #3502

github

Pull Request #3502: Apply clang-format to the codebase

75589 of 81959 relevant lines covered (92.23%)

12139530.51 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
         const Botan::OID aead_oid = Botan::OID::from_string(aead_algo);
1✔
52
         if(aead_oid.empty())
1✔
53
            throw CLI_Usage_Error("No OID defined for AEAD '" + aead_algo + "'");
×
54

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

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

62
         Botan::PK_Encryptor_EME enc(*key, rng(), "OAEP(" + OAEP_HASH + ")");
2✔
63

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

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

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

73
         aead->finish(data);
1✔
74

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

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

86
         output() << Botan::PEM_Code::encode(buf, "PUBKEY ENCRYPTED MESSAGE", 72);
1✔
87
      }
8✔
88
};
89

90
BOTAN_REGISTER_COMMAND("pk_encrypt", PK_Encrypt);
2✔
91

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

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

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

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

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

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

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

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

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

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

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

146
         Botan::AlgorithmIdentifier oaep_hash_id;
1✔
147
         Botan::BER_Decoder(pk_alg_id.parameters()).decode(oaep_hash_id);
1✔
148

149
         const std::string oaep_hash = oaep_hash_id.oid().human_name_or_empty();
1✔
150

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

156
         if(oaep_hash_id.parameters().empty() == false) {
1✔
157
            error_output() << "Unknown OAEP parameters used\n";
×
158
            return set_return_code(1);
×
159
         }
160

161
         std::unique_ptr<Botan::AEAD_Mode> aead =
1✔
162
            Botan::AEAD_Mode::create_or_throw(aead_algo, Botan::Cipher_Dir::Decryption);
1✔
163

164
         const size_t expected_keylen = aead->key_spec().maximum_keylength();
1✔
165

166
         Botan::PK_Decryptor_EME dec(*key, rng(), "OAEP(" + oaep_hash + ")");
2✔
167

168
         const Botan::secure_vector<uint8_t> file_key =
1✔
169
            dec.decrypt_or_random(encrypted_key.data(), encrypted_key.size(), expected_keylen, rng());
1✔
170

171
         aead->set_key(file_key);
1✔
172
         aead->set_associated_data(encrypted_key);
1✔
173
         aead->start(nonce);
1✔
174

175
         try {
1✔
176
            aead->finish(data);
1✔
177

178
            output().write(reinterpret_cast<const char*>(data.data()), data.size());
1✔
179
         } catch(Botan::Integrity_Failure&) {
×
180
            error_output() << "Message authentication failure, possible ciphertext tampering\n";
×
181
            return set_return_code(1);
×
182
         }
×
183
      }
6✔
184
};
185

186
BOTAN_REGISTER_COMMAND("pk_decrypt", PK_Decrypt);
2✔
187

188
}
189

190
}
191

192
#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

© 2025 Coveralls, Inc