Skip to content

Commit 75bdade

Browse files
authored
Add cryptograhpic key decoders (#1936)
1 parent b1da390 commit 75bdade

28 files changed

+1561
-148
lines changed

Packet++/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ add_library(
66
src/BgpLayer.cpp
77
src/CiscoHdlcLayer.cpp
88
src/CotpLayer.cpp
9+
src/CryptoKeyDecoder.cpp
910
src/DhcpLayer.cpp
1011
src/DhcpV6Layer.cpp
1112
src/DnsLayer.cpp
@@ -82,6 +83,8 @@ set(
8283
header/BgpLayer.h
8384
header/CiscoHdlcLayer.h
8485
header/CotpLayer.h
86+
header/CryptoDataReader.h
87+
header/CryptoKeyDecoder.h
8588
header/DhcpLayer.h
8689
header/DhcpV6Layer.h
8790
header/DnsLayerEnums.h

Packet++/header/Asn1Codec.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -434,11 +434,13 @@ namespace pcpp
434434
return getIntValue<uint32_t>();
435435
}
436436

437+
/// Get the integer value of this record as a hex string
438+
/// @param removeLeadingZeros If true, leading zeros will be removed
437439
/// @return A hex string representation of the record value
438-
std::string getValueAsString() const
440+
std::string getValueAsString(bool removeLeadingZeros = false) const
439441
{
440442
decodeValueIfNeeded();
441-
return m_Value.toString();
443+
return m_Value.toString(removeLeadingZeros);
442444
}
443445

444446
protected:
@@ -491,7 +493,7 @@ namespace pcpp
491493
return sizeof(T) >= (m_Value.size() + 1) / 2;
492494
}
493495

494-
std::string toString() const;
496+
std::string toString(bool removeLeadingZeros = false) const;
495497
std::vector<uint8_t> toBytes() const;
496498

497499
private:

Packet++/header/CryptoDataReader.h

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
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+
{
34+
return std::unique_ptr<CryptoDecoder>(new CryptoDecoder(derData, derDataLen, ownDerData));
35+
}
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

0 commit comments

Comments
 (0)