Exemple #1
0
/*
* Library Initialization
*/
void LibraryInitializer::initialize(const std::string& arg_string)
   {
   bool thread_safe = false;

   const std::vector<std::string> arg_list = split_on(arg_string, ' ');
   for(u32bit j = 0; j != arg_list.size(); ++j)
      {
      if(arg_list[j].size() == 0)
         continue;

      std::string name, value;

      if(arg_list[j].find('=') == std::string::npos)
         {
         name = arg_list[j];
         value = "true";
         }
      else
         {
         std::vector<std::string> name_and_value = split_on(arg_list[j], '=');
         name = name_and_value[0];
         value = name_and_value[1];
         }

      bool is_on =
         (value == "1" || value == "true" || value == "yes" || value == "on");

      if(name == "thread_safe")
         thread_safe = is_on;
      }

   try
      {
      /*
      This two stage initialization process is because Library_State's
      constructor will implicitly refer to global state through the
      allocators and so for, so global_state() has to be a valid
      reference before initialize() can be called. Yeah, gross.
      */
      set_global_state(new Library_State);

      global_state().initialize(thread_safe);
      }
   catch(...)
      {
      deinitialize();
      throw;
      }
   }
Exemple #2
0
/*
* Return the hash used in generating the signature
*/
std::string X509_Object::hash_used_for_signature() const
   {
   const OID& oid = m_sig_algo.get_oid();
   const std::vector<std::string> sig_info = split_on(OIDS::lookup(oid), '/');

   if(sig_info.size() == 1 && sig_info[0] == "Ed25519")
      return "SHA-512";
   else if(sig_info.size() != 2)
      throw Internal_Error("Invalid name format found for " + oid.as_string());

   if(sig_info[1] == "EMSA4")
      {
      return OIDS::lookup(decode_pss_params(signature_algorithm().get_parameters()).hash_algo.get_oid());
      }
   else
      {
      const std::vector<std::string> pad_and_hash =
         parse_algorithm_name(sig_info[1]);

      if(pad_and_hash.size() != 2)
         {
         throw Internal_Error("Invalid name format " + sig_info[1]);
         }

      return pad_and_hash[1];
      }
   }
Exemple #3
0
SRP6_Authenticator_File::SRP6_Authenticator_File(std::istream& in)
   {
   if(!in)
      return; // no entries

   while(in.good())
      {
      std::string line;
      std::getline(in, line);

      std::vector<std::string> parts = split_on(line, ':');

      if(parts.size() != 4)
         throw Decoding_Error("Invalid line in SRP authenticator file");

      std::string username = parts[0];
      BigInt v = BigInt::decode(base64_decode(parts[1]));
      std::vector<byte> salt = unlock(base64_decode(parts[2]));
      BigInt group_id_idx = BigInt::decode(base64_decode(parts[3]));

      std::string group_id;

      if(group_id_idx == 1)
         group_id = "modp/srp/1024";
      else if(group_id_idx == 2)
         group_id = "modp/srp/1536";
      else if(group_id_idx == 3)
         group_id = "modp/srp/2048";
      else
         continue; // unknown group, ignored

      m_entries[username] = SRP6_Data(v, salt, group_id);
      }
   }
Exemple #4
0
/*************************************************
* Initialize the certificate options             *
*************************************************/
X509_Cert_Options::X509_Cert_Options(const std::string& initial_opts,
                                     u32bit expiration_time_in_seconds)
   {
   is_CA = false;
   path_limit = 0;
   constraints = NO_CONSTRAINTS;

   const u32bit now = system_time();

   start = X509_Time(now);
   end = X509_Time(now + expiration_time_in_seconds);

   if(initial_opts == "")
      return;

   std::vector<std::string> parsed = split_on(initial_opts, '/');

   if(parsed.size() > 4)
      throw Invalid_Argument("X.509 cert options: Too many names: "
                             + initial_opts);

   if(parsed.size() >= 1) common_name  = parsed[0];
   if(parsed.size() >= 2) country      = parsed[1];
   if(parsed.size() >= 3) organization = parsed[2];
   if(parsed.size() == 4) org_unit     = parsed[3];
   }
Exemple #5
0
bool EAC_Signed_Object::check_signature(Public_Key& pub_key,
                                        const MemoryRegion<byte>& sig) const
   {
   try
      {
      std::vector<std::string> sig_info =
         split_on(OIDS::lookup(sig_algo.oid), '/');

      if(sig_info.size() != 2 || sig_info[0] != pub_key.algo_name())
         {
         return false;
         }

      std::string padding = sig_info[1];
      Signature_Format format =
         (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363;

      SecureVector<byte> to_sign = tbs_data();

      PK_Verifier verifier(pub_key, padding, format);
      return verifier.verify_message(to_sign, sig);
      }
   catch(...)
      {
      return false;
      }
   }
Exemple #6
0
/*
* Read a PEM or BER X.509 object
*/
void X509_Object::init(DataSource& in, const std::string& labels)
   {
   m_PEM_labels_allowed = split_on(labels, '/');
   if(m_PEM_labels_allowed.size() < 1)
      throw Invalid_Argument("Bad labels argument to X509_Object");

   m_PEM_label_pref = m_PEM_labels_allowed[0];
   std::sort(m_PEM_labels_allowed.begin(), m_PEM_labels_allowed.end());

   try {
      if(ASN1::maybe_BER(in) && !PEM_Code::matches(in))
         {
         BER_Decoder dec(in);
         decode_from(dec);
         }
      else
         {
         std::string got_label;
         DataSource_Memory ber(PEM_Code::decode(in, got_label));

         if(!std::binary_search(m_PEM_labels_allowed.begin(),
                                m_PEM_labels_allowed.end(), got_label))
            throw Decoding_Error("Invalid PEM label: " + got_label);

         BER_Decoder dec(ber);
         decode_from(dec);
         }
      }
   catch(Decoding_Error& e)
      {
      throw Decoding_Error(m_PEM_label_pref + " decoding failed: " + e.what());
      }
   }
Exemple #7
0
Certificate_Status_Code Response::verify_signature(const X509_Certificate& issuer) const
   {
   if (m_responses.empty())
      return m_dummy_response_status;
      
   try
      {
      std::unique_ptr<Public_Key> pub_key(issuer.subject_public_key());

      const std::vector<std::string> sig_info =
         split_on(OIDS::lookup(m_sig_algo.get_oid()), '/');

      if(sig_info.size() != 2 || sig_info[0] != pub_key->algo_name())
         return Certificate_Status_Code::OCSP_RESPONSE_INVALID;

      std::string padding = sig_info[1];
      Signature_Format format = (pub_key->message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363;

      PK_Verifier verifier(*pub_key, padding, format);

      if(verifier.verify_message(ASN1::put_in_sequence(m_tbs_bits), m_signature))
         return Certificate_Status_Code::OCSP_SIGNATURE_OK;
      else
         return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
      }
   catch(Exception&)
      {
      return Certificate_Status_Code::OCSP_SIGNATURE_ERROR;
      }
   }
Exemple #8
0
bool GeneralName::matches_ip(const std::string& nam) const
   {
   u32bit ip = string_to_ipv4(nam);
   std::vector<std::string> p = split_on(name(),'/');

   if(p.size() != 2)
      throw Decoding_Error("failed to parse IPv4 address");

   u32bit net = string_to_ipv4(p.at(0));
   u32bit mask = string_to_ipv4(p.at(1));

   return (ip & mask) == net;
   }
Exemple #9
0
/**
* DataSource_Command Constructor
*/
DataSource_Command::DataSource_Command(const std::string& prog_and_args,
                                       const std::vector<std::string>& paths) :
   MAX_BLOCK_USECS(100000), KILL_WAIT(10000)
   {
   arg_list = split_on(prog_and_args, ' ');

   if(arg_list.size() == 0)
      throw Invalid_Argument("DataSource_Command: No command given");
   if(arg_list.size() > 5)
      throw Invalid_Argument("DataSource_Command: Too many args");

   pipe = 0;
   create_pipe(paths);
   }
Exemple #10
0
/*
* Win32_Capi_Entropysource Constructor
*/
Win32_CAPI_EntropySource::Win32_CAPI_EntropySource(const std::string& provs)
   {
   std::vector<std::string> capi_provs = split_on(provs, ':');

   for(size_t i = 0; i != capi_provs.size(); ++i)
      {
      if(capi_provs[i] == "RSA_FULL")  m_prov_types.push_back(PROV_RSA_FULL);
      if(capi_provs[i] == "INTEL_SEC") m_prov_types.push_back(PROV_INTEL_SEC);
      if(capi_provs[i] == "FORTEZZA")  m_prov_types.push_back(PROV_FORTEZZA);
      if(capi_provs[i] == "RNG")       m_prov_types.push_back(PROV_RNG);
      }

   if(m_prov_types.size() == 0)
      m_prov_types.push_back(PROV_RSA_FULL);
   }
Exemple #11
0
/*
* Decode PKCS#5 PBES2 parameters
*/
void PBE_PKCS5v20::decode_params(DataSource& source)
   {
   AlgorithmIdentifier kdf_algo, enc_algo;

   BER_Decoder(source)
      .start_cons(SEQUENCE)
         .decode(kdf_algo)
         .decode(enc_algo)
         .verify_end()
      .end_cons();

   if(kdf_algo.oid == OIDS::lookup("PKCS5.PBKDF2"))
      {
      BER_Decoder(kdf_algo.parameters)
         .start_cons(SEQUENCE)
            .decode(salt, OCTET_STRING)
            .decode(iterations)
            .decode_optional(key_length, INTEGER, UNIVERSAL)
            .verify_end()
         .end_cons();
      }
   else
      throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " +
                           kdf_algo.oid.as_string());

   Algorithm_Factory& af = global_state().algorithm_factory();

   std::string cipher = OIDS::lookup(enc_algo.oid);
   std::vector<std::string> cipher_spec = split_on(cipher, '/');
   if(cipher_spec.size() != 2)
      throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);

   if(!known_cipher(cipher_spec[0]) || cipher_spec[1] != "CBC")
      throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " +
                           cipher);

   BER_Decoder(enc_algo.parameters).decode(iv, OCTET_STRING).verify_end();

   block_cipher = af.make_block_cipher(cipher_spec[0]);
   hash_function = af.make_hash_function("SHA-160");

   if(key_length == 0)
      key_length = block_cipher->maximum_keylength();

   if(salt.size() < 8)
      throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small");
   }
Exemple #12
0
/*
* Return the hash used in generating the signature
*/
std::string X509_Object::hash_used_for_signature() const
   {
   std::vector<std::string> sig_info =
      split_on(OIDS::lookup(m_sig_algo.oid), '/');

   if(sig_info.size() != 2)
      throw Internal_Error("Invalid name format found for " +
                           m_sig_algo.oid.as_string());

   std::vector<std::string> pad_and_hash =
      parse_algorithm_name(sig_info[1]);

   if(pad_and_hash.size() != 2)
      throw Internal_Error("Invalid name format " + sig_info[1]);

   return pad_and_hash[1];
   }
Exemple #13
0
/*
* Win32_Capi_Entropysource Constructor
*/
Win32_CAPI_EntropySource::Win32_CAPI_EntropySource(const std::string& provs)
   {
   for(std::string prov_name : split_on(provs, ':'))
      {
      DWORD prov_type;

      if(prov_name == "RSA_FULL")
         prov_type = PROV_RSA_FULL;
      else if(prov_name == "INTEL_SEC")
         prov_type = PROV_INTEL_SEC;
      else if(prov_name == "RNG")
         prov_type = PROV_RNG;
      else
         continue;

      m_csp_provs.push_back(std::unique_ptr<CSP_Handle>(new CSP_Handle_Impl(prov_type)));
      }
   }
Exemple #14
0
/*************************************************
* Convert a decimal-dotted string to binary IP   *
*************************************************/
u32bit string_to_ipv4(const std::string& str)
   {
   std::vector<std::string> parts = split_on(str, '.');

   if(parts.size() != 4)
      throw Decoding_Error("Invalid IP string " + str);

   u32bit ip = 0;

   for(size_t j = 0; j != parts.size(); j++)
      {
      u32bit octet = to_u32bit(parts[j]);

      if(octet > 255)
         throw Decoding_Error("Invalid IP string " + str);

      ip = (ip << 8) | (octet & 0xFF);
      }

   return ip;
   }
Exemple #15
0
/*
* Convert a decimal-dotted string to binary IP
*/
u32bit string_to_ipv4(const std::string& str)
   {
   std::vector<std::string> parts = split_on(str, '.');

   if(parts.size() != 4)
      throw Decoding_Error("Invalid IP string " + str);

   u32bit ip = 0;

   for(auto part = parts.begin(); part != parts.end(); ++part)
      {
      u32bit octet = to_u32bit(*part);

      if(octet > 255)
         throw Decoding_Error("Invalid IP string " + str);

      ip = (ip << 8) | (octet & 0xFF);
      }

   return ip;
   }
Exemple #16
0
/*
* Check the signature on an object
*/
bool X509_Object::check_signature(const Public_Key& pub_key) const
   {
   try {
      std::vector<std::string> sig_info =
         split_on(OIDS::lookup(m_sig_algo.oid), '/');

      if(sig_info.size() != 2 || sig_info[0] != pub_key.algo_name())
         return false;

      std::string padding = sig_info[1];
      Signature_Format format =
         (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363;

      PK_Verifier verifier(pub_key, padding, format);

      return verifier.verify_message(tbs_data(), signature());
      }
   catch(std::exception&)
      {
      return false;
      }
   }
Exemple #17
0
static int with_tokens(const char *str, const char *sep, int (*cb)(char **, int n))
{
	char *tokens[64] = { NULL };
	int n = 0, i, ret;

	void push_back_ptr(char *ptr)
	{
		if (n < 64)
			tokens[n++] = ptr;
	}

	split_on(str, sep, push_back_ptr);

	ret = cb(tokens, n);

	for(i = 0; i < n; ++i)
	{
		free(tokens[i]);
	}

	return ret;
}
Exemple #18
0
secure_vector<uint8_t>
pbes2_decrypt(const secure_vector<uint8_t>& key_bits,
              const std::string& passphrase,
              const std::vector<uint8_t>& params)
   {
   AlgorithmIdentifier kdf_algo, enc_algo;

   BER_Decoder(params)
      .start_cons(SEQUENCE)
         .decode(kdf_algo)
         .decode(enc_algo)
      .end_cons();

   const std::string cipher = OIDS::lookup(enc_algo.get_oid());
   const std::vector<std::string> cipher_spec = split_on(cipher, '/');
   if(cipher_spec.size() != 2)
      throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);
   if(!known_pbes_cipher_mode(cipher_spec[1]))
      throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher);

   secure_vector<uint8_t> iv;
   BER_Decoder(enc_algo.get_parameters()).decode(iv, OCTET_STRING).verify_end();

   std::unique_ptr<Cipher_Mode> dec = Cipher_Mode::create(cipher, DECRYPTION);
   if(!dec)
      throw Decoding_Error("PBE-PKCS5 cannot decrypt no cipher " + cipher);

   dec->set_key(derive_key(passphrase, kdf_algo, dec->key_spec().maximum_keylength()));

   dec->start(iv);

   secure_vector<uint8_t> buf = key_bits;
   dec->finish(buf);

   return buf;
   }
Exemple #19
0
Certificate_Status_Code X509_Object::verify_signature(const Public_Key& pub_key) const
   {
   const std::vector<std::string> sig_info =
      split_on(OIDS::lookup(m_sig_algo.get_oid()), '/');

   if(sig_info.size() < 1 || sig_info.size() > 2 || sig_info[0] != pub_key.algo_name())
      return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;

   std::string padding;
   if(sig_info.size() == 2)
      padding = sig_info[1];
   else if(sig_info[0] == "Ed25519")
      padding = "Pure";
   else
      return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;

   const Signature_Format format =
      (pub_key.message_parts() >= 2) ? DER_SEQUENCE : IEEE_1363;

   if(padding == "EMSA4")
      {
      // "MUST contain RSASSA-PSS-params"
      if(signature_algorithm().parameters.empty())
         {
         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
         }

      Pss_params pss_parameter = decode_pss_params(signature_algorithm().parameters);

      // hash_algo must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512
      const std::string hash_algo = OIDS::lookup(pss_parameter.hash_algo.oid);
      if(hash_algo != "SHA-160" &&
         hash_algo != "SHA-224" &&
         hash_algo != "SHA-256" &&
         hash_algo != "SHA-384" &&
         hash_algo != "SHA-512")
         {
         return Certificate_Status_Code::UNTRUSTED_HASH;
         }

      const std::string mgf_algo = OIDS::lookup(pss_parameter.mask_gen_algo.oid);
      if(mgf_algo != "MGF1")
         {
         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
         }

      // For MGF1, it is strongly RECOMMENDED that the underlying hash function be the same as the one identified by hashAlgorithm
      // Must be SHA1, SHA2-224, SHA2-256, SHA2-384 or SHA2-512
      if(pss_parameter.mask_gen_hash.oid != pss_parameter.hash_algo.oid)
         {
         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
         }

      if(pss_parameter.trailer_field != 1)
         {
         return Certificate_Status_Code::SIGNATURE_ALGO_BAD_PARAMS;
         }

      // salt_len is actually not used for verification. Length is inferred from the signature
      padding += "(" + hash_algo + "," + mgf_algo + "," + std::to_string(pss_parameter.salt_len) + ")";
      }

   try
      {
      PK_Verifier verifier(pub_key, padding, format);
      const bool valid = verifier.verify_message(tbs_data(), signature());

      if(valid)
         return Certificate_Status_Code::VERIFIED;
      else
         return Certificate_Status_Code::SIGNATURE_ERROR;
      }
   catch(Algorithm_Not_Found&)
      {
      return Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN;
      }
   catch(...)
      {
      // This shouldn't happen, fallback to generic signature error
      return Certificate_Status_Code::SIGNATURE_ERROR;
      }
   }
Exemple #20
0
bool Ciphersuite::valid() const
   {
   if(!m_cipher_keylen) // uninitialized object
      return false;

   if(!have_hash(prf_algo()))
      return false;

   if(mac_algo() == "AEAD")
      {
      if(cipher_algo() == "ChaCha20Poly1305")
         {
#if !defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305)
         return false;
#endif
         }
      else
         {
         auto cipher_and_mode = split_on(cipher_algo(), '/');
         BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo");
         if(!have_cipher(cipher_and_mode[0]))
            return false;

         const auto mode = cipher_and_mode[1];

#if !defined(BOTAN_HAS_AEAD_CCM)
         if(mode == "CCM" || mode == "CCM-8")
            return false;
#endif

#if !defined(BOTAN_HAS_AEAD_GCM)
         if(mode == "GCM")
            return false;
#endif

#if !defined(BOTAN_HAS_AEAD_OCB)
         if(mode == "OCB(12)" || mode == "OCB")
            return false;
#endif
         }
      }
   else
      {
      // Old non-AEAD schemes
      if(!have_cipher(cipher_algo()))
         return false;
      if(!have_hash(mac_algo())) // HMAC
         return false;
      }

   if(kex_algo() == "SRP_SHA")
      {
#if !defined(BOTAN_HAS_SRP6)
      return false;
#endif
      }
   else if(kex_algo() == "ECDH" || kex_algo() == "ECDHE_PSK")
      {
#if !defined(BOTAN_HAS_ECDH)
      return false;
#endif
      }
   else if(kex_algo() == "DH" || kex_algo() == "DHE_PSK")
      {
#if !defined(BOTAN_HAS_DIFFIE_HELLMAN)
      return false;
#endif
      }

   if(sig_algo() == "DSA")
      {
#if !defined(BOTAN_HAS_DSA)
      return false;
#endif
      }
   else if(sig_algo() == "ECDSA")
      {
#if !defined(BOTAN_HAS_ECDSA)
      return false;
#endif
      }
   else if(sig_algo() == "RSA")
      {
#if !defined(BOTAN_HAS_RSA)
      return false;
#endif
      }

   return true;
   }
Exemple #21
0
Cipher_Mode* get_cipher_mode(const std::string& algo_spec, Cipher_Dir direction)
   {
   const std::string provider = "";

   const char* dir_string = (direction == ENCRYPTION) ? "_Encryption" : "_Decryption";

   Cipher_Mode::Spec spec(algo_spec, dir_string);

   std::unique_ptr<Cipher_Mode> cipher_mode(
      Algo_Registry<Cipher_Mode>::global_registry().make(
         Cipher_Mode::Spec(algo_spec, dir_string),
         provider)
      );

   if(cipher_mode)
      {
      return cipher_mode.release();
      }

   const std::vector<std::string> algo_parts = split_on(algo_spec, '/');
   if(algo_parts.size() < 2)
      return nullptr;

   const std::string cipher_name = algo_parts[0];
   const std::vector<std::string> mode_info = parse_algorithm_name(algo_parts[1]);

   if(mode_info.empty())
      return nullptr;

   std::ostringstream alg_args;

   alg_args << '(' << cipher_name;
   for(size_t i = 1; i < mode_info.size(); ++i)
      alg_args << ',' << mode_info[i];
   for(size_t i = 2; i < algo_parts.size(); ++i)
      alg_args << ',' << algo_parts[i];
   alg_args << ')';

   const std::string mode_name = mode_info[0] + alg_args.str();
   const std::string mode_name_directional = mode_info[0] + dir_string + alg_args.str();

   cipher_mode.reset(
      Algo_Registry<Cipher_Mode>::global_registry().make(
         Cipher_Mode::Spec(mode_name_directional),
         provider)
      );

   if(cipher_mode)
      {
      return cipher_mode.release();
      }

   cipher_mode.reset(
      Algo_Registry<Cipher_Mode>::global_registry().make(
         Cipher_Mode::Spec(mode_name),
         provider)
      );

   if(cipher_mode)
      {
      return cipher_mode.release();
      }

   if(auto sc = StreamCipher::create(mode_name, provider))
      {
      return new Stream_Cipher_Mode(sc.release());
      }

   return nullptr;
   }
Exemple #22
0
std::unique_ptr<Public_Key>
load_public_key(const AlgorithmIdentifier& alg_id,
                const std::vector<uint8_t>& key_bits)
   {
   const std::vector<std::string> alg_info = split_on(OIDS::lookup(alg_id.get_oid()), '/');

   if(alg_info.empty())
      throw Decoding_Error("Unknown algorithm OID: " + alg_id.get_oid().to_string());

   const std::string alg_name = alg_info[0];

#if defined(BOTAN_HAS_RSA)
   if(alg_name == "RSA")
      return std::unique_ptr<Public_Key>(new RSA_PublicKey(alg_id, key_bits));
#endif

#if defined(BOTAN_HAS_CURVE_25519)
   if(alg_name == "Curve25519")
      return std::unique_ptr<Public_Key>(new Curve25519_PublicKey(alg_id, key_bits));
#endif

#if defined(BOTAN_HAS_MCELIECE)
   if(alg_name == "McEliece")
      return std::unique_ptr<Public_Key>(new McEliece_PublicKey(key_bits));
#endif

#if defined(BOTAN_HAS_ECDSA)
   if(alg_name == "ECDSA")
      return std::unique_ptr<Public_Key>(new ECDSA_PublicKey(alg_id, key_bits));
#endif

#if defined(BOTAN_HAS_ECDH)
   if(alg_name == "ECDH")
      return std::unique_ptr<Public_Key>(new ECDH_PublicKey(alg_id, key_bits));
#endif

#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
   if(alg_name == "DH")
      return std::unique_ptr<Public_Key>(new DH_PublicKey(alg_id, key_bits));
#endif

#if defined(BOTAN_HAS_DSA)
   if(alg_name == "DSA")
      return std::unique_ptr<Public_Key>(new DSA_PublicKey(alg_id, key_bits));
#endif

#if defined(BOTAN_HAS_ELGAMAL)
   if(alg_name == "ElGamal")
      return std::unique_ptr<Public_Key>(new ElGamal_PublicKey(alg_id, key_bits));
#endif

#if defined(BOTAN_HAS_ECGDSA)
   if(alg_name == "ECGDSA")
      return std::unique_ptr<Public_Key>(new ECGDSA_PublicKey(alg_id, key_bits));
#endif

#if defined(BOTAN_HAS_ECKCDSA)
   if(alg_name == "ECKCDSA")
      return std::unique_ptr<Public_Key>(new ECKCDSA_PublicKey(alg_id, key_bits));
#endif

#if defined(BOTAN_HAS_ED25519)
   if(alg_name == "Ed25519")
      return std::unique_ptr<Public_Key>(new Ed25519_PublicKey(alg_id, key_bits));
#endif

#if defined(BOTAN_HAS_GOST_34_10_2001)
   if(alg_name == "GOST-34.10")
      return std::unique_ptr<Public_Key>(new GOST_3410_PublicKey(alg_id, key_bits));
#endif

#if defined(BOTAN_HAS_SM2)
   if(alg_name == "SM2" || alg_name == "SM2_Sig" || alg_name == "SM2_Enc")
      return std::unique_ptr<Public_Key>(new SM2_PublicKey(alg_id, key_bits));
#endif

#if defined(BOTAN_HAS_XMSS)
   if(alg_name == "XMSS")
      return std::unique_ptr<Public_Key>(new XMSS_PublicKey(key_bits));
#endif

   throw Decoding_Error("Unhandled PK algorithm " + alg_name);
   }
Exemple #23
0
Cipher_Mode* get_cipher_mode(const std::string& algo, Cipher_Dir direction)
   {
   if(auto sc = StreamCipher::create(algo))
      {
      return new Stream_Cipher_Mode(sc.release());
      }

#if defined(BOTAN_HAS_AEAD_MODES)
   if(auto aead = get_aead(algo, direction))
      {
      return aead;
      }
#endif

   if(algo.find('/') != std::string::npos)
      {
      const std::vector<std::string> algo_parts = split_on(algo, '/');
      const std::string cipher_name = algo_parts[0];
      const std::vector<std::string> mode_info = parse_algorithm_name(algo_parts[1]);

      if(mode_info.empty())
         return nullptr;

      std::ostringstream alg_args;

      alg_args << '(' << cipher_name;
      for(size_t i = 1; i < mode_info.size(); ++i)
         alg_args << ',' << mode_info[i];
      for(size_t i = 2; i < algo_parts.size(); ++i)
         alg_args << ',' << algo_parts[i];
      alg_args << ')';

      const std::string mode_name = mode_info[0] + alg_args.str();
      return get_cipher_mode(mode_name, direction);
      }

#if defined(BOTAN_HAS_BLOCK_CIPHER)

   SCAN_Name spec(algo);

   if(spec.arg_count() == 0)
      {
      return nullptr;
      }

   std::unique_ptr<BlockCipher> bc(BlockCipher::create(spec.arg(0)));

   if(!bc)
      {
      return nullptr;
      }

#if defined(BOTAN_HAS_MODE_CBC)
   if(spec.algo_name() == "CBC")
      {
      const std::string padding = spec.arg(1, "PKCS7");

      if(padding == "CTS")
         {
         if(direction == ENCRYPTION)
            return new CTS_Encryption(bc.release());
         else
            return new CTS_Decryption(bc.release());
         }
      else
         {
         std::unique_ptr<BlockCipherModePaddingMethod> pad(get_bc_pad(padding));

         if(pad)
            {
            if(direction == ENCRYPTION)
               return new CBC_Encryption(bc.release(), pad.release());
            else
               return new CBC_Decryption(bc.release(), pad.release());
            }
         }
      }
#endif

#if defined(BOTAN_HAS_MODE_XTS)
   if(spec.algo_name() == "XTS")
      {
      if(direction == ENCRYPTION)
         return new XTS_Encryption(bc.release());
      else
         return new XTS_Decryption(bc.release());
      }
#endif

#if defined(BOTAN_HAS_MODE_CFB)
   if(spec.algo_name() == "CFB")
      {
      const size_t feedback_bits = spec.arg_as_integer(1, 8*bc->block_size());
      if(direction == ENCRYPTION)
         return new CFB_Encryption(bc.release(), feedback_bits);
      else
         return new CFB_Decryption(bc.release(), feedback_bits);
      }
#endif

#endif

   return nullptr;
   }
Exemple #24
0
secure_vector<uint8_t>
pbes2_decrypt(const secure_vector<uint8_t>& key_bits,
              const std::string& passphrase,
              const std::vector<uint8_t>& params)
   {
   AlgorithmIdentifier kdf_algo, enc_algo;

   BER_Decoder(params)
      .start_cons(SEQUENCE)
         .decode(kdf_algo)
         .decode(enc_algo)
      .end_cons();

   AlgorithmIdentifier prf_algo;

   if(kdf_algo.oid != OIDS::lookup("PKCS5.PBKDF2"))
      throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " +
                           kdf_algo.oid.as_string());

   secure_vector<uint8_t> salt;
   size_t iterations = 0, key_length = 0;

   BER_Decoder(kdf_algo.parameters)
      .start_cons(SEQUENCE)
         .decode(salt, OCTET_STRING)
         .decode(iterations)
         .decode_optional(key_length, INTEGER, UNIVERSAL)
         .decode_optional(prf_algo, SEQUENCE, CONSTRUCTED,
                          AlgorithmIdentifier("HMAC(SHA-160)",
                                              AlgorithmIdentifier::USE_NULL_PARAM))
      .end_cons();

   const std::string cipher = OIDS::lookup(enc_algo.oid);
   const std::vector<std::string> cipher_spec = split_on(cipher, '/');
   if(cipher_spec.size() != 2)
      throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);
   if(cipher_spec[1] != "CBC" && cipher_spec[1] != "GCM")
      throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher);

   if(salt.size() < 8)
      throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small");

   secure_vector<uint8_t> iv;
   BER_Decoder(enc_algo.parameters).decode(iv, OCTET_STRING).verify_end();

   const std::string prf = OIDS::lookup(prf_algo.oid);

   std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(" + prf + ")"));

   std::unique_ptr<Cipher_Mode> dec(get_cipher_mode(cipher, DECRYPTION));
   if(!dec)
      throw Decoding_Error("PBE-PKCS5 cannot decrypt no cipher " + cipher);

   if(key_length == 0)
      key_length = dec->key_spec().maximum_keylength();

   dec->set_key(pbkdf->pbkdf_iterations(key_length, passphrase, salt.data(), salt.size(), iterations));

   dec->start(iv);

   secure_vector<uint8_t> buf = key_bits;
   dec->finish(buf);

   return buf;
   }