Skip to content

Commit dbb2385

Browse files
committed
Add CramMD5 auth for platforms that have enough crypto to support this (ESP32)
1 parent 0d0926f commit dbb2385

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

EMailSender.cpp

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

3535
#include "EMailSender.h"
3636
#include <stdio.h>
37+
#include <mbedtls/base64.h>
38+
3739
//#include <SPIFFS.h>
3840
//#include <LittleFS.h>
3941

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