/src/PcapPlusPlus/Packet++/header/CryptoDataReader.h
Line | Count | Source |
1 | | #pragma once |
2 | | |
3 | | /// @file |
4 | | |
5 | | #include "GeneralUtils.h" |
6 | | #include "PemCodec.h" |
7 | | #include <string> |
8 | | #include <memory> |
9 | | #include <fstream> |
10 | | |
11 | | /// @namespace pcpp |
12 | | /// @brief The main namespace for the PcapPlusPlus lib |
13 | | namespace pcpp |
14 | | { |
15 | | namespace internal |
16 | | { |
17 | | /// @class CryptoDataReader |
18 | | /// @brief A template helper class for reading and decoding cryptographic data in different formats (DER/PEM) |
19 | | /// @tparam CryptoDecoder The decoder type that will be used to process the cryptographic data. |
20 | | /// Must be a class that can be constructed with a byte array and a length, or a unique pointer to a byte array |
21 | | /// and a length |
22 | | template <typename CryptoDecoder> class CryptoDataReader |
23 | | { |
24 | | public: |
25 | | /// Creates a decoder from DER-encoded data |
26 | | /// @param[in] derData Pointer to the DER-encoded data |
27 | | /// @param[in] derDataLen Length of the DER-encoded data |
28 | | /// @param[in] ownDerData If true, the decoder will take ownership of the data and free it when the |
29 | | /// decoder class is destructed |
30 | | /// @return A unique pointer to the created decoder |
31 | | /// @throws An exception if the data is not a valid ASN.1 record |
32 | | static std::unique_ptr<CryptoDecoder> fromDER(uint8_t* derData, size_t derDataLen, bool ownDerData = false) |
33 | 0 | { |
34 | 0 | return std::unique_ptr<CryptoDecoder>(new CryptoDecoder(derData, derDataLen, ownDerData)); |
35 | 0 | } |
36 | | |
37 | | /// Creates a decoder from a hex string containing DER-encoded data |
38 | | /// @param[in] derData Hex string containing DER-encoded data |
39 | | /// @return A unique pointer to the created decoder |
40 | | /// @throws An exception if the data is not a valid ASN.1 record |
41 | | static std::unique_ptr<CryptoDecoder> fromDER(const std::string& derData) |
42 | | { |
43 | | size_t derDataBufferLen = derData.length() / 2; |
44 | | auto derDataBuffer = std::make_unique<uint8_t[]>(derDataBufferLen); |
45 | | hexStringToByteArray(derData, derDataBuffer.get(), derDataBufferLen); |
46 | | return std::unique_ptr<CryptoDecoder>(new CryptoDecoder(std::move(derDataBuffer), derDataBufferLen)); |
47 | | } |
48 | | |
49 | | /// Creates a decoder from a file containing DER-encoded data |
50 | | /// @param[in] derFileName Path to the file containing DER-encoded data |
51 | | /// @return A unique pointer to the created decoder |
52 | | /// @throws An exception if the file doesn't exist, cannot be read or contains invalid data |
53 | | static std::unique_ptr<CryptoDecoder> fromDERFile(const std::string& derFileName) |
54 | | { |
55 | | std::ifstream derFile(derFileName, std::ios::binary); |
56 | | if (!derFile.good()) |
57 | | { |
58 | | throw std::runtime_error("DER file doesn't exist or cannot be opened"); |
59 | | } |
60 | | |
61 | | derFile.seekg(0, std::ios::end); |
62 | | std::streamsize derDataLen = derFile.tellg(); |
63 | | if (derDataLen < 0) |
64 | | { |
65 | | throw std::runtime_error("Failed to determine DER file size"); |
66 | | } |
67 | | derFile.seekg(0, std::ios::beg); |
68 | | |
69 | | auto derData = std::make_unique<uint8_t[]>(derDataLen); |
70 | | |
71 | | if (!derFile.read(reinterpret_cast<char*>(derData.get()), derDataLen)) |
72 | | { |
73 | | throw std::runtime_error("Failed to read DER file"); |
74 | | } |
75 | | return std::unique_ptr<CryptoDecoder>(new CryptoDecoder(std::move(derData), derDataLen)); |
76 | | } |
77 | | |
78 | | /// Creates a decoder from PEM-encoded data |
79 | | /// @param[in] pemData PEM-encoded data |
80 | | /// @return A unique pointer to the created decoder |
81 | | /// @throws std::invalid_argument exception if the data is not a valid PEM-encoded data |
82 | | static std::unique_ptr<CryptoDecoder> fromPEM(const std::string& pemData) |
83 | | { |
84 | | auto derData = PemCodec::decode(pemData, CryptoDecoder::pemLabel); |
85 | | auto derDataBuffer = std::make_unique<uint8_t[]>(derData.size()); |
86 | | std::copy(derData.begin(), derData.end(), derDataBuffer.get()); |
87 | | return std::unique_ptr<CryptoDecoder>(new CryptoDecoder(std::move(derDataBuffer), derData.size())); |
88 | | } |
89 | | |
90 | | /// Creates a decoder from a file containing PEM-encoded data |
91 | | /// @param[in] pemFileName Path to the file containing PEM-encoded data |
92 | | /// @return A unique pointer to the created decoder |
93 | | /// @throws std::runtime_error exception if the file doesn't exist or cannot be read |
94 | | /// @throws std::invalid_argument exception if the data is not a valid PEM-encoded data |
95 | | static std::unique_ptr<CryptoDecoder> fromPEMFile(const std::string& pemFileName) |
96 | | { |
97 | | std::ifstream pemFile(pemFileName, std::ios::in | std::ios::binary); |
98 | | if (!pemFile.good()) |
99 | | { |
100 | | throw std::runtime_error("PEM file doesn't exist or cannot be opened"); |
101 | | } |
102 | | |
103 | | pemFile.seekg(0, std::ios::end); |
104 | | std::streamsize pemContentLen = pemFile.tellg(); |
105 | | if (pemContentLen < 0) |
106 | | { |
107 | | throw std::runtime_error("Failed to determine PEM file size"); |
108 | | } |
109 | | pemFile.seekg(0, std::ios::beg); |
110 | | |
111 | | std::string pemContent; |
112 | | pemContent.resize(static_cast<std::size_t>(pemContentLen)); |
113 | | if (!pemFile.read(&pemContent[0], pemContentLen)) |
114 | | { |
115 | | throw std::runtime_error("Failed to read PEM file"); |
116 | | } |
117 | | |
118 | | return fromPEM(pemContent); |
119 | | } |
120 | | |
121 | | protected: |
122 | | ~CryptoDataReader() = default; |
123 | | }; |
124 | | } // namespace internal |
125 | | } // namespace pcpp |