First version with SendEncryptedContext

This commit is contained in:
Michael Geramb 2023-11-12 16:44:44 +01:00
parent 3d955be629
commit 3cd8f8469a
5 changed files with 213 additions and 21 deletions

View File

@ -851,7 +851,6 @@ int HAPClient::getAccessoriesURL(){
unauthorizedError();
return(0);
}
LOG1("In Get Accessories #");
LOG1(conNum);
LOG1(" (");
@ -859,22 +858,27 @@ int HAPClient::getAccessoriesURL(){
LOG1(")...\n");
int nBytes = homeSpan.sprintfAttributes(NULL); // get size of HAP attributes JSON
TempBuffer <char> jBuf(nBytes+1,"HAPClient::getAccessoriesURL");
homeSpan.sprintfAttributes(jBuf.get()); // create JSON database (will need to re-cast to uint8_t* below)
char *body;
asprintf(&body,"HTTP/1.1 200 OK\r\nContent-Type: application/hap+json\r\nContent-Length: %d\r\n\r\n",nBytes);
// TempBuffer <char> jBuf(nBytes+1,"HAPClient::getAccessoriesURL");
// homeSpan.sprintfAttributes(jBuf.get()); // create JSON database (will need to re-cast to uint8_t* below)
// char *body;
// asprintf(&body,"HTTP/1.1 200 OK\r\nContent-Type: application/hap+json\r\nContent-Length: %d\r\n\r\n",nBytes);
LOG2("\n>>>>>>>>>> ");
LOG2(client.remoteIP());
LOG2(" >>>>>>>>>>\n");
LOG2(body);
LOG2(jBuf.get());
LOG2("\n");
// LOG2("\n>>>>>>>>>> ");
// LOG2(client.remoteIP());
// LOG2(" >>>>>>>>>>\n");
// LOG2(body);
// LOG2(jBuf.get());
// LOG2("\n");
sendEncrypted(body,(uint8_t *)jBuf.get(),nBytes);
free(body);
// sendEncrypted(body,(uint8_t *)jBuf.get(),nBytes);
// free(body);
SendEncryptedContext context(*this);
context.printf("HTTP/1.1 200 OK\r\nContent-Type: application/hap+json\r\nContent-Length: %d\r\n\r\n",nBytes);
homeSpan.sprintfAttributes(NULL, GET_VALUE|GET_META|GET_PERMS|GET_TYPE|GET_DESC, &context);
return(1);
} // getAccessories

View File

@ -39,6 +39,7 @@
#include "HomeSpan.h"
#include "HAP.h"
#include "SendEncryptedContext.h"
const __attribute__((section(".rodata_custom_desc"))) SpanPartition spanPartition = {HOMESPAN_MAGIC_COOKIE,0};
@ -1227,19 +1228,33 @@ Span& Span::setWifiCredentials(const char *ssid, const char *pwd){
///////////////////////////////
int Span::sprintfAttributes(char *cBuf, int flags){
int Span::sprintfAttributes(char *cBuf, int flags, SendEncryptedContext* sendEncryptedContext){
int nBytes=0;
nBytes+=snprintf(cBuf,cBuf?64:0,"{\"accessories\":[");
if (sendEncryptedContext != NULL)
sendEncryptedContext->print("{\"accessories\":[");
for(int i=0;i<Accessories.size();i++){
nBytes+=Accessories[i]->sprintfAttributes(cBuf?(cBuf+nBytes):NULL,flags);
if(i+1<Accessories.size())
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",");
SpanAccessory* accessory=Accessories[i];
int accessoryBytes=accessory->sprintfAttributes(cBuf?(cBuf+nBytes):NULL,flags);
nBytes+= accessoryBytes;
if (sendEncryptedContext != NULL)
{
char* buffer = sendEncryptedContext->reserveStringBuffer(accessoryBytes);
accessory->sprintfAttributes(buffer, flags);
}
if(i+1<Accessories.size())
{
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,",");
if (sendEncryptedContext != NULL)
sendEncryptedContext->print(",");
}
}
nBytes+=snprintf(cBuf?(cBuf+nBytes):NULL,cBuf?64:0,"]}");
if (sendEncryptedContext != NULL)
sendEncryptedContext->print("]}");
return(nBytes);
}

View File

@ -48,6 +48,7 @@
#include "extras/Pixel.h"
#include "Settings.h"
#include "Utils.h"
#include "SendEncryptedContext.h"
#include "Network.h"
#include "HAPConstants.h"
#include "HapQR.h"
@ -268,7 +269,7 @@ class Span{
void resetStatus(); // resets statusLED and calls statusCallback based on current HomeSpan status
void reboot(); // reboots device
int sprintfAttributes(char *cBuf, int flags=GET_VALUE|GET_META|GET_PERMS|GET_TYPE|GET_DESC); // prints Attributes JSON database into buf, unless buf=NULL; return number of characters printed, excluding null terminator
int sprintfAttributes(char *cBuf, int flags=GET_VALUE|GET_META|GET_PERMS|GET_TYPE|GET_DESC, SendEncryptedContext* sendEncryptedContext = nullptr); // prints Attributes JSON database into buf, unless buf=NULL; return number of characters printed, excluding null terminator
void prettyPrint(char *buf, int nsp=2, int minLogLevel=0); // print arbitrary JSON from buf to serial monitor, formatted with indentions of 'nsp' spaces, subject to specified minimum log level
SpanCharacteristic *find(uint32_t aid, int iid); // return Characteristic with matching aid and iid (else NULL if not found)

View File

@ -0,0 +1,116 @@
/*********************************************************************************
* MIT License
*
* Copyright (c) 2020-2023 Michael Geramb
*
* https://github.com/HomeSpan/HomeSpan
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
********************************************************************************/
#include <Arduino.h>
#include "SendEncryptedContext.h"
#include "HomeSpan.h"
#include "HAP.h"
#include "Settings.h"
#include <sodium.h>
SendEncryptedContext::SendEncryptedContext(HAPClient& hapClient)
: hapClient(hapClient),
stringBuffer(FRAME_SIZE + 1, "SendEncryptedContext dataBuffer"),
sendBuffer(FRAME_SIZE + 2 + 16, "SendEncryptedContext sendBuffer") // FRAME_SIZE + AAD + Auth
{
LOG2("\n>>>>>>>>>> ");
LOG2(hapClient.client.remoteIP());
LOG2(" >>>>>>>>>>\n");
}
void SendEncryptedContext::printf(const char* format, ...)
{
va_list ap;
va_start(ap, format);
int len = vsnprintf(NULL, 0, format, ap);
char* buffer = reserveStringBuffer(len);
vsnprintf(buffer, len + 1, format, ap); // the reserved buffer is one byte larger because it contains the terminating '\0'
LOG2(buffer);
va_end(ap);
}
void SendEncryptedContext::print(const char* text)
{
auto len = strlen(text);
auto buffer = reserveStringBuffer(len);
memcpy(buffer, text, len);
LOG2(buffer);
}
char* SendEncryptedContext::reserveStringBuffer(int stringLength)
{
int requiredNewBufferLength = stringLength + 1; // reserve buffer for characters and string terminator '\0'
if (stringBuffer.len() - usedStringLength < requiredNewBufferLength)
{
// to less memory, send first exitsting buffer
if (usedStringLength > 0)
{
sendEncrypted(stringBuffer.get(), usedStringLength);
usedStringLength = 0;
}
// Check if still more memory is needed
if (stringBuffer.len() < requiredNewBufferLength)
stringBuffer = TempBuffer<char>(requiredNewBufferLength, "SendEncryptedContext::reserveMemory");
}
int alreadyInUse = usedStringLength;
usedStringLength += stringLength;
char* result = stringBuffer.get() + alreadyInUse;
result[stringLength] = '\0'; // add string terminator
return result;
}
void SendEncryptedContext::sendEncrypted(const char* buffer, int length)
{
if (length == 0)
return;
sentLength += length;
LOG2(buffer);
for(int i=0;i<length;i+=FRAME_SIZE){ // encrypt FRAME_SIZE number of bytes in dataBuf in sequential frames
int n=length-i; // number of bytes remaining
if(n>FRAME_SIZE) // maximum number of bytes to encrypt=FRAME_SIZE
n=FRAME_SIZE;
sendBuffer.get()[0]=n%256; // store number of bytes that encrypts this frame (AAD bytes)
sendBuffer.get()[1]=n/256;
unsigned long long nBytes;
crypto_aead_chacha20poly1305_ietf_encrypt(sendBuffer.get()+2,&nBytes, (uint8_t*) buffer+i,n,sendBuffer.get(),2,NULL,hapClient.a2cNonce.get(),hapClient.a2cKey); // encrypt the next portion of dataBuf with authentication tag appended
hapClient.client.write(sendBuffer.get(),nBytes+2); // transmit encrypted frame
hapClient.a2cNonce.inc(); // increment nonce
}
}
SendEncryptedContext::~SendEncryptedContext()
{
if (usedStringLength > 0)
sendEncrypted(stringBuffer.get(), usedStringLength);
LOG2("-------- SENT ENCRYPTED! --------\n");
}

View File

@ -0,0 +1,56 @@
/*********************************************************************************
* MIT License
*
* Copyright (c) 2020-2023 Michael Geramb
*
* https://github.com/HomeSpan/HomeSpan
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
********************************************************************************/
#pragma once
#include "Utils.h"
struct HAPClient;
/////////////////////////////////////////////////
// SendEncryptedContext class
// Write encrypted data as response to a web call
class SendEncryptedContext
{
const int FRAME_SIZE=1024; // number of bytes to use in each ChaCha20-Poly1305 encrypted frame when sending encrypted JSON content to Client
TempBuffer<char> stringBuffer;
int usedStringLength = 0;
int sentLength = 0;
HAPClient& hapClient;
TempBuffer<uint8_t> sendBuffer;
public:
SendEncryptedContext(HAPClient& hapClient);
~SendEncryptedContext();
void printf(const char* format, ...);
void print(const char* text);
char* reserveStringBuffer(int stringLength);
private:
void sendEncrypted(const char* buffer, int length);
};