diff --git a/Crypto/ASN1/ASN1.cpp b/Crypto/ASN1/ASN1.cpp new file mode 100644 index 0000000..f025de4 --- /dev/null +++ b/Crypto/ASN1/ASN1.cpp @@ -0,0 +1,113 @@ +#include +#include +#include +#include "ASN1.h" + + +ASN1Object::ASN1Object(const std::vector& asn1_encoded_data) + : m_type(ASN1_Invalid) +{ + m_tmp = 1; + + if (asn1_encoded_data.size() < 2) + { + printf("not enough data to form an object\n"); + return; + } + uint8_t sizeByte = asn1_encoded_data[1]; + size_t size = 0; + if (sizeByte & 0x80) + { + sizeByte &= 0x7F; + if (asn1_encoded_data.size() < (sizeByte + 2)) + { + printf("not enough data to decode the size bytes %i (data size: %li)\n", sizeByte, asn1_encoded_data.size()); + return; + } + for (int i = 0; i < sizeByte; i++) + { + size <<= 8; + size |= asn1_encoded_data[2 + i]; + } + if (asn1_encoded_data.size() < (sizeByte + 2 + size)) + { + printf("not enough data to decode an object of size %li (data size: %li)\n", size, asn1_encoded_data.size()); + return; + } + } + else + { + size = sizeByte; + if (asn1_encoded_data.size() < (size + 2)) + { + printf("not enough data to decode a small object of size %li (data size: %li)\n", size, asn1_encoded_data.size()); + return; + } + sizeByte = 0; + } + + m_tmp = 2 + sizeByte; + + // Copy the data + m_data.resize(size); + memcpy(&m_data[0], &asn1_encoded_data[sizeByte + 2], size); + + // Set the type + m_type = (ASN1Type)asn1_encoded_data[0]; + + if (m_type == ASN1_Sequence || m_type == ASN1_Set) + { + size_t sizeRemaining = size; + size_t offset = 0; + while (sizeRemaining) + { + std::vector data; + data.resize(sizeRemaining); + memcpy(&data[0], &m_data[offset], sizeRemaining); + + ASN1Object child(data); + if (child.m_type == ASN1_Invalid) + { + printf("error with decoding the children of sequence or set\n"); + return; + } + m_children.push_back(child); + + sizeRemaining -= child.m_data.size() + child.m_tmp; + offset += child.m_data.size() + child.m_tmp; + } + } +} + + +void ASN1Object::Print(int indent) const +{ + const char* ASN1TypeNames[0x32] = { + "INVALID", "BOOLEAN", "INTEGER", "BIT_STRING", "OCTET_STRING", "NULL", "OBJECT_ID", + 0, 0, 0, 0, 0, "UTF8String", 0, 0, 0, 0, 0, 0, "PrintableString", "TeletexString", + 0, "IA5String", 0, 0, 0, 0, 0, 0, 0, "BMPString", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, "SEQUENCE", "SET" + }; + // Encoded Length: + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb648641(v=vs.85).aspx + // if len < 128, single byte, otherwise it is bit 7 + sizeof(len), followed by len + + const char* typeName = 0; + if (m_type >= 0 && m_type < 0x32) + { + typeName = ASN1TypeNames[m_type]; + } + if (!typeName) + { + printf("invalid type: %i\n", m_type); + return; + } + for (int i = 0; i < indent; i++) + printf(" "); + printf("Type: %s, Size: %li\n", typeName, m_data.size()); + if (m_type == ASN1_Sequence || m_type == ASN1_Set) + for (const ASN1Object& obj: m_children) + obj.Print(indent + 2); +} + + diff --git a/Crypto/ASN1/ASN1.cpp b/Crypto/ASN1/ASN1.cpp new file mode 100644 index 0000000..f025de4 --- /dev/null +++ b/Crypto/ASN1/ASN1.cpp @@ -0,0 +1,113 @@ +#include +#include +#include +#include "ASN1.h" + + +ASN1Object::ASN1Object(const std::vector& asn1_encoded_data) + : m_type(ASN1_Invalid) +{ + m_tmp = 1; + + if (asn1_encoded_data.size() < 2) + { + printf("not enough data to form an object\n"); + return; + } + uint8_t sizeByte = asn1_encoded_data[1]; + size_t size = 0; + if (sizeByte & 0x80) + { + sizeByte &= 0x7F; + if (asn1_encoded_data.size() < (sizeByte + 2)) + { + printf("not enough data to decode the size bytes %i (data size: %li)\n", sizeByte, asn1_encoded_data.size()); + return; + } + for (int i = 0; i < sizeByte; i++) + { + size <<= 8; + size |= asn1_encoded_data[2 + i]; + } + if (asn1_encoded_data.size() < (sizeByte + 2 + size)) + { + printf("not enough data to decode an object of size %li (data size: %li)\n", size, asn1_encoded_data.size()); + return; + } + } + else + { + size = sizeByte; + if (asn1_encoded_data.size() < (size + 2)) + { + printf("not enough data to decode a small object of size %li (data size: %li)\n", size, asn1_encoded_data.size()); + return; + } + sizeByte = 0; + } + + m_tmp = 2 + sizeByte; + + // Copy the data + m_data.resize(size); + memcpy(&m_data[0], &asn1_encoded_data[sizeByte + 2], size); + + // Set the type + m_type = (ASN1Type)asn1_encoded_data[0]; + + if (m_type == ASN1_Sequence || m_type == ASN1_Set) + { + size_t sizeRemaining = size; + size_t offset = 0; + while (sizeRemaining) + { + std::vector data; + data.resize(sizeRemaining); + memcpy(&data[0], &m_data[offset], sizeRemaining); + + ASN1Object child(data); + if (child.m_type == ASN1_Invalid) + { + printf("error with decoding the children of sequence or set\n"); + return; + } + m_children.push_back(child); + + sizeRemaining -= child.m_data.size() + child.m_tmp; + offset += child.m_data.size() + child.m_tmp; + } + } +} + + +void ASN1Object::Print(int indent) const +{ + const char* ASN1TypeNames[0x32] = { + "INVALID", "BOOLEAN", "INTEGER", "BIT_STRING", "OCTET_STRING", "NULL", "OBJECT_ID", + 0, 0, 0, 0, 0, "UTF8String", 0, 0, 0, 0, 0, 0, "PrintableString", "TeletexString", + 0, "IA5String", 0, 0, 0, 0, 0, 0, 0, "BMPString", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, "SEQUENCE", "SET" + }; + // Encoded Length: + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb648641(v=vs.85).aspx + // if len < 128, single byte, otherwise it is bit 7 + sizeof(len), followed by len + + const char* typeName = 0; + if (m_type >= 0 && m_type < 0x32) + { + typeName = ASN1TypeNames[m_type]; + } + if (!typeName) + { + printf("invalid type: %i\n", m_type); + return; + } + for (int i = 0; i < indent; i++) + printf(" "); + printf("Type: %s, Size: %li\n", typeName, m_data.size()); + if (m_type == ASN1_Sequence || m_type == ASN1_Set) + for (const ASN1Object& obj: m_children) + obj.Print(indent + 2); +} + + diff --git a/Crypto/ASN1/ASN1.h b/Crypto/ASN1/ASN1.h new file mode 100644 index 0000000..3afdb8d --- /dev/null +++ b/Crypto/ASN1/ASN1.h @@ -0,0 +1,40 @@ +#ifndef ASN1_H +#define ASN1_H + + +#include + + +class ASN1Object +{ +public: + ASN1Object(const std::vector& asn1_encoded_data); + void Print(int indent = 0) const; +private: + // Type tags from documentation here: + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb540791(v=vs.85).aspx + // https://msdn.microsoft.com/en-us/library/windows/desktop/bb648642(v=vs.85).aspx + enum ASN1Type { + ASN1_Invalid = 0x00, + ASN1_Boolean = 0x01, + ASN1_Integer = 0x02, + ASN1_BitString = 0x03, + ASN1_OctetString = 0x04, + ASN1_Null = 0x05, + ASN1_ObjectId = 0x06, + ASN1_UTF8String = 0x0C, + ASN1_PrintableString = 0x13, + ASN1_TeletexString = 0x14, + ASN1_IA5String = 0x16, + ASN1_BMPString = 0x1E, + ASN1_Sequence = 0x30, + ASN1_Set = 0x31 + }; + ASN1Type m_type; + std::vector m_data; + std::vector m_children; + size_t m_tmp; +}; + +#endif // ASN1_H +