How do I base64 encode (decode) in C?

后端 未结 17 1528
孤城傲影
孤城傲影 2020-11-22 06:27

I have binary data in an unsigned char variable. I need to convert them to PEM base64 in c. I looked in openssl library but i could not find any function. Does any body have

17条回答
  •  臣服心动
    2020-11-22 06:33

    Small improvement to the code from ryyst (who got the most votes) is to not use dynamically allocated decoding table but rather static const precomputed table. This eliminates the use of pointer and initialization of the table, and also avoids memory leakage if one forgets to clean up the decoding table with base64_cleanup() (by the way, in base64_cleanup(), after calling free(decoding_table), one should have decoding_table=NULL, otherwise accidentally calling base64_decode after base64_cleanup() will crash or cause undetermined behavior). Another solution could be to use std::unique_ptr...but I'm satisfied with just having const char[256] on the stack and avoid using pointers alltogether - the code looks cleaner and shorter this way.

    The decoding table is computed as follows:

    const char encoding_table[] = { 
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
        'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
        'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
        'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
        'w', 'x', 'y', 'z', '0', '1', '2', '3',
        '4', '5', '6', '7', '8', '9', '+', '/' };
    
    unsigned char decoding_table[256];
    
    for (int i = 0; i < 256; i++)
        decoding_table[i] = '\0';
    
    for (int i = 0; i < 64; i++)
        decoding_table[(unsigned char)encoding_table[i]] = i;
    
    for (int i = 0; i < 256; i++)
        cout << "0x" << (int(decoding_table[i]) < 16 ? "0" : "") << hex << int(decoding_table[i]) << (i != 255 ? "," : "") << ((i+1) % 16 == 0 ? '\n' : '\0');
    
    cin.ignore();
    

    and the modified code I am using is:

            static const char encoding_table[] = { 
                'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
                'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
                'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
                'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
                'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
                'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
                'w', 'x', 'y', 'z', '0', '1', '2', '3',
                '4', '5', '6', '7', '8', '9', '+', '/' };
    
            static const unsigned char decoding_table[256] = {
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3f,
                0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
                0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
                0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    
            char* base64_encode(const unsigned char *data, size_t input_length, size_t &output_length) {
    
                const int mod_table[] = { 0, 2, 1 };
    
                output_length = 4 * ((input_length + 2) / 3);
    
                char *encoded_data = (char*)malloc(output_length);
    
                if (encoded_data == nullptr)
                    return nullptr;
    
                for (int i = 0, j = 0; i < input_length;) {
    
                    uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
                    uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
                    uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
    
                    uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
    
                    encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
                    encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
                    encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
                    encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
    
                }
    
                for (int i = 0; i < mod_table[input_length % 3]; i++)
                    encoded_data[output_length - 1 - i] = '=';
    
                return encoded_data;
    
            };
    
            unsigned char* base64_decode(const char *data, size_t input_length, size_t &output_length) {        
    
                if (input_length % 4 != 0)
                    return nullptr;
    
                output_length = input_length / 4 * 3;
    
                if (data[input_length - 1] == '=') (output_length)--;
                if (data[input_length - 2] == '=') (output_length)--;
    
                unsigned char* decoded_data = (unsigned char*)malloc(output_length);
    
                if (decoded_data == nullptr)
                    return nullptr;
    
                for (int i = 0, j = 0; i < input_length;) {
    
                    uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
                    uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
                    uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
                    uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
    
                    uint32_t triple = (sextet_a << 3 * 6)
                        + (sextet_b << 2 * 6)
                        + (sextet_c << 1 * 6)
                        + (sextet_d << 0 * 6);
    
                    if (j < output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF;
                    if (j < output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF;
                    if (j < output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF;
    
                }
    
                return decoded_data;
    
            };
    

提交回复
热议问题