From 93cc810f2987cc90b7a4f8699655af43b36c6c23 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 17 Mar 2025 09:06:11 -0400 Subject: [PATCH] use string/string_view for base64 --- libi2pd/Base.cpp | 184 ++++++++++++++++++++++++-------------- libi2pd/Base.h | 9 +- libi2pd/Family.cpp | 9 +- libi2pd/Identity.cpp | 32 +++---- libi2pd/Identity.h | 2 +- libi2pd/NetDb.cpp | 4 +- libi2pd/NetDbRequests.cpp | 4 +- libi2pd/RouterInfo.cpp | 12 ++- libi2pd/Tag.h | 6 +- 9 files changed, 142 insertions(+), 120 deletions(-) diff --git a/libi2pd/Base.cpp b/libi2pd/Base.cpp index dc331e3e..bce303a2 100644 --- a/libi2pd/Base.cpp +++ b/libi2pd/Base.cpp @@ -15,7 +15,7 @@ namespace i2p { namespace data { - static const char T32[32] = + static constexpr char T32[32] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', @@ -38,7 +38,7 @@ namespace data * Direct Substitution Table */ - static const char T64[64] = + static constexpr char T64[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', @@ -77,11 +77,11 @@ namespace data * */ - size_t ByteStreamToBase64 ( /* Number of bytes in the encoded buffer */ - const uint8_t * InBuffer, /* Input buffer, binary data */ - size_t InCount, /* Number of bytes in the input buffer */ - char * OutBuffer, /* output buffer */ - size_t len /* length of output buffer */ + size_t ByteStreamToBase64 ( // Number of bytes in the encoded buffer + const uint8_t * InBuffer, // Input buffer, binary data + size_t InCount, // Number of bytes in the input buffer + char * OutBuffer, // output buffer + size_t len // length of output buffer ) { unsigned char * ps; @@ -108,24 +108,24 @@ namespace data { acc_1 = *ps++; acc_2 = (acc_1 << 4) & 0x30; - acc_1 >>= 2; /* base64 digit #1 */ + acc_1 >>= 2; // base64 digit #1 *pd++ = T64[acc_1]; acc_1 = *ps++; - acc_2 |= acc_1 >> 4; /* base64 digit #2 */ + acc_2 |= acc_1 >> 4; // base64 digit #2 *pd++ = T64[acc_2]; acc_1 &= 0x0f; acc_1 <<= 2; acc_2 = *ps++; - acc_1 |= acc_2 >> 6; /* base64 digit #3 */ + acc_1 |= acc_2 >> 6; // base64 digit #3 *pd++ = T64[acc_1]; - acc_2 &= 0x3f; /* base64 digit #4 */ + acc_2 &= 0x3f; // base64 digit #4 *pd++ = T64[acc_2]; } if ( m == 1 ) { acc_1 = *ps++; - acc_2 = (acc_1 << 4) & 0x3f; /* base64 digit #2 */ - acc_1 >>= 2; /* base64 digit #1 */ + acc_2 = (acc_1 << 4) & 0x3f; // base64 digit #2 + acc_1 >>= 2; // base64 digit #1 *pd++ = T64[acc_1]; *pd++ = T64[acc_2]; *pd++ = P64; @@ -136,13 +136,13 @@ namespace data { acc_1 = *ps++; acc_2 = (acc_1 << 4) & 0x3f; - acc_1 >>= 2; /* base64 digit #1 */ + acc_1 >>= 2; // base64 digit #1 *pd++ = T64[acc_1]; acc_1 = *ps++; - acc_2 |= acc_1 >> 4; /* base64 digit #2 */ + acc_2 |= acc_1 >> 4; // base64 digit #2 *pd++ = T64[acc_2]; acc_1 &= 0x0f; - acc_1 <<= 2; /* base64 digit #3 */ + acc_1 <<= 2; // base64 digit #3 *pd++ = T64[acc_1]; *pd++ = P64; } @@ -150,60 +150,112 @@ namespace data return outCount; } - /* - * - * Base64ToByteStream - * ------------------ - * - * Converts BASE64 encoded data to binary format. If input buffer is - * not properly padded, buffer of negative length is returned - * - */ - - size_t Base64ToByteStream ( /* Number of output bytes */ - const char * InBuffer, /* BASE64 encoded buffer */ - size_t InCount, /* Number of input bytes */ - uint8_t * OutBuffer, /* output buffer length */ - size_t len /* length of output buffer */ + std::string ByteStreamToBase64 (// base64 encoded string + const uint8_t * InBuffer, // Input buffer, binary data + size_t InCount // Number of bytes in the input buffer ) { unsigned char * ps; - unsigned char * pd; unsigned char acc_1; unsigned char acc_2; int i; int n; int m; + + ps = (unsigned char *)InBuffer; + n = InCount / 3; + m = InCount % 3; + size_t outCount = m ? (4 * (n + 1)) : (4 * n); + + std::string out; + out.reserve (outCount); + for ( i = 0; i < n; i++ ) + { + acc_1 = *ps++; + acc_2 = (acc_1 << 4) & 0x30; + acc_1 >>= 2; // base64 digit #1 + out.push_back (T64[acc_1]); + acc_1 = *ps++; + acc_2 |= acc_1 >> 4; // base64 digit #2 + out.push_back (T64[acc_2]); + acc_1 &= 0x0f; + acc_1 <<= 2; + acc_2 = *ps++; + acc_1 |= acc_2 >> 6; // base64 digit #3 + out.push_back (T64[acc_1]); + acc_2 &= 0x3f; // base64 digit #4 + out.push_back (T64[acc_2]); + } + if ( m == 1 ) + { + acc_1 = *ps++; + acc_2 = (acc_1 << 4) & 0x3f; // base64 digit #2 + acc_1 >>= 2; // base64 digit #1 + out.push_back (T64[acc_1]); + out.push_back (T64[acc_2]); + out.push_back (P64); + out.push_back (P64); + + } + else if ( m == 2 ) + { + acc_1 = *ps++; + acc_2 = (acc_1 << 4) & 0x3f; + acc_1 >>= 2; // base64 digit #1 + out.push_back (T64[acc_1]); + acc_1 = *ps++; + acc_2 |= acc_1 >> 4; // base64 digit #2 + out.push_back (T64[acc_2]); + acc_1 &= 0x0f; + acc_1 <<= 2; // base64 digit #3 + out.push_back (T64[acc_1]); + out.push_back (P64); + } + + return out; + } + + /* + * + * Base64ToByteStream + * ------------------ + * + * Converts BASE64 encoded string to binary format. If input buffer is + * not properly padded, buffer of negative length is returned + * + */ + size_t Base64ToByteStream ( // Number of output bytes + std::string_view base64Str, // BASE64 encoded string + uint8_t * OutBuffer, // output buffer length + size_t len // length of output buffer + ) + { + unsigned char * pd; + unsigned char acc_1; + unsigned char acc_2; size_t outCount; - if (isFirstTime) - iT64Build(); - - n = InCount / 4; - m = InCount % 4; - - if (InCount && !m) - outCount = 3 * n; + if (base64Str.empty () || base64Str[0] == P64) return 0; + auto d = std::div (base64Str.length (), 4); + if (!d.rem) + outCount = 3 * d.quot; else return 0; - if(*InBuffer == P64) - return 0; - - ps = (unsigned char *)(InBuffer + InCount - 1); - while ( *ps-- == P64 ) - outCount--; - ps = (unsigned char *)InBuffer; - - if (outCount > len) - return 0; + if (isFirstTime) iT64Build(); + auto pos = base64Str.find_last_not_of (P64); + if (pos == base64Str.npos) return 0; + outCount -= (base64Str.length () - pos - 1); + if (outCount > len) return 0; + + auto ps = base64Str.begin (); pd = OutBuffer; auto endOfOutBuffer = OutBuffer + outCount; - for ( i = 0; i < n; i++ ) + for (int i = 0; i < d.quot; i++) { - acc_1 = iT64[*ps++]; - acc_2 = iT64[*ps++]; + acc_1 = iT64[int(*ps++)]; + acc_2 = iT64[int(*ps++)]; acc_1 <<= 2; acc_1 |= acc_2 >> 4; *pd++ = acc_1; @@ -211,36 +263,30 @@ namespace data break; acc_2 <<= 4; - acc_1 = iT64[*ps++]; + acc_1 = iT64[int(*ps++)]; acc_2 |= acc_1 >> 2; *pd++ = acc_2; if (pd >= endOfOutBuffer) break; - acc_2 = iT64[*ps++]; + acc_2 = iT64[int(*ps++)]; acc_2 |= acc_1 << 6; *pd++ = acc_2; } return outCount; - } + } std::string ToBase64Standard (std::string_view in) { - auto len = Base64EncodingBufferSize (in.length ()); - char * str = new char[len + 1]; - auto l = ByteStreamToBase64 ((const uint8_t *)in.data (), in.length (), str, len); - str[l] = 0; + auto str = ByteStreamToBase64 ((const uint8_t *)in.data (), in.length ()); // replace '-' by '+' and '~' by '/' - for (size_t i = 0; i < l; i++) - if (str[i] == '-') - str[i] = '+'; - else if (str[i] == '~') - str[i] = '/'; - - std::string s(str); - delete[] str; - return s; + for (auto& ch: str) + if (ch == '-') + ch = '+'; + else if (ch == '~') + ch = '/'; + return str; } /* diff --git a/libi2pd/Base.h b/libi2pd/Base.h index 3bdbe211..c14abac7 100644 --- a/libi2pd/Base.h +++ b/libi2pd/Base.h @@ -18,8 +18,10 @@ namespace i2p { namespace data { - size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len); - size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len ); + size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len); // called from SAM TODO: rewrite + std::string ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount); + size_t Base64ToByteStream (std::string_view base64Str, uint8_t * OutBuffer, size_t len); + const char * GetBase32SubstitutionTable (); const char * GetBase64SubstitutionTable (); constexpr bool IsBase64 (char ch) @@ -28,8 +30,7 @@ namespace data } size_t Base32ToByteStream (std::string_view base32Str, uint8_t * outBuf, size_t outLen); - std::string ByteStreamToBase32 (const uint8_t * inBuf, size_t len); - + std::string ByteStreamToBase32 (const uint8_t * inBuf, size_t len); constexpr bool IsBase32 (char ch) { return (ch >= 'a' && ch <= 'z') || (ch >= '2' && ch <= '7'); diff --git a/libi2pd/Family.cpp b/libi2pd/Family.cpp index f8cf9c0a..300a50ab 100644 --- a/libi2pd/Family.cpp +++ b/libi2pd/Family.cpp @@ -105,7 +105,7 @@ namespace data memcpy (buf, family.c_str (), len); memcpy (buf + len, (const uint8_t *)ident, 32); len += 32; - auto signatureBufLen = Base64ToByteStream (signature.data (), signature.length (), signatureBuf, 64); + auto signatureBufLen = Base64ToByteStream (signature, signatureBuf, 64); if (signatureBufLen) { EVP_MD_CTX * ctx = EVP_MD_CTX_create (); @@ -154,12 +154,7 @@ namespace data memcpy (buf + len, (const uint8_t *)ident, 32); len += 32; signer.Sign (buf, len, signature); - len = Base64EncodingBufferSize (64); - char * b64 = new char[len+1]; - len = ByteStreamToBase64 (signature, 64, b64, len); - b64[len] = 0; - sig = b64; - delete[] b64; + sig = ByteStreamToBase64 (signature, 64); } else LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 93d7ec08..e98e5fbc 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -271,21 +271,17 @@ namespace data size_t IdentityEx::FromBase64(std::string_view s) { - const size_t slen = s.length(); - std::vector buf(slen); // binary data can't exceed base64 - const size_t len = Base64ToByteStream (s.data(), slen, buf.data(), slen); + std::vector buf(s.length ()); // binary data can't exceed base64 + auto len = Base64ToByteStream (s, buf.data(), buf.size ()); return FromBuffer (buf.data(), len); } std::string IdentityEx::ToBase64 () const { const size_t bufLen = GetFullLen(); - const size_t strLen = Base64EncodingBufferSize(bufLen); std::vector buf(bufLen); - std::vector str(strLen); size_t l = ToBuffer (buf.data(), bufLen); - size_t l1 = i2p::data::ByteStreamToBase64 (buf.data(), l, str.data(), strLen); - return std::string (str.data(), l1); + return i2p::data::ByteStreamToBase64 (buf.data(), l); } size_t IdentityEx::GetSigningPublicKeyLen () const @@ -570,26 +566,18 @@ namespace data return ret; } - size_t PrivateKeys::FromBase64(const std::string& s) + size_t PrivateKeys::FromBase64(std::string_view s) { - uint8_t * buf = new uint8_t[s.length ()]; - size_t l = i2p::data::Base64ToByteStream (s.c_str (), s.length (), buf, s.length ()); - size_t ret = FromBuffer (buf, l); - delete[] buf; - return ret; + std::vector buf(s.length ()); + size_t l = i2p::data::Base64ToByteStream (s, buf.data (), buf.size ()); + return FromBuffer (buf.data (), l); } std::string PrivateKeys::ToBase64 () const { - uint8_t * buf = new uint8_t[GetFullLen ()]; - char * str = new char[GetFullLen ()*2]; - size_t l = ToBuffer (buf, GetFullLen ()); - size_t l1 = i2p::data::ByteStreamToBase64 (buf, l, str, GetFullLen ()*2); - str[l1] = 0; - delete[] buf; - std::string ret(str); - delete[] str; - return ret; + std::vector buf(GetFullLen ()); + size_t l = ToBuffer (buf.data (), buf.size ()); + return i2p::data::ByteStreamToBase64 (buf.data (), l); } void PrivateKeys::Sign (const uint8_t * buf, int len, uint8_t * signature) const diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index cf1dbfcd..e08ac802 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -164,7 +164,7 @@ namespace data size_t FromBuffer (const uint8_t * buf, size_t len); size_t ToBuffer (uint8_t * buf, size_t len) const; - size_t FromBase64(const std::string& s); + size_t FromBase64(std::string_view s); std::string ToBase64 () const; std::shared_ptr CreateDecryptor (const uint8_t * key) const; diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 7f6882c4..2bfaa8d8 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -951,9 +951,7 @@ namespace data LogPrint (eLogError, "NetDb: DatabaseLookup for zero ident. Ignored"); return; } - char key[48]; - int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48); - key[l] = 0; + auto key = i2p::data::ByteStreamToBase64 (buf, 32); IdentHash replyIdent(buf + 32); uint8_t flag = buf[64]; diff --git a/libi2pd/NetDbRequests.cpp b/libi2pd/NetDbRequests.cpp index f8c5037c..0648d6bf 100644 --- a/libi2pd/NetDbRequests.cpp +++ b/libi2pd/NetDbRequests.cpp @@ -360,9 +360,7 @@ namespace data void NetDbRequests::HandleDatabaseSearchReplyMsg (std::shared_ptr msg) { const uint8_t * buf = msg->GetPayload (); - char key[48]; - int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48); - key[l] = 0; + auto key = i2p::data::ByteStreamToBase64 (buf, 32); size_t num = buf[32]; // num LogPrint (eLogDebug, "NetDbReq: DatabaseSearchReply for ", key, " num=", num); IdentHash ident (buf); diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index f5ed27e6..41f71e14 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -281,7 +281,7 @@ namespace data address->caps = ExtractAddressCaps (value); else if (key == "s") // ntcp2 or ssu2 static key { - if (Base64ToByteStream (value.data (), value.length (), address->s, 32) == 32 && + if (Base64ToByteStream (value, address->s, 32) == 32 && !(address->s[31] & 0x80)) // check if x25519 public key isStaticKey = true; else @@ -291,14 +291,14 @@ namespace data { if (address->IsNTCP2 ()) { - if (Base64ToByteStream (value.data (), value.length (), address->i, 16) == 16) + if (Base64ToByteStream (value, address->i, 16) == 16) address->published = true; // presence of "i" means "published" NTCP2 else address->transportStyle = eTransportUnknown; // invalid address } else if (address->IsSSU2 ()) { - if (Base64ToByteStream (value.data (), value.length (), address->i, 32) == 32) + if (Base64ToByteStream (value, address->i, 32) == 32) isIntroKey = true; else address->transportStyle = eTransportUnknown; // invalid address @@ -343,7 +343,7 @@ namespace data LogPrint (eLogWarning, "RouterInfo: 'itag' conversion error: ", std::make_error_code (res.ec).message ()); } else if (key1 == "ih") - Base64ToByteStream (value.data (), value.length (), introducer.iH, 32); + Base64ToByteStream (value, introducer.iH, 32); else if (key1 == "iexp") { auto res = std::from_chars(value.data(), value.data() + value.size(), introducer.iExp); @@ -1394,9 +1394,7 @@ namespace data if (!introducer.iTag) continue; WriteString ("ih" + std::to_string(i), properties); properties << '='; - char value[64]; - size_t l = ByteStreamToBase64 (introducer.iH, 32, value, 64); - value[l] = 0; + auto value = ByteStreamToBase64 (introducer.iH, 32); WriteString (value, properties); properties << ';'; i++; diff --git a/libi2pd/Tag.h b/libi2pd/Tag.h index af2de154..30b7708d 100644 --- a/libi2pd/Tag.h +++ b/libi2pd/Tag.h @@ -62,9 +62,7 @@ namespace data std::string ToBase64 (size_t len = sz) const { - char str[sz*2]; - size_t l = i2p::data::ByteStreamToBase64 (m_Buf, len, str, sz*2); - return std::string (str, str + l); + return i2p::data::ByteStreamToBase64 (m_Buf, len); } std::string ToBase32 (size_t len = sz) const @@ -79,7 +77,7 @@ namespace data size_t FromBase64 (std::string_view s) { - return i2p::data::Base64ToByteStream (s.data (), s.length (), m_Buf, sz); + return i2p::data::Base64ToByteStream (s, m_Buf, sz); } uint8_t GetBit (int i) const