Skip to content

Commit b59a995

Browse files
authored
Merge pull request xreef#45 from dirkx/digestMD5-feature
Add CramMD5 auth
2 parents 0d0926f + 24203a9 commit b59a995

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

EMailSender.cpp

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@
3434

3535
#include "EMailSender.h"
3636
#include <stdio.h>
37+
#if defined(ESP32)
38+
#include <mbedtls/base64.h>
39+
#endif
40+
3741
//#include <SPIFFS.h>
3842
//#include <LittleFS.h>
3943

@@ -624,7 +628,70 @@ EMailSender::Response EMailSender::send(const char* to[], byte sizeOfTo, byte s
624628
// String auth = "AUTH PLAIN "+String(encode64(logPass));
625629
DEBUG_PRINTLN(auth);
626630
client.println(auth);
627-
}else{
631+
}
632+
#if defined(ESP32)
633+
else if (this->isCramMD5Login == true) {
634+
DEBUG_PRINTLN(F("AUTH CRAM-MD5"));
635+
client.println(F("AUTH CRAM-MD5"));
636+
637+
// read back the base64 encoded digest.
638+
//
639+
response = awaitSMTPResponse(client,"334","No digest error");
640+
if (!response.status) {
641+
client.flush();
642+
client.stop();
643+
return response;
644+
};
645+
_serverResponce = _serverResponce.substring(4); // '334<space>'
646+
647+
size_t b64l = _serverResponce.length()-1; // C vs C++ counting of \0
648+
const unsigned char * b64 = (const unsigned char *)_serverResponce.c_str();
649+
DEBUG_PRINTLN("B64digest="+String((char *)b64) + " Len=" + String((int)b64l));
650+
651+
unsigned char digest[256];
652+
size_t len;
653+
654+
int e = mbedtls_base64_decode(digest, sizeof(digest), &len, b64, b64l);
655+
if (e || len < 3 || len >= 256) {
656+
response.code = F("999");
657+
response.desc = F("Invalid digest");
658+
response.status = false;
659+
client.flush();
660+
client.stop();
661+
return response;
662+
};
663+
664+
// calculate HMAC with the password as the key of this digest.
665+
//
666+
mbedtls_md_context_t ctx;
667+
mbedtls_md_type_t md_type = MBEDTLS_MD_MD5;
668+
unsigned char md5[16];
669+
670+
mbedtls_md_init(&ctx);
671+
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1);
672+
mbedtls_md_hmac_starts(&ctx,
673+
(const unsigned char *)this->email_password, strlen(this->email_password));
674+
mbedtls_md_hmac_update(&ctx, digest, len);
675+
mbedtls_md_hmac_finish(&ctx, md5);
676+
mbedtls_md_free(&ctx);
677+
678+
// build an output string of the username followed by the __lowercase__ hex of the md5
679+
//
680+
String rsp = String(this->email_login) + " ";
681+
for(int i = 0; i < sizeof(md5); i++) {
682+
unsigned char c = md5[i];
683+
char h[16+1] = "0123456789abcdef";
684+
rsp += String(h[ (c >> 4) &0xF]) + String(h[ (c >> 0) &0xF]);
685+
};
686+
687+
// And submit this to the server as a login string.
688+
DEBUG_PRINTLN(encode64((char*)rsp.c_str()));
689+
client.println(encode64((char*)rsp.c_str()));
690+
691+
// now exepct the normal login confirmation to continue.
692+
}
693+
#endif
694+
else{
628695
DEBUG_PRINTLN(F("AUTH LOGIN:"));
629696
client.println(F("AUTH LOGIN"));
630697
awaitSMTPResponse(client);

EMailSender.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,13 @@ class EMailSender {
462462
this->isSASLLogin = isSASLLogin;
463463
}
464464

465+
#if defined(ESP32)
466+
// Conditional - as it relies on considerable crypto infra.
467+
void setCramMD5Login(bool onoff= false) {
468+
this->isCramMD5Login = onoff;
469+
}
470+
#endif
471+
465472
void setAdditionalResponseLineOnConnection(uint8_t numLines = 0) {
466473
this->additionalResponseLineOnConnection = numLines;
467474
}
@@ -485,6 +492,7 @@ class EMailSender {
485492
bool isSASLLogin = false;
486493

487494
bool useAuth = true;
495+
bool isCramMD5Login = false;
488496

489497
String _serverResponce;
490498

0 commit comments

Comments
 (0)