Click here to Skip to main content
13,665,554 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

19.8K views
536 downloads
17 bookmarked
Posted 23 Jul 2016
Licenced CPOL

C++ 11 S/MIME: A simple MIME parser and builder with security features

, 11 Mar 2017
Rate this:
Please Sign up or sign in to vote.
Easy to use simple parser with S/MIME Support

 

Introduction

This is a very simple MIME parser and builder which uses C++ 11 elements and Win32 API for quick stuff.

Also extensive S/MIME support with sign, encrypt, verify and timestamps.

Includes a QP Decoder from https://github.com/Psychtoolbox-3/Psychtoolbox-3/blob/master/Psychtoolbox/PsychHardware/iViewXToolbox/cbase64/AMMimeUtils.cpp

Single Message Builder

// Single Message
MIMELIB::CONTENT c;

c["MIME-Version"] = "1.0";
c["Content-Type"] = "text/plain";
c.SetData("Hello");

auto str = c.Serialize();

Result

MIME-Version: 1.0
Content-Type: text/plain

Hello

Some Binary Message

MIMELIB::CONTENT c;
c["MIME-Version"] = "1.0";
c["Content-Type"] = "application/octet-stream";
c["Content-Transfer-Encoding"] = "base64";
c["Content-Disposition"] = "attachment; filename=\"hello.txt\"";
string out = MIMELIB::Char2Base64("Hello", 5);
c.SetData(out.c_str());

auto str = c.Serialize();

Result

MIME-Version: 1.0
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="hello.txt"

SGVsbG8=

Multipart Builder

MIMELIB::CONTENTBUILDER cb;
MIMELIB::CONTENT e1;
MIMELIB::CONTENT e2;
e1["Content-Type"] = "text/plain";
e1.SetData("Hello\r\n\r\n");
e2["Content-Type"] = "text/html";
e2.SetData("<b>Hello</b>");

cb.Add(e1);
cb.Add(e2);

MIMELIB::CONTENT cc;
cb.Build(cc, "multipart/alternative");

auto str = cc.Serialize();

Result

MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}"

--{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}
Content-Type: text/plain

Hello

--{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}
Content-Type: text/html

<b>Hello</b>

--{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}--

 

Parse Simple

    string str = 
R"(MIME-Version: 1.0
Content-Type: text/plain

Hello)";

    MIMELIB::CONTENT c;
    if (c.Parse(str.c_str()) != MIMELIB::MIMEERR::OK)
        return;

    auto a1 = c.hval("Content-Type"); // a1 = "text/plain"
    auto a2 = c.GetData(); // vector<char> with the data

Parse Multiple

string str = "MIME-Version: 1.0\r\n\
Content-Type: multipart/alternative; boundary=\"{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}\"\r\n\r\n\
\r\n\
--{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}\r\n\
Content-Type: text/plain\r\n\
\r\n\
Hello\r\n\
\r\n\
--{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}\r\n\
Content-Type: text/html\r\n\
\r\n\
<b>Hello</b>\r\n\
\r\n\
--{79EAC9E2-BAF9-11CE-8C82-00AA004BA90B}--";

    MIMELIB::CONTENT c;
    if (c.Parse(str.c_str()) != MIMELIB::MIMEERR::OK)
        return;

    auto a1 = c.hval("Content-Type","boundary"); // a1 = the boundary
    if (a1.empty())
        return;

    vector<MIMELIB::CONTENT> Contents;
    MIMELIB::ParseMultipleContent(str.c_str(), a1.c_str(), Contents);

    // Should have 2
    vector<char> d;
    Contents[1].DecodeData(d); // Decodes from Base64 or Quoted-Printable
    // d = "<b>Hello</b>"

 

S/MIME

Sign

// Single Message
    MIMELIB::CONTENT c;

    c["MIME-Version"] = "1.0";
    c["Content-Type"] = "text/plain";
    c.SetData("Hello");
    PCCERT_CONTEXT cert = nullptr; // If not null, it will be used, else the user picks a cert.
    c.Sign(c, cert, true); // Attached. If you want detached, pass false and another MIMELIB::CONTENT as first param

    auto str = c.Serialize();

Result

MIME-Version: 1.0
Content-Type: application/pkcs7-mime; smime-type=signed-data; name="smime.p7m"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7m"

MIIG0QYJKoZIhvcNAQcCoIIGwjCCBr4CAQExDzANBgkqhkiG9w0BAQsFADBFBgkq
hkiG9w0BBwGgOAQ2TUlNRS1WZXJzaW9uOiAxLjANCkNvbnRlbnQtVHlwZTogdGV4
dC9wbGFpbg0KDQpIZWxsbw0KoIIFWzCCBVcwggM/oAMCAQICAjFhMA0GCSqGSIb3
DQEBCwUAMFExCzAJBgNVBAYTAkdSMSQwIgYDVQQKExtHcmVlayBNaW5pc3RyeSBv
ZiBFZHVjYXRpb24xHDAaBgNVBAMTE1NDSCBVU0VSIENsYXNzIDEgQ0EwHhcNMTYw
NzAzMTQ0MzQwWhcNMTcwMTAyMTQ0MzQwWjBJMQswCQYDVQQGEwJHUjEMMAoGA1UE
CgwDU0NIMRswGQYDVQQDDBJDSE9VUkRBS0lTIE1JQ0hBSUwxDzANBgNVBAUTBjE4
MDIxNTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAs/v8o+8a9ZkiJq4wlEMW
Y1pFmUB1pGMXdPcXSFLoQ8ZOyAXpyKcdjNWC1fQWCHBLVqMq8wQYQ56ReDtpVJgv
PSR2d4PrU7yvenHYhUqLo/3ofa1i/X8SnmA9XwdAgN4mfvS67yjrEYkI7N/0nr2v
ZHvh/JxLeBIdPRbyRaGDu10CAwEAAaOCAcMwggG/MAwGA1UdEwEB/wQCMAAwDgYD
VR0PAQH/BAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUFBwMEBggrBgEFBQcDAjARBglg
hkgBhvhCAQEEBAMCBaAwHQYDVR0OBBYEFM59ESeBE44FMsUJ46lD0MI2iMlIMB8G
A1UdIwQYMBaAFAoL5fnH3ueIw8rDlLGTqmSGA5QoMDEGCCsGAQUFBwEBBCUwIzAh
BggrBgEFBQcwAYYVaHR0cDovL2NhLnNjaC5ncjoyNTYwMBwGA1UdEQQVMBOBEWZy
YW56bGlzenRAc2NoLmdyMDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jYS5zY2gu
Z3IvcHViL2NybC9zY2gtdXNlci1jMS5jcmwwNwYJYIZIAYb4QgEEBCoWKGh0dHA6
Ly9jYS5zY2guZ3IvcHViL2NybC9zY2gtdXNlci1jMS5jcmwwJwYJYIZIAYb4QgEI
BBoWGGh0dHA6Ly9jYS5zY2guZ3IvcG9saWN5LzAfBglghkgBhvhCAQIEEhYQaHR0
cDovL2NhLnNjaC5ncjAeBgkrBgEEAbxmAwMEETEPFg1FS1BBSURFRlRJS09TMA0G
CSqGSIb3DQEBCwUAA4ICAQCeS9tK+QuE0yO643XcJy4agxWSuy5qqykhxgCWw2ZZ
x6gRmfmI2VQobZjvakRV6ZMYw2yOGQ3RApjhQvpvp48FPVCQlKUP90DTQ92ahXdy
Qzsh6erCRDznQDcMA2LeVDCWvSAGtNG9r7k5fZCUMhgBGGUwboLZxvIogzEeCRVC
P2hvWWnmSEqEt8l9X5fm29xrtjVpbtmaxOTFF1L7FVsWhM3DEpdMpZ+2qdMxRPw/
mtQIg8R+N0N4/mc/qiqHo3NZANWlYGc16XQpZto8wToIW/yxnhJvULO32dVx+CFs
EYyLiz+qoe5vCxw99baaCDDzEY+4HXvUvWJNdmvISgPTXmrTK+7sswJ3+qp+8ekE
FrZgRNC2kLy290xi+wu9w3GAk9fRn/4FaMNIfnAAzhVkiH7bGJGwm+FQA6nwltPB
qxr3TBu3o7K5NY5TZU6NUAA5tkpCDgQ1PDLvbmhuqdRBStmmkJ6P9d9KYqRCVhf9
Ilr2LPAasNm1Q5WZumB8GPBw+t6i+mpfBBTAVxQbUNxNgykmreaLP/5JjBXoL50K
hHqePxMYEF867suwpTQU1sMWIRgsXu+osvcCS6X4YC/VKGSEGV+PEshqHI4mgDq6
8LGUSwTRHiIf6RAkjww4KcqE2ni7lkG25i8cmTslsAhr8e2UPKcdBUnofpG8G18q
UDGCAQAwgf0CAQEwVzBRMQswCQYDVQQGEwJHUjEkMCIGA1UEChMbR3JlZWsgTWlu
aXN0cnkgb2YgRWR1Y2F0aW9uMRwwGgYDVQQDExNTQ0ggVVNFUiBDbGFzcyAxIENB
AgIxYTANBgkqhkiG9w0BAQsFADANBgkqhkiG9w0BAQEFAASBgHRHrCSawIHLu8i6
5UwYCWoZRFpTp+Sk3epXAg62TcDNfM8zvsHmvUrHU5glEdl/P8zbiGfb1Wzs3CN3
Tn7RJgb5zQBw7FbGhD71515dclmAQHwjr4K76gLrv+Vz3do9NEvnEu8WAWQW19u+
vovVmL/ZpbX4YuJBxMYX77x8svuX

Encrypt

// Single Message
MIMELIB::CONTENT c;

c["MIME-Version"] = "1.0";
c["Content-Type"] = "text/plain";
c.SetData("Hello");
PCCERT_CONTEXT cert = nullptr; // If not null, it will be used, else the user picks a cert.
c.Encrypt(c, cert);

auto str = c.Serialize();

Result

MIME-Version: 1.0
Content-Type: application/pkcs7-mime; smime-type=enveloped-data; name="smime.p7m"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="smime.p7m"

MIIBXQYJKoZIhvcNAQcDoIIBTjCCAUoCAQAxgfEwge4CAQAwVzBRMQswCQYDVQQG
EwJHUjEkMCIGA1UEChMbR3JlZWsgTWluaXN0cnkgb2YgRWR1Y2F0aW9uMRwwGgYD
VQQDExNTQ0ggVVNFUiBDbGFzcyAxIENBAgIxYTANBgkqhkiG9w0BAQEFAASBgC93
eDnXKXKaFlOvJgZLlrtdTAc/3lIb0OogUGl/+sDc/GxkVuPueYEuI9sklXi86H15
1A9KM4qOBgGbGoeIyHEmFqkbcYmxV7Eif2GMN4fgYqcNSwZq/BMahNJ3+OPbHoEb
eCAkoFSEiZ+FY8xoYNlwrZlvPUPZUYtVu7MWbwtrMFEGCSqGSIb3DQEHATAMBggq
hkiG9w0DBAUAgDbh+wWhuZe1hUoTSq6kTJwVz0mg8xqG1AE2FMtiZgML3br1ZF+Y
a/DBvgTNz7kzwQ2d5yRrIok=

Verify

auto res = c.VerifySignature();
if (res == MIMELIB::MIMEERR::ERRSIGN) // ...
if (res == MIMELIB::MIMEERR::NOTSIGNED) // ...
if (res == MIMELIB::MIMEERR::OK) // ...

Low Level Functions

// Sign with multiple certs, add also certs, with timestamp support
MIMEERR Sign2(CONTENT& co, std::vector<PCCERT_CONTEXT> certs, std::vector<PCCERT_CONTEXT> addcerts,const wchar_t* TimeStampServer = 0,bool Attached = true, bool BinaryOutput = false,vector<char>* cc = 0,CONTENT* pct = 0)

// Verify TimeStamp
MIMEERR VerifyTimestamp2(PCCERT_CONTEXT* p = 0, FILETIME* ft = 0);

 

HTTP support

vector<char> data = "HTTP 1/1 200 OK\r\n...."
c.Parse(data.data(),true); // true indicates a possible HTTP header
auto mh = c1.httphdr(); // Gets the header

Or build

c.AddHTTPHeader("HTTP 1/1 200 OK");

 

Have fun with it!

History

02 - 08 - 2016: Added binary support for all sort of operations.
30 - 7 - 2016 : Added Timestamp support and low level functions, builder for detached signatures.
23 - 7 - 2016 : First Release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Michael Chourdakis
Engineer
Greece Greece
I'm working in C++, PHP , Java, Windows, iOS and Android.

I 've a PhD in Digital Signal Processing and I specialize in Pro Audio applications.

My home page: http://www.michaelchourdakis.com

You may also be interested in...

Pro

Comments and Discussions

 
QuestionWhat about UNICODE? Pin
Michael Haephrati8-Jan-18 8:35
mvpMichael Haephrati8-Jan-18 8:35 
AnswerRe: What about UNICODE? Pin
Michael Chourdakis8-Jan-18 11:40
mvpMichael Chourdakis8-Jan-18 11:40 
GeneralRe: What about UNICODE? Pin
Michael Haephrati8-Jan-18 11:49
mvpMichael Haephrati8-Jan-18 11:49 
GeneralRe: What about UNICODE? Pin
Michael Chourdakis8-Jan-18 11:52
mvpMichael Chourdakis8-Jan-18 11:52 
AnswerRe: What about UNICODE? Pin
Michael Haephrati8-Jan-18 11:58
mvpMichael Haephrati8-Jan-18 11:58 
GeneralRe: What about UNICODE? Pin
Michael Chourdakis8-Jan-18 12:19
mvpMichael Chourdakis8-Jan-18 12:19 
GeneralRe: What about UNICODE? Pin
Michael Haephrati9-Jan-18 7:45
mvpMichael Haephrati9-Jan-18 7:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web06-2016 | 2.8.180810.1 | Last Updated 12 Mar 2017
Article Copyright 2016 by Michael Chourdakis
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid