DecodeBase58(const std::string& str, …) is a bit too liberal when decoding? #17718

issue practicalswift opened this issue on December 10, 2019
  1. practicalswift commented at 11:21 PM on December 10, 2019: contributor

    When fuzzing the base58 functions I noticed that DecodeBase58(const std::string& str, …) is perhaps a bit too liberal in what input it accepts when decoding.

    I naïvely assumed that DecodeBase58(const std::string& str, …) would return false when passing it a str which contains at least one character that is not any of the base58 characters (all alphanumeric characters except for "0", "I", "O", and "l") or the whitespace characters.

    That is not the case:

    • str contains goodDecodeBase58(const std::string& str, …) == true (as expected)
    • str contains bad0IOlDecodeBase58(const std::string& str, …) == false (as expected)
    • str contains good\x00bad0IOlDecodeBase58(const std::string& str, …) == true(!)

    The reason is that DecodeBase58(const std::string& str, …) calls DecodeBase58(const char* psz, …) which will only consider the string up to the first \x00.

  2. practicalswift added the label Bug on Dec 10, 2019
  3. practicalswift commented at 10:39 AM on December 11, 2019: contributor

    The same applies also to DecodeBase58Check(const std::string& str, …), DecodeBase32(const std::string& str, …) and DecodeBase64(const std::string& str, …).

  4. practicalswift commented at 4:44 PM on December 11, 2019: contributor

    Also ParseMoney(const std::string&, …) and ParseHex(const std::string& …).

  5. practicalswift commented at 5:12 PM on December 11, 2019: contributor

    This is a list of functions that might be worth checking for potential problems introduced by "\0-stuffing".

    I'll take a look :)

    The candidate list was generated using git grep -E '(\(const std::string *&|[a-zA-Z0-9_]\(const (unsigned |)char *\*)' and then filtered manually.

    src/arith_uint256.cpp:template void base_uint<256>::SetHex(const char*);
    src/arith_uint256.cpp:template void base_uint<256>::SetHex(const std::string&);
    
    src/arith_uint256.cpp:void base_uint<BITS>::SetHex(const char* psz)
    src/arith_uint256.cpp:void base_uint<BITS>::SetHex(const std::string& str)
    
    src/base58.cpp:bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
    src/base58.cpp:bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
    
    src/base58.cpp:bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
    src/base58.cpp:bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
    
    src/uint256.cpp:template void base_blob<160>::SetHex(const char*);
    src/uint256.cpp:template void base_blob<160>::SetHex(const std::string&);
    
    src/uint256.cpp:template void base_blob<256>::SetHex(const char*);
    src/uint256.cpp:template void base_blob<256>::SetHex(const std::string&);
    
    src/uint256.cpp:void base_blob<BITS>::SetHex(const char* psz)
    src/uint256.cpp:void base_blob<BITS>::SetHex(const std::string& str)
    
    src/uint256.h:inline uint256 uint256S(const char *str)
    src/uint256.h:inline uint256 uint256S(const std::string& str)
    
    src/util/moneystr.cpp:bool ParseMoney(const char* pszIn, CAmount& nRet)
    src/util/moneystr.cpp:bool ParseMoney(const std::string& str, CAmount& nRet)
    
    src/util/strencodings.cpp:int64_t atoi64(const char* psz)
    src/util/strencodings.cpp:int64_t atoi64(const std::string& str)
    
    src/util/strencodings.cpp:std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid)
    src/util/strencodings.cpp:std::string DecodeBase32(const std::string& str, bool* pf_invalid)
    
    src/util/strencodings.cpp:std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid)
    src/util/strencodings.cpp:std::string DecodeBase64(const std::string& str, bool* pf_invalid)
    
    src/util/strencodings.cpp:std::string EncodeBase32(const unsigned char* pch, size_t len)
    src/util/strencodings.cpp:std::string EncodeBase32(const std::string& str)
    
    src/util/strencodings.cpp:std::string EncodeBase64(const unsigned char* pch, size_t len)
    src/util/strencodings.cpp:std::string EncodeBase64(const std::string& str)
    
    src/util/strencodings.cpp:std::vector<unsigned char> ParseHex(const char* psz)
    src/util/strencodings.cpp:std::vector<unsigned char> ParseHex(const std::string& str)
    
  6. laanwj commented at 10:10 AM on December 12, 2019: member

    The thing has always been that a lot of those don't even have a mechanism to report parse errors. Handling \0 would just be the icing on the cake so to say… (I had a similar idea in #17385 to get rid of some of these, but I think it's just too deep a rabbit hole)

  7. laanwj removed the label Bug on Dec 12, 2019
  8. laanwj added the label Utils/log/libs on Dec 12, 2019
  9. laanwj closed this on Dec 13, 2019

  10. sidhujag referenced this in commit db2f0b32fa on Dec 13, 2019
  11. sidhujag referenced this in commit b4bf670575 on Nov 10, 2020
  12. DrahtBot locked this on Dec 16, 2021

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-13 15:14 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me