aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/pubkey
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-11-03 10:30:13 -0400
committerJack Lloyd <[email protected]>2016-11-03 10:30:13 -0400
commit341fd32b46363cad4c2caee3fca166695100ba07 (patch)
tree89a98aa28a431f2625268cf61e7adf903fd24a98 /src/lib/pubkey
parent1e72720661383466807ac496b941af41d756a2ce (diff)
Move cert/x509 to top level and pem and pbes2 to pubkey.
The `cert` dir was just an artifact of having previously supported CVC (smartcard cert format), removed a long time ago. The pem and pbes2 code is directly related to the pubkey code, in fact the only caller of pbes2 (likely anywhere, not just in the library) is in pkcs8.cpp
Diffstat (limited to 'src/lib/pubkey')
-rw-r--r--src/lib/pubkey/pbes2/info.txt9
-rw-r--r--src/lib/pubkey/pbes2/pbes2.cpp176
-rw-r--r--src/lib/pubkey/pbes2/pbes2.h47
-rw-r--r--src/lib/pubkey/pem/info.txt5
-rw-r--r--src/lib/pubkey/pem/pem.cpp167
-rw-r--r--src/lib/pubkey/pem/pem.h100
6 files changed, 504 insertions, 0 deletions
diff --git a/src/lib/pubkey/pbes2/info.txt b/src/lib/pubkey/pbes2/info.txt
new file mode 100644
index 000000000..ed88ac3eb
--- /dev/null
+++ b/src/lib/pubkey/pbes2/info.txt
@@ -0,0 +1,9 @@
+define PKCS5_PBES2 20141119
+
+<requires>
+asn1
+cbc
+hmac
+oid_lookup
+pbkdf2
+</requires>
diff --git a/src/lib/pubkey/pbes2/pbes2.cpp b/src/lib/pubkey/pbes2/pbes2.cpp
new file mode 100644
index 000000000..c66b293e8
--- /dev/null
+++ b/src/lib/pubkey/pbes2/pbes2.cpp
@@ -0,0 +1,176 @@
+/*
+* PKCS #5 PBES2
+* (C) 1999-2008,2014 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/pbes2.h>
+#include <botan/cipher_mode.h>
+#include <botan/pbkdf.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/parsing.h>
+#include <botan/alg_id.h>
+#include <botan/oids.h>
+#include <botan/rng.h>
+#include <algorithm>
+
+namespace Botan {
+
+namespace {
+
+/*
+* Encode PKCS#5 PBES2 parameters
+*/
+std::vector<byte> encode_pbes2_params(const std::string& cipher,
+ const std::string& prf,
+ const secure_vector<byte>& salt,
+ const secure_vector<byte>& iv,
+ size_t iterations,
+ size_t key_length)
+ {
+ return DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode(
+ AlgorithmIdentifier("PKCS5.PBKDF2",
+ DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode(salt, OCTET_STRING)
+ .encode(iterations)
+ .encode(key_length)
+ .encode_if(
+ prf != "HMAC(SHA-160)",
+ AlgorithmIdentifier(prf, AlgorithmIdentifier::USE_NULL_PARAM))
+ .end_cons()
+ .get_contents_unlocked()
+ )
+ )
+ .encode(
+ AlgorithmIdentifier(cipher,
+ DER_Encoder().encode(iv, OCTET_STRING).get_contents_unlocked()
+ )
+ )
+ .end_cons()
+ .get_contents_unlocked();
+ }
+
+}
+
+/*
+* PKCS#5 v2.0 PBE Constructor
+*/
+std::pair<AlgorithmIdentifier, std::vector<byte>>
+pbes2_encrypt(const secure_vector<byte>& key_bits,
+ const std::string& passphrase,
+ std::chrono::milliseconds msec,
+ const std::string& cipher,
+ const std::string& digest,
+ RandomNumberGenerator& rng)
+ {
+ const std::string prf = "HMAC(" + digest + ")";
+
+ 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);
+
+ const secure_vector<byte> salt = rng.random_vec(12);
+
+ if(cipher_spec[1] != "CBC" && cipher_spec[1] != "GCM")
+ throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher);
+
+ std::unique_ptr<Cipher_Mode> enc(get_cipher_mode(cipher, ENCRYPTION));
+
+ if(!enc)
+ throw Decoding_Error("PBE-PKCS5 cannot encrypt no cipher " + cipher);
+
+ std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(" + prf + ")"));
+
+ const size_t key_length = enc->key_spec().maximum_keylength();
+ size_t iterations = 0;
+
+ secure_vector<byte> iv = rng.random_vec(enc->default_nonce_length());
+
+ enc->set_key(pbkdf->derive_key(key_length, passphrase, salt.data(), salt.size(),
+ msec, iterations).bits_of());
+
+ enc->start(iv);
+ secure_vector<byte> buf = key_bits;
+ enc->finish(buf);
+
+ AlgorithmIdentifier id(
+ OIDS::lookup("PBE-PKCS5v20"),
+ encode_pbes2_params(cipher, prf, salt, iv, iterations, key_length));
+
+ return std::make_pair(id, unlock(buf));
+ }
+
+secure_vector<byte>
+pbes2_decrypt(const secure_vector<byte>& key_bits,
+ const std::string& passphrase,
+ const std::vector<byte>& params)
+ {
+ AlgorithmIdentifier kdf_algo, enc_algo;
+
+ BER_Decoder(params)
+ .start_cons(SEQUENCE)
+ .decode(kdf_algo)
+ .decode(enc_algo)
+ .verify_end()
+ .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<byte> 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))
+ .verify_end()
+ .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<byte> 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<byte> buf = key_bits;
+ dec->finish(buf);
+
+ return buf;
+ }
+
+}
diff --git a/src/lib/pubkey/pbes2/pbes2.h b/src/lib/pubkey/pbes2/pbes2.h
new file mode 100644
index 000000000..7c8c4095d
--- /dev/null
+++ b/src/lib/pubkey/pbes2/pbes2.h
@@ -0,0 +1,47 @@
+/*
+* PKCS #5 v2.0 PBE
+* (C) 1999-2007,2014 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_PBE_PKCS_v20_H__
+#define BOTAN_PBE_PKCS_v20_H__
+
+#include <botan/rng.h>
+#include <botan/alg_id.h>
+#include <chrono>
+
+namespace Botan {
+
+/**
+* Encrypt with PBES2 from PKCS #5 v2.0
+* @param key_bits the input
+* @param passphrase the passphrase to use for encryption
+* @param msec how many milliseconds to run PBKDF2
+* @param cipher specifies the block cipher to use to encrypt
+* @param digest specifies the PRF to use with PBKDF2 (eg "HMAC(SHA-1)")
+* @param rng a random number generator
+*/
+std::pair<AlgorithmIdentifier, std::vector<byte>>
+BOTAN_DLL pbes2_encrypt(const secure_vector<byte>& key_bits,
+ const std::string& passphrase,
+ std::chrono::milliseconds msec,
+ const std::string& cipher,
+ const std::string& digest,
+ RandomNumberGenerator& rng);
+
+/**
+* Decrypt a PKCS #5 v2.0 encrypted stream
+* @param key_bits the input
+* @param passphrase the passphrase to use for decryption
+* @param params the PBES2 parameters
+*/
+secure_vector<byte>
+BOTAN_DLL pbes2_decrypt(const secure_vector<byte>& key_bits,
+ const std::string& passphrase,
+ const std::vector<byte>& params);
+
+}
+
+#endif
diff --git a/src/lib/pubkey/pem/info.txt b/src/lib/pubkey/pem/info.txt
new file mode 100644
index 000000000..9340a7cef
--- /dev/null
+++ b/src/lib/pubkey/pem/info.txt
@@ -0,0 +1,5 @@
+define PEM_CODEC 20131128
+
+<requires>
+base64
+</requires>
diff --git a/src/lib/pubkey/pem/pem.cpp b/src/lib/pubkey/pem/pem.cpp
new file mode 100644
index 000000000..83b48c07b
--- /dev/null
+++ b/src/lib/pubkey/pem/pem.cpp
@@ -0,0 +1,167 @@
+/*
+* PEM Encoding/Decoding
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/pem.h>
+#include <botan/base64.h>
+#include <botan/parsing.h>
+#include <botan/exceptn.h>
+
+namespace Botan {
+
+namespace PEM_Code {
+
+namespace {
+
+std::string linewrap(size_t width, const std::string& in)
+ {
+ std::string out;
+ for(size_t i = 0; i != in.size(); ++i)
+ {
+ if(i > 0 && i % width == 0)
+ {
+ out.push_back('\n');
+ }
+ out.push_back(in[i]);
+ }
+ if(out.size() > 0 && out[out.size()-1] != '\n')
+ {
+ out.push_back('\n');
+ }
+
+ return out;
+ }
+
+}
+
+/*
+* PEM encode BER/DER-encoded objects
+*/
+std::string encode(const byte der[], size_t length, const std::string& label, size_t width)
+ {
+ const std::string PEM_HEADER = "-----BEGIN " + label + "-----\n";
+ const std::string PEM_TRAILER = "-----END " + label + "-----\n";
+
+ return (PEM_HEADER + linewrap(width, base64_encode(der, length)) + PEM_TRAILER);
+ }
+
+/*
+* Decode PEM down to raw BER/DER
+*/
+secure_vector<byte> decode_check_label(DataSource& source,
+ const std::string& label_want)
+ {
+ std::string label_got;
+ secure_vector<byte> ber = decode(source, label_got);
+ if(label_got != label_want)
+ throw Decoding_Error("PEM: Label mismatch, wanted " + label_want +
+ ", got " + label_got);
+ return ber;
+ }
+
+/*
+* Decode PEM down to raw BER/DER
+*/
+secure_vector<byte> decode(DataSource& source, std::string& label)
+ {
+ const size_t RANDOM_CHAR_LIMIT = 8;
+
+ const std::string PEM_HEADER1 = "-----BEGIN ";
+ const std::string PEM_HEADER2 = "-----";
+ size_t position = 0;
+
+ while(position != PEM_HEADER1.length())
+ {
+ byte b;
+ if(!source.read_byte(b))
+ throw Decoding_Error("PEM: No PEM header found");
+ if(b == PEM_HEADER1[position])
+ ++position;
+ else if(position >= RANDOM_CHAR_LIMIT)
+ throw Decoding_Error("PEM: Malformed PEM header");
+ else
+ position = 0;
+ }
+ position = 0;
+ while(position != PEM_HEADER2.length())
+ {
+ byte b;
+ if(!source.read_byte(b))
+ throw Decoding_Error("PEM: No PEM header found");
+ if(b == PEM_HEADER2[position])
+ ++position;
+ else if(position)
+ throw Decoding_Error("PEM: Malformed PEM header");
+
+ if(position == 0)
+ label += static_cast<char>(b);
+ }
+
+ std::vector<char> b64;
+
+ const std::string PEM_TRAILER = "-----END " + label + "-----";
+ position = 0;
+ while(position != PEM_TRAILER.length())
+ {
+ byte b;
+ if(!source.read_byte(b))
+ throw Decoding_Error("PEM: No PEM trailer found");
+ if(b == PEM_TRAILER[position])
+ ++position;
+ else if(position)
+ throw Decoding_Error("PEM: Malformed PEM trailer");
+
+ if(position == 0)
+ b64.push_back(b);
+ }
+
+ return base64_decode(b64.data(), b64.size());
+ }
+
+secure_vector<byte> decode_check_label(const std::string& pem,
+ const std::string& label_want)
+ {
+ DataSource_Memory src(pem);
+ return decode_check_label(src, label_want);
+ }
+
+secure_vector<byte> decode(const std::string& pem, std::string& label)
+ {
+ DataSource_Memory src(pem);
+ return decode(src, label);
+ }
+
+/*
+* Search for a PEM signature
+*/
+bool matches(DataSource& source, const std::string& extra,
+ size_t search_range)
+ {
+ const std::string PEM_HEADER = "-----BEGIN " + extra;
+
+ secure_vector<byte> search_buf(search_range);
+ size_t got = source.peek(search_buf.data(), search_buf.size(), 0);
+
+ if(got < PEM_HEADER.length())
+ return false;
+
+ size_t index = 0;
+
+ for(size_t j = 0; j != got; ++j)
+ {
+ if(search_buf[j] == PEM_HEADER[index])
+ ++index;
+ else
+ index = 0;
+ if(index == PEM_HEADER.size())
+ return true;
+ }
+ return false;
+ }
+
+}
+
+}
diff --git a/src/lib/pubkey/pem/pem.h b/src/lib/pubkey/pem/pem.h
new file mode 100644
index 000000000..acbd40a77
--- /dev/null
+++ b/src/lib/pubkey/pem/pem.h
@@ -0,0 +1,100 @@
+/*
+* PEM Encoding/Decoding
+* (C) 1999-2007 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_PEM_H__
+#define BOTAN_PEM_H__
+
+#include <botan/data_src.h>
+
+namespace Botan {
+
+namespace PEM_Code {
+
+/**
+* Encode some binary data in PEM format
+* @param data binary data to encode
+* @param data_len length of binary data in bytes
+* @param label PEM label put after BEGIN and END
+* @param line_width after this many characters, a new line is inserted
+*/
+BOTAN_DLL std::string encode(const byte data[],
+ size_t data_len,
+ const std::string& label,
+ size_t line_width = 64);
+
+/**
+* Encode some binary data in PEM format
+* @param data binary data to encode
+* @param label PEM label
+* @param line_width after this many characters, a new line is inserted
+*/
+inline std::string encode(const std::vector<byte>& data,
+ const std::string& label,
+ size_t line_width = 64)
+ {
+ return encode(data.data(), data.size(), label, line_width);
+ }
+
+/**
+* Encode some binary data in PEM format
+* @param data binary data to encode
+* @param label PEM label put after BEGIN and END
+* @param line_width after this many characters, a new line is inserted
+*/
+inline std::string encode(const secure_vector<byte>& data,
+ const std::string& label,
+ size_t line_width = 64)
+ {
+ return encode(data.data(), data.size(), label, line_width);
+ }
+
+/**
+* Decode PEM data
+* @param pem a datasource containing PEM encoded data
+* @param label is set to the PEM label found for later inspection
+*/
+BOTAN_DLL secure_vector<byte> decode(DataSource& pem,
+ std::string& label);
+
+/**
+* Decode PEM data
+* @param pem a string containing PEM encoded data
+* @param label is set to the PEM label found for later inspection
+*/
+BOTAN_DLL secure_vector<byte> decode(const std::string& pem,
+ std::string& label);
+
+/**
+* Decode PEM data
+* @param pem a datasource containing PEM encoded data
+* @param label is what we expect the label to be
+*/
+BOTAN_DLL secure_vector<byte> decode_check_label(
+ DataSource& pem,
+ const std::string& label);
+
+/**
+* Decode PEM data
+* @param pem a string containing PEM encoded data
+* @param label is what we expect the label to be
+*/
+BOTAN_DLL secure_vector<byte> decode_check_label(
+ const std::string& pem,
+ const std::string& label);
+
+/**
+* Heuristic test for PEM data.
+*/
+BOTAN_DLL bool matches(DataSource& source,
+ const std::string& extra = "",
+ size_t search_range = 4096);
+
+}
+
+}
+
+#endif