C++ 中的 base32 转换

发布于 2024-08-14 12:19:45 字数 70 浏览 6 评论 0原文

有谁知道任何常用的 C++ 库提供了从 10 基数到 32 基数的编码和解码方法,反之亦然?

谢谢, 斯特凡诺

does anybody know any commonly used library for C++ that provides methods for encoding and decoding numbers from base 10 to base 32 and viceversa?

Thanks,
Stefano

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

路还长,别太狂 2024-08-21 12:19:45

[已更新]显然,C++ std::setbase() IO 操纵器和普通 <<>> IO 运算符仅处理基数 8、10 和 16,并且因此对于处理基数 32 是无用的。

因此,为了解决

  • 将从某些输入读取的数字的基数 10/32 表示形式的字符串转换为程序中的整数的
  • 问题,将程序中的整数转换为要输出的基数 10/32 表示形式的字符串,

您将需要借助其他功能。

要将包含基本 2..36 表示形式的 C 样式字符串转换为整数,您可以使用 #include 并使用 strtol(3) &有限公司的功能集。

至于将整数转换为具有任意基数的字符串......我找不到一个简单的答案。 printf(3) 样式格式字符串仅处理基数 8、10、16 AFAICS,就像 std::setbase 一样。有人吗?

[Updated] Apparently, the C++ std::setbase() IO manipulator and normal << and >> IO operators only handle bases 8, 10, and 16, and is therefore useless for handling base 32.

So to solve your issue of converting

  • strings with base 10/32 representation of numbers read from some input to integers in the program
  • integers in the program to strings with base 10/32 representations to be output

you will need to resort to other functions.

For converting C style strings containing base 2..36 representations to integers, you can use #include <cstdlib> and use the strtol(3) & Co. set of functions.

As for converting integers to strings with arbitrary base... I cannot find an easy answer. printf(3) style format strings only handle bases 8,10,16 AFAICS, just like std::setbase. Anyone?

无敌元气妹 2024-08-21 12:19:45

您的意思是“基数 10 到基数 32”,而不是整数到基数 32?后者似乎更有可能,也更有用。默认情况下,标准格式的 I/O 函数在处理整数时会生成以 10 为基数的字符串格式。

对于从 32 进制到整数的转换,标准库 strtol() 函数将执行此操作。反过来,您不需要一个库来实现自己可以轻松实现的东西(并非所有东西都是乐高积木)。

这是一个例子,不一定是最有效的,但很简单;

#include <cstring>
#include <string>

long b32tol( std::string b32 )
{
    return strtol( b32.c_str(), 0, 32 ) ;
}

std::string itob32( long i )
{
    unsigned long u = *(reinterpret_cast<unsigned long*>)( &i ) ;
    std::string b32 ;

    do
    {
        int d = u % 32 ;
        if( d < 10 )
        {
            b32.insert( 0, 1, '0' + d ) ;
        }
        else
        {
            b32.insert( 0, 1, 'a' + d - 10 ) ;
        }

        u /= 32 ;

    } while( u > 0 );

    return b32 ;
}


#include <iostream>

int main() 
{ 
    long i = 32*32*11 + 32*20 + 5 ; // BK5 in base 32
    std::string b32 = itob32( i ) ;
    long ii = b32tol( b32 ) ;

    std::cout << i << std::endl ;    // Original
    std::cout << b32 << std::endl ;  // Converted to b32
    std::cout << ii << std::endl ;   // Converted back

    return 0 ;
}

Did you mean "base 10 to base 32", rather than integer to base32? The latter seems more likely and more useful; by default standard formatted I/O functions generate base 10 string format when dealing with integers.

For the base 32 to integer conversion the standard library strtol() function will do that. For the reciprocal, you don't need a library for something you can easily implement yourself (not everything is a lego brick).

Here's an example, not necessarily the most efficient, but simple;

#include <cstring>
#include <string>

long b32tol( std::string b32 )
{
    return strtol( b32.c_str(), 0, 32 ) ;
}

std::string itob32( long i )
{
    unsigned long u = *(reinterpret_cast<unsigned long*>)( &i ) ;
    std::string b32 ;

    do
    {
        int d = u % 32 ;
        if( d < 10 )
        {
            b32.insert( 0, 1, '0' + d ) ;
        }
        else
        {
            b32.insert( 0, 1, 'a' + d - 10 ) ;
        }

        u /= 32 ;

    } while( u > 0 );

    return b32 ;
}


#include <iostream>

int main() 
{ 
    long i = 32*32*11 + 32*20 + 5 ; // BK5 in base 32
    std::string b32 = itob32( i ) ;
    long ii = b32tol( b32 ) ;

    std::cout << i << std::endl ;    // Original
    std::cout << b32 << std::endl ;  // Converted to b32
    std::cout << ii << std::endl ;   // Converted back

    return 0 ;
}
熟人话多 2024-08-21 12:19:45

在直接回答原来的(现在是旧的)问题时,我不知道有任何通用库用于以 Base32 编码字节数组,或随后再次解码它们。然而,上周我需要将以 Base32 表示的 SHA1 哈希值解码为其原始字节数组。这是我编写的一些 C++ 代码(带有一些值得注意的 Windows/小端工件),用于执行此操作并验证结果。

请注意,与上面的 Clifford 代码相反,如果我没有记错的话,它假定 RFC 4648 中提到的“base32hex”字母表,而我的代码则假定“base32”字母表(“AZ”和“2-7”)。

// This program illustrates how SHA1 hash values in base32 encoded form can be decoded
// and then re-encoded in base16.

#include "stdafx.h"
#include <string>
#include <vector>
#include <iostream>
#include <cassert>

using namespace std;

unsigned char Base16EncodeNibble( unsigned char value )
{
    if( value >= 0 && value <= 9 )
        return value + 48;
    else if( value >= 10 && value <= 15 )
        return (value-10) + 65;
    else //assert(false);
    {
        cout << "Error: trying to convert value: " << value << endl;
    }

    return 42; // sentinal for error condition
}

void Base32DecodeBase16Encode(const string & input, string & output)
{
    // Here's the base32 decoding:

        // The "Base 32 Encoding" section of http://tools.ietf.org/html/rfc4648#page-8
        // shows that every 8 bytes of base32 encoded data must be translated back into 5 bytes
        // of original data during a decoding process. The following code does this.

    int input_len = input.length();
    assert( input_len == 32 );
    const char * input_str = input.c_str();
    int output_len = (input_len*5)/8;
    assert( output_len == 20 );
        // Because input strings are assumed to be SHA1 hash values in base32, it is also assumed
        // that they will be 32 characters (and bytes in this case) in length, and so the output
        // string should be 20 bytes in length.
    unsigned char *output_str = new unsigned char[output_len];

    char curr_char, temp_char;
    long long temp_buffer = 0; //formerly: __int64 temp_buffer = 0;
    for( int i=0; i<input_len; i++ )
    {
        curr_char = input_str[i];
        if( curr_char >= 'A' && curr_char <= 'Z' )
            temp_char = curr_char - 'A';
        if( curr_char >= '2' && curr_char <= '7' )
            temp_char = curr_char - '2' + 26;

        if( temp_buffer )
            temp_buffer <<= 5; //temp_buffer = (temp_buffer << 5);
        temp_buffer |= temp_char;

        // if 8 encoded characters have been decoded into the temp location,
            // then copy them to the appropriate section of the final decoded location
        if( (i>0) && !((i+1) % 8) )
        {
            unsigned char * source = reinterpret_cast<unsigned char*>(&temp_buffer);
            //strncpy(output_str+(5*(((i+1)/8)-1)), source, 5);
            int start_index = 5*(((i+1)/8)-1);
            int copy_index = 4;
            for( int x=start_index; x<(start_index+5); x++, copy_index-- )
                output_str[x] = source[copy_index];
            temp_buffer = 0;

            // I could be mistaken, but I'm guessing that the necessity of copying
            // in "reverse" order results from temp_buffer's little endian byte order.
        }
    }

    // Here's the base16 encoding (for human-readable output and the chosen validation tests):

        // The "Base 16 Encoding" section of http://tools.ietf.org/html/rfc4648#page-10
        // shows that every byte original data must be encoded as two characters from the
        // base16 alphabet - one charactor for the original byte's high nibble, and one for
        // its low nibble.

    unsigned char out_temp, chr_temp;
    for( int y=0; y<output_len; y++ )
    {
        out_temp = Base16EncodeNibble( output_str[y] >> 4 ); //encode the high nibble
        output.append( 1, static_cast<char>(out_temp) );
        out_temp = Base16EncodeNibble( output_str[y] & 0xF ); //encode the low nibble
        output.append( 1, static_cast<char>(out_temp) );
    }

    delete [] output_str;
}

int _tmain(int argc, _TCHAR* argv[])
{
    //string input = "J3WEDSJDRMJHE2FUHERUR6YWLGE3USRH";
    vector<string> input_b32_strings, output_b16_strings, expected_b16_strings;

    input_b32_strings.push_back("J3WEDSJDRMJHE2FUHERUR6YWLGE3USRH");
    expected_b16_strings.push_back("4EEC41C9238B127268B4392348FB165989BA4A27");
    input_b32_strings.push_back("2HPUCIVW2EVBANIWCXOIQZX6N5NDIUSX");
    expected_b16_strings.push_back("D1DF4122B6D12A10351615DC8866FE6F5A345257");
    input_b32_strings.push_back("U4BDNCBAQFCPVDBL4FBG3AANGWVESI5J");
    expected_b16_strings.push_back("A7023688208144FA8C2BE1426D800D35AA4923A9");

    // Use the base conversion tool at http://darkfader.net/toolbox/convert/
    // to verify that the above base32/base16 pairs are equivalent.

    int num_input_strs = input_b32_strings.size();
    for(int i=0; i<num_input_strs; i++)
    {
        string temp;
        Base32DecodeBase16Encode(input_b32_strings[i], temp);
        output_b16_strings.push_back(temp);
    }

    for(int j=0; j<num_input_strs; j++)
    {
        cout << input_b32_strings[j] << endl;
        cout << output_b16_strings[j] << endl;
        cout << expected_b16_strings[j] << endl;

        if( output_b16_strings[j] != expected_b16_strings[j] )
        {
            cout << "Error in conversion for string " << j << endl;
        }
    }

    return 0;
}

In direct answer to the original (and now old) question, I don't know of any common library for encoding byte arrays in base32, or for decoding them again afterward. However, I was presented last week with a need to decode SHA1 hash values represented in base32 into their original byte arrays. Here's some C++ code (with some notable Windows/little endian artifacts) that I wrote to do just that, and to verify the results.

Note that in contrast with Clifford's code above, which, if I'm not mistaken, assumes the "base32hex" alphabet mentioned on RFC 4648, my code assumes the "base32" alphabet ("A-Z" and "2-7").

// This program illustrates how SHA1 hash values in base32 encoded form can be decoded
// and then re-encoded in base16.

#include "stdafx.h"
#include <string>
#include <vector>
#include <iostream>
#include <cassert>

using namespace std;

unsigned char Base16EncodeNibble( unsigned char value )
{
    if( value >= 0 && value <= 9 )
        return value + 48;
    else if( value >= 10 && value <= 15 )
        return (value-10) + 65;
    else //assert(false);
    {
        cout << "Error: trying to convert value: " << value << endl;
    }

    return 42; // sentinal for error condition
}

void Base32DecodeBase16Encode(const string & input, string & output)
{
    // Here's the base32 decoding:

        // The "Base 32 Encoding" section of http://tools.ietf.org/html/rfc4648#page-8
        // shows that every 8 bytes of base32 encoded data must be translated back into 5 bytes
        // of original data during a decoding process. The following code does this.

    int input_len = input.length();
    assert( input_len == 32 );
    const char * input_str = input.c_str();
    int output_len = (input_len*5)/8;
    assert( output_len == 20 );
        // Because input strings are assumed to be SHA1 hash values in base32, it is also assumed
        // that they will be 32 characters (and bytes in this case) in length, and so the output
        // string should be 20 bytes in length.
    unsigned char *output_str = new unsigned char[output_len];

    char curr_char, temp_char;
    long long temp_buffer = 0; //formerly: __int64 temp_buffer = 0;
    for( int i=0; i<input_len; i++ )
    {
        curr_char = input_str[i];
        if( curr_char >= 'A' && curr_char <= 'Z' )
            temp_char = curr_char - 'A';
        if( curr_char >= '2' && curr_char <= '7' )
            temp_char = curr_char - '2' + 26;

        if( temp_buffer )
            temp_buffer <<= 5; //temp_buffer = (temp_buffer << 5);
        temp_buffer |= temp_char;

        // if 8 encoded characters have been decoded into the temp location,
            // then copy them to the appropriate section of the final decoded location
        if( (i>0) && !((i+1) % 8) )
        {
            unsigned char * source = reinterpret_cast<unsigned char*>(&temp_buffer);
            //strncpy(output_str+(5*(((i+1)/8)-1)), source, 5);
            int start_index = 5*(((i+1)/8)-1);
            int copy_index = 4;
            for( int x=start_index; x<(start_index+5); x++, copy_index-- )
                output_str[x] = source[copy_index];
            temp_buffer = 0;

            // I could be mistaken, but I'm guessing that the necessity of copying
            // in "reverse" order results from temp_buffer's little endian byte order.
        }
    }

    // Here's the base16 encoding (for human-readable output and the chosen validation tests):

        // The "Base 16 Encoding" section of http://tools.ietf.org/html/rfc4648#page-10
        // shows that every byte original data must be encoded as two characters from the
        // base16 alphabet - one charactor for the original byte's high nibble, and one for
        // its low nibble.

    unsigned char out_temp, chr_temp;
    for( int y=0; y<output_len; y++ )
    {
        out_temp = Base16EncodeNibble( output_str[y] >> 4 ); //encode the high nibble
        output.append( 1, static_cast<char>(out_temp) );
        out_temp = Base16EncodeNibble( output_str[y] & 0xF ); //encode the low nibble
        output.append( 1, static_cast<char>(out_temp) );
    }

    delete [] output_str;
}

int _tmain(int argc, _TCHAR* argv[])
{
    //string input = "J3WEDSJDRMJHE2FUHERUR6YWLGE3USRH";
    vector<string> input_b32_strings, output_b16_strings, expected_b16_strings;

    input_b32_strings.push_back("J3WEDSJDRMJHE2FUHERUR6YWLGE3USRH");
    expected_b16_strings.push_back("4EEC41C9238B127268B4392348FB165989BA4A27");
    input_b32_strings.push_back("2HPUCIVW2EVBANIWCXOIQZX6N5NDIUSX");
    expected_b16_strings.push_back("D1DF4122B6D12A10351615DC8866FE6F5A345257");
    input_b32_strings.push_back("U4BDNCBAQFCPVDBL4FBG3AANGWVESI5J");
    expected_b16_strings.push_back("A7023688208144FA8C2BE1426D800D35AA4923A9");

    // Use the base conversion tool at http://darkfader.net/toolbox/convert/
    // to verify that the above base32/base16 pairs are equivalent.

    int num_input_strs = input_b32_strings.size();
    for(int i=0; i<num_input_strs; i++)
    {
        string temp;
        Base32DecodeBase16Encode(input_b32_strings[i], temp);
        output_b16_strings.push_back(temp);
    }

    for(int j=0; j<num_input_strs; j++)
    {
        cout << input_b32_strings[j] << endl;
        cout << output_b16_strings[j] << endl;
        cout << expected_b16_strings[j] << endl;

        if( output_b16_strings[j] != expected_b16_strings[j] )
        {
            cout << "Error in conversion for string " << j << endl;
        }
    }

    return 0;
}
风铃鹿 2024-08-21 12:19:45

我不知道有任何专门用于 Base32 编码的常用库,但 Crypto++ 包含 公共域 Base32 编码器和解码器

I'm not aware of any commonly-used library devoted to base32 encoding but Crypto++ includes a public domain base32 encoder and decoder.

会发光的星星闪亮亮i 2024-08-21 12:19:45

我不使用cpp,所以如果我错了,请纠正我。我编写这段代码是为了将其从 C# 翻译过来,以免给我的熟人带来麻烦。我用来创建这些方法的原始来源位于 stackoverflow 上的另一篇文章中:

虽这么说,这是我的解决方案:

#include <iostream>
#include <math.h>

class Base32 {
    public:
        static std::string dict;
        static std::string encode(int number) {
            std::string result = "";
            bool negative = false;
            if (number < 0) {
                negative = true;
            }

            number = abs(number);
            do {
                result = Base32::dict[fmod(floor(number), 32)] + result;
                number /= 32;
            } while(number > 0);

            if (negative) {
                result = "-" + result;
            }
    
            return result;
        }

        static int decode(std::string str) {
            int result = 0;
            int negative = 1;
            if (str.rfind("-", 0) == 0) {
                negative = -1;
                str = str.substr(1);
            }

            for(char& letter : str) {
                result += Base32::dict.find(letter);
                result *= 32;
            }

            return result / 32 * negative;
        }
};

std::string Base32::dict = "0123456789abcdefghijklmnopqrstuvwxyz";

int main() {
    std::cout << Base32::encode(0) + "\n" << Base32::decode(Base32::encode(0)) << "\n";

    return 0;
}

I don't use cpp, so correct me if I'm wrong. I wrote this code for the sake of translating it from C# to save my acquaintance the trouble. The original source, that which I used to create these methods, is on a different post, here, on stackoverflow:
https://stackoverflow.com/a/10981113/13766753

That being said, here's my solution:

#include <iostream>
#include <math.h>

class Base32 {
    public:
        static std::string dict;
        static std::string encode(int number) {
            std::string result = "";
            bool negative = false;
            if (number < 0) {
                negative = true;
            }

            number = abs(number);
            do {
                result = Base32::dict[fmod(floor(number), 32)] + result;
                number /= 32;
            } while(number > 0);

            if (negative) {
                result = "-" + result;
            }
    
            return result;
        }

        static int decode(std::string str) {
            int result = 0;
            int negative = 1;
            if (str.rfind("-", 0) == 0) {
                negative = -1;
                str = str.substr(1);
            }

            for(char& letter : str) {
                result += Base32::dict.find(letter);
                result *= 32;
            }

            return result / 32 * negative;
        }
};

std::string Base32::dict = "0123456789abcdefghijklmnopqrstuvwxyz";

int main() {
    std::cout << Base32::encode(0) + "\n" << Base32::decode(Base32::encode(0)) << "\n";

    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文