1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-11-06 08:49:29 +02:00

Add strNewEncode(), strCatEncode(), and bufNewDecode().

These constructors wrap encodeToStr() and decodeToBin(), making them convenient and safe by eliminating the need to create intermediate buffers. Encoding/decoding is performed directly into the target String/Buffer. Sizing of the destination buffer is handled by the new functions so it doesn't have to be done at each call site.
This commit is contained in:
David Steele
2021-02-19 17:05:15 -05:00
parent 5b98968605
commit d485609658
15 changed files with 133 additions and 46 deletions

View File

@@ -5,7 +5,6 @@ Stanza Commands Handler
#include "command/check/common.h"
#include "common/debug.h"
#include "common/encode.h"
#include "common/log.h"
#include "config/config.h"
#include "db/helper.h"
@@ -27,12 +26,9 @@ cipherPassGen(CipherType cipherType)
if (cipherType != cipherTypeNone)
{
unsigned char buffer[48]; // 48 is the amount of entropy needed to get a 64 base key
char cipherPassSubChar[65];
ASSERT(encodeToStrSize(encodeBase64, sizeof(buffer)) + 1 == sizeof(cipherPassSubChar));
cryptoRandomBytes(buffer, sizeof(buffer));
encodeToStr(encodeBase64, buffer, sizeof(buffer), cipherPassSubChar);
result = strNew(cipherPassSubChar);
result = strNewEncode(encodeBase64, BUF(buffer, sizeof(buffer)));
}
FUNCTION_TEST_RETURN(result);

View File

@@ -6,6 +6,8 @@ These high-level functions are preferred to the low-level functions for each enc
#ifndef COMMON_ENCODE_H
#define COMMON_ENCODE_H
#include <stddef.h>
/***********************************************************************************************************************************
Encoding types
***********************************************************************************************************************************/

View File

@@ -87,6 +87,23 @@ bufNewC(const void *buffer, size_t size)
FUNCTION_TEST_RETURN(this);
}
/**********************************************************************************************************************************/
Buffer *
bufNewDecode(EncodeType type, const String *string)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, type);
FUNCTION_TEST_PARAM(STRING, string);
FUNCTION_TEST_END();
Buffer *this = bufNew(decodeToBinSize(type, strZ(string)));
decodeToBin(type, strZ(string), bufPtr(this));
bufUsedSet(this, bufSize(this));
FUNCTION_TEST_RETURN(this);
}
/**********************************************************************************************************************************/
Buffer *
bufDup(const Buffer *buffer)

View File

@@ -43,6 +43,10 @@ Buffer *bufNew(size_t size);
// Create a new buffer from a C buffer
Buffer *bufNewC(const void *buffer, size_t size);
// Create a new buffer from a string encoded with the specified type
Buffer *bufNewDecode(EncodeType type, const String *string);
// Duplicate a buffer
Buffer *bufDup(const Buffer *buffer);
/***********************************************************************************************************************************

View File

@@ -138,6 +138,37 @@ strNewBuf(const Buffer *buffer)
FUNCTION_TEST_RETURN(this);
}
/**********************************************************************************************************************************/
String *
strNewEncode(EncodeType type, const Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(ENUM, type);
FUNCTION_TEST_PARAM(BUFFER, buffer);
FUNCTION_TEST_END();
ASSERT(buffer != NULL);
// Check encoded size
size_t size = encodeToStrSize(type, bufUsed(buffer));
CHECK_SIZE(size);
// Create object
String *this = memNew(sizeof(String));
*this = (String)
{
.memContext = memContextCurrent(),
.size = (unsigned int)size,
};
// Allocate and encode buffer
this->buffer = memNew(this->size + 1);
encodeToStr(type, bufPtrConst(buffer), bufUsed(buffer), this->buffer);
FUNCTION_TEST_RETURN(this);
}
/**********************************************************************************************************************************/
String *
strNewFmt(const char *format, ...)
@@ -394,6 +425,33 @@ strCatChr(String *this, char cat)
FUNCTION_TEST_RETURN(this);
}
/**********************************************************************************************************************************/
String *
strCatEncode(String *this, EncodeType type, const Buffer *buffer)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(STRING, this);
FUNCTION_TEST_PARAM(ENUM, type);
FUNCTION_TEST_PARAM(BUFFER, buffer);
FUNCTION_TEST_END();
ASSERT(this != NULL);
ASSERT(buffer != NULL);
// Ensure there is enough space to grow the string
size_t encodeSize = encodeToStrSize(type, bufUsed(buffer));
strResize(this, encodeSize);
// Append the encoded string
encodeToStr(type, bufPtrConst(buffer), bufUsed(buffer), this->buffer + this->size);
// Update size/extra
this->size += (unsigned int)encodeSize;
this->extra -= (unsigned int)encodeSize;
FUNCTION_TEST_RETURN(this);
}
/**********************************************************************************************************************************/
String *
strCatFmt(String *this, const char *format, ...)

View File

@@ -36,6 +36,7 @@ String object
typedef struct String String;
#include "common/assert.h"
#include "common/encode.h"
#include "common/type/buffer.h"
/***********************************************************************************************************************************
@@ -67,6 +68,9 @@ String *strNewBuf(const Buffer *buffer);
// Create a new string by converting the double value
String *strNewDbl(double value);
// Create a new string encoded with the specified type (e.g. encodeBase64) from a buffer
String *strNewEncode(EncodeType type, const Buffer *buffer);
// Create a new string from a format string with parameters (i.e. sprintf)
String *strNewFmt(const char *format, ...) __attribute__((format(printf, 1, 2)));
@@ -96,6 +100,9 @@ String *strCatZ(String *this, const char *cat);
// Append a character
String *strCatChr(String *this, char cat);
// Append a string encoded with the specified type (e.g. encodeBase64) from a buffer
String *strCatEncode(String *this, EncodeType type, const Buffer *buffer);
// Append a formatted string
String *strCatFmt(String *this, const char *format, ...) __attribute__((format(printf, 2, 3)));

View File

@@ -10,7 +10,6 @@ Info Handler
#include "common/type/convert.h"
#include "common/crypto/hash.h"
#include "common/debug.h"
#include "common/encode.h"
#include "common/io/filter/filter.intern.h"
#include "common/ini.h"
#include "common/log.h"

View File

@@ -7,7 +7,6 @@ Azure Storage
#include "common/crypto/common.h"
#include "common/crypto/hash.h"
#include "common/encode.h"
#include "common/debug.h"
#include "common/io/http/client.h"
#include "common/io/http/common.h"
@@ -71,7 +70,7 @@ struct StorageAzure
const String *container; // Container to store data in
const String *account; // Account
const String *sharedKey; // Shared key
const Buffer *sharedKey; // Shared key
const HttpQuery *sasKey; // SAS key
const String *host; // Host name
size_t blockSize; // Block size for multi-block upload
@@ -171,17 +170,9 @@ storageAzureAuth(
strZ(dateTime), strZ(headerCanonical), strZ(this->account), strZ(path), strZ(queryCanonical));
// Generate authorization header
Buffer *keyBin = bufNew(decodeToBinSize(encodeBase64, strZ(this->sharedKey)));
decodeToBin(encodeBase64, strZ(this->sharedKey), bufPtr(keyBin));
bufUsedSet(keyBin, bufSize(keyBin));
char authHmacBase64[45];
encodeToStr(
encodeBase64, bufPtr(cryptoHmacOne(HASH_TYPE_SHA256_STR, keyBin, BUFSTR(stringToSign))),
HASH_TYPE_SHA256_SIZE, authHmacBase64);
httpHeaderPut(
httpHeader, HTTP_HEADER_AUTHORIZATION_STR, strNewFmt("SharedKey %s:%s", strZ(this->account), authHmacBase64));
httpHeader, HTTP_HEADER_AUTHORIZATION_STR, strNewFmt("SharedKey %s:%s", strZ(this->account),
strZ(strNewEncode(encodeBase64, cryptoHmacOne(HASH_TYPE_SHA256_STR, this->sharedKey, BUFSTR(stringToSign))))));
}
// SAS authentication
else
@@ -229,9 +220,9 @@ storageAzureRequestAsync(StorageAzure *this, const String *verb, StorageAzureReq
// Calculate content-md5 header if there is content
if (param.content != NULL)
{
char md5Hash[HASH_TYPE_MD5_SIZE_HEX];
encodeToStr(encodeBase64, bufPtr(cryptoHashOne(HASH_TYPE_MD5_STR, param.content)), HASH_TYPE_M5_SIZE, md5Hash);
httpHeaderAdd(requestHeader, HTTP_HEADER_CONTENT_MD5_STR, STR(md5Hash));
httpHeaderAdd(
requestHeader, HTTP_HEADER_CONTENT_MD5_STR,
strNewEncode(encodeBase64, cryptoHashOne(HASH_TYPE_MD5_STR, param.content)));
}
// Encode path
@@ -773,7 +764,7 @@ storageAzureNew(
// Store shared key or parse sas query
if (keyType == storageAzureKeyTypeShared)
driver->sharedKey = key;
driver->sharedKey = bufNewDecode(encodeBase64, key);
else
driver->sasKey = httpQueryNewStr(key);

View File

@@ -6,7 +6,6 @@ Azure Storage File Write
#include <string.h>
#include "common/debug.h"
#include "common/encode.h"
#include "common/io/write.intern.h"
#include "common/log.h"
#include "common/memContext.h"

View File

@@ -6,7 +6,6 @@ S3 Storage
#include <string.h>
#include "common/crypto/hash.h"
#include "common/encode.h"
#include "common/debug.h"
#include "common/io/http/client.h"
#include "common/io/http/common.h"
@@ -306,9 +305,9 @@ storageS3RequestAsync(StorageS3 *this, const String *verb, const String *path, S
// Calculate content-md5 header if there is content
if (param.content != NULL)
{
char md5Hash[HASH_TYPE_MD5_SIZE_HEX];
encodeToStr(encodeBase64, bufPtr(cryptoHashOne(HASH_TYPE_MD5_STR, param.content)), HASH_TYPE_M5_SIZE, md5Hash);
httpHeaderAdd(requestHeader, HTTP_HEADER_CONTENT_MD5_STR, STR(md5Hash));
httpHeaderAdd(
requestHeader, HTTP_HEADER_CONTENT_MD5_STR,
strNewEncode(encodeBase64, cryptoHashOne(HASH_TYPE_MD5_STR, param.content)));
}
// When using path-style URIs the bucket name needs to be prepended

View File

@@ -113,6 +113,14 @@ unit:
coverage:
- common/time
# ----------------------------------------------------------------------------------------------------------------------------
- name: encode
total: 1
coverage:
- common/encode
- common/encode/base64
# ----------------------------------------------------------------------------------------------------------------------------
- name: type-string
total: 26
@@ -315,14 +323,6 @@ unit:
coverage:
- common/exec
# ----------------------------------------------------------------------------------------------------------------------------
- name: encode
total: 1
coverage:
- common/encode
- common/encode/base64
# ----------------------------------------------------------------------------------------------------------------------------
- name: ini
total: 4

View File

@@ -11,7 +11,7 @@ testRun(void)
FUNCTION_HARNESS_VOID();
// *****************************************************************************************************************************
if (testBegin("bufNew(), bufNewC, bufNewUseC, bufMove(), bufSize(), bufSizeAlloc(), bufPtr(), and bufFree()"))
if (testBegin("bufNew*(), bufMove(), bufSize(), bufSizeAlloc(), bufPtr(), and bufFree()"))
{
Buffer *buffer = NULL;
@@ -39,6 +39,11 @@ testRun(void)
TEST_ASSIGN(buffer, bufNewC(cBuffer, sizeof(cBuffer)), "create from c buffer");
TEST_RESULT_BOOL(memcmp(bufPtr(buffer), cBuffer, sizeof(cBuffer)) == 0, true, "check buffer");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("bufNewDecode()");
TEST_RESULT_STR_Z(strNewBuf(bufNewDecode(encodeBase64, STRDEF("eno="))), "zz", "decode base64");
}
// *****************************************************************************************************************************

View File

@@ -15,7 +15,7 @@ testRun(void)
FUNCTION_HARNESS_VOID();
// *****************************************************************************************************************************
if (testBegin("strNew(), strNewBuf(), strNewDbl(), strNewN(), strEmpty(), strZ(), strZNull(), strSize(), and strFree()"))
if (testBegin("strNew*(), strEmpty(), strZ(), strZNull(), strSize(), and strFree()"))
{
// We don't want this struct to grow since there are generally a lot of strings, so make sure it doesn't grow without us
// knowing about it
@@ -63,6 +63,11 @@ testRun(void)
TEST_ASSIGN(string, strNew(""), "new empty string");
TEST_RESULT_UINT(string->size, 0, " check size");
TEST_RESULT_UINT(string->extra, 64, " check extra");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("strNewEncode()");
TEST_RESULT_STR_Z(strNewEncode(encodeBase64, BUFSTRDEF("zz")), "eno=", "encode base64");
}
// *****************************************************************************************************************************
@@ -99,7 +104,7 @@ testRun(void)
}
// *****************************************************************************************************************************
if (testBegin("strCat(), strCatChr(), and strCatFmt()"))
if (testBegin("strCat*()"))
{
String *string = strNew("XXXX");
String *string2 = strNew("ZZZZ");
@@ -114,6 +119,10 @@ testRun(void)
strCatZN(string, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*", 55),
"XXXXYYYY00777!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "cat chr");
TEST_RESULT_UINT(string->extra, 34, "check extra");
TEST_RESULT_STR_Z(
strCatEncode(string, encodeBase64, BUFSTRDEF("zzzzz")),
"XXXXYYYY00777!$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$enp6eno=", "cat encode");
TEST_RESULT_UINT(string->extra, 26, "check extra");
TEST_RESULT_STR_Z(string2, "ZZZZ", "check unaltered string");
}

View File

@@ -73,9 +73,9 @@ testRequest(IoWrite *write, const char *verb, const char *path, TestRequestParam
// Add md5
if (param.content != NULL)
{
char md5Hash[HASH_TYPE_MD5_SIZE_HEX];
encodeToStr(encodeBase64, bufPtr(cryptoHashOne(HASH_TYPE_MD5_STR, BUFSTRZ(param.content))), HASH_TYPE_M5_SIZE, md5Hash);
strCatFmt(request, "content-md5:%s\r\n", md5Hash);
strCatFmt(
request, "content-md5:%s\r\n",
strZ(strNewEncode(encodeBase64, cryptoHashOne(HASH_TYPE_MD5_STR, BUFSTRZ(param.content)))));
}
// Add date
@@ -190,7 +190,8 @@ testRun(void)
TEST_RESULT_STR_Z(storage->path, "/repo", " check path");
TEST_RESULT_STR(((StorageAzure *)storage->driver)->account, TEST_ACCOUNT_STR, " check account");
TEST_RESULT_STR(((StorageAzure *)storage->driver)->container, TEST_CONTAINER_STR, " check container");
TEST_RESULT_STR(((StorageAzure *)storage->driver)->sharedKey, TEST_KEY_SHARED_STR, " check key");
TEST_RESULT_STR(
strNewEncode(encodeBase64, ((StorageAzure *)storage->driver)->sharedKey), TEST_KEY_SHARED_STR, " check key");
TEST_RESULT_STR_Z(((StorageAzure *)storage->driver)->host, TEST_ACCOUNT ".blob.core.windows.net", " check host");
TEST_RESULT_STR_Z(((StorageAzure *)storage->driver)->pathPrefix, "/" TEST_CONTAINER, " check path prefix");
TEST_RESULT_UINT(((StorageAzure *)storage->driver)->blockSize, STORAGE_AZURE_BLOCKSIZE_MIN, " check block size");

View File

@@ -78,9 +78,9 @@ testRequest(IoWrite *write, Storage *s3, const char *verb, const char *path, Tes
// Add md5
if (param.content != NULL)
{
char md5Hash[HASH_TYPE_MD5_SIZE_HEX];
encodeToStr(encodeBase64, bufPtr(cryptoHashOne(HASH_TYPE_MD5_STR, BUFSTRZ(param.content))), HASH_TYPE_M5_SIZE, md5Hash);
strCatFmt(request, "content-md5:%s\r\n", md5Hash);
strCatFmt(
request, "content-md5:%s\r\n",
strZ(strNewEncode(encodeBase64, cryptoHashOne(HASH_TYPE_MD5_STR, BUFSTRZ(param.content)))));
}
// Add host