Thread: How do you convert a string to MIME base 64?

  1. #1
    Registered User HelpfulPerson's Avatar
    Join Date
    Jun 2013
    Location
    Over the rainbow
    Posts
    288

    How do you convert a string to MIME base 64?

    I've been trying to write some code to do what I mentioned in the title, but I haven't had much luck. I get very confused when I deal with bitwise operators, so it's hard for me to write this kind of encoding on my own. I need this encodement so I can login to an email account using smtp. I've been trying to use Base64 - Wikipedia, the free encyclopedia to help me figure out what I need to do, but I'm a bit confused on how exactly to go about it. The octet part is the main part that I don't really know how to do well. Here is my code so far :

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    
    
    #include <string.h>
    
    
    const char base64_table[] =
    {
        'A', 'B', 'C', 'D', 'E', 'F',
        'G', 'H', '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',
    
    
        '+', '-'
    };
    
    
    inline unsigned octet_to_base64( uint8_t octet )
    {
        return base64_table[octet];
    }
    
    
    char * string_to_base64( const char * orig_text )
    {
        int byte_offset;
    
    
        const int orig_text_sz = strlen( orig_text );
        const int new_text_sz = ( 4 * ( orig_text_sz / 3 ) ) + 1;
        char * new_text = malloc( new_text_sz );
    
    
        char * temp = ( char * )orig_text;
    
    
        uint32_t octets = 0;
    
    
        for ( byte_offset = 0; byte_offset < new_text_sz - 1; byte_offset++ )
        {
            if ( !( byte_offset % 3 ) )
                if ( ( temp - orig_text ) < orig_text_sz )
                    for ( octets = 0; ( temp - orig_text ) < orig_text_sz; ++temp )
                        octets += *temp;
    
    
            printf( "%X\n", octets );
            printf( "byte offset %d, new_text_sz = %d\n", byte_offset, new_text_sz );
    
    
            new_text[byte_offset] = octet_to_base64( ( octets & ( 0x3F000000 >> ( ( byte_offset % 3 ) * 8 ) ) ) );
    
    
        }
    
    
        new_text[byte_offset] = '\0';
    
    
        return new_text;
    }
    
    
    int main( )
    {
        char * encrypted_string = NULL;
    
    
        printf( "%s", ( encrypted_string = string_to_base64( "Man" ) ) );
    
    
        free( encrypted_string );
    
    
        return 0;
    }
    Gives the output :

    Code:
    11C
    byte offset 0, new_text_sz = 5
    11C
    byte offset 1, new_text_sz = 5
    11C
    byte offset 2, new_text_sz = 5
    11C
    byte offset 3, new_text_sz = 5
    AAAA
    When according to wikipedia, it should be :
    T W F u
    "Some people think they can outsmart me, maybe. Maybe. I've yet to meet one that can outsmart bullet" - Meet the Heavy, Team Fortress 2

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    You can't turn an octet into a single base64 character. The whole point of base64 is you take your stream of binary and break it up into groups of 6, not 8.

  3. #3
    Registered User HelpfulPerson's Avatar
    Join Date
    Jun 2013
    Location
    Over the rainbow
    Posts
    288
    Quote Originally Posted by tabstop View Post
    You can't turn an octet into a single base64 character. The whole point of base64 is you take your stream of binary and break it up into groups of 6, not 8.
    Oops, I should've labeled it sixtet. 0x3f is actually 0b00111111, I just mislabeled it.

    Edit : And on that note, it should be FC and be bitshifted over 6 instead of 8.
    Last edited by HelpfulPerson; 12-01-2013 at 01:42 PM.
    "Some people think they can outsmart me, maybe. Maybe. I've yet to meet one that can outsmart bullet" - Meet the Heavy, Team Fortress 2

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Just because:
    Code:
    void turn_three_characters_into_base64(char *in[], char *out[]) {
        /* Assuming three characters available in the in char pointer, and out has at least four characters (five if you want to make the last one \0) */
        int val = in[0] >> 2;
        out[0] = base64_table[val];
        val = ((in[0]%4) << 4) + (in[1] >> 4);
        out[1] = base64_table[val];
        val = ((in[1]%16) << 4) + (in[2] >> 6);
        out[2] = base64_table[val];
        val = in[2]%64;
        out[3] = base64_table[val];
    }
    Note: this was typed directly into the box here and not tested in any way. But I'm feeling lucky.
    Last edited by tabstop; 12-01-2013 at 01:46 PM. Reason: I definitely remember typing "int val" -- wonder where it went.

  5. #5
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    And you're missing capital 'I' from your table! Also, the last character is a slash (not a dash) in the wikipedia table.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  6. #6
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    I would do it something like this.
    Code:
    char *string_to_base64(const char * orig_text) {
        size_t orig_text_sz = strlen(orig_text);
        char *new_text = malloc((orig_text_sz + 2) / 3 * 4 + 1);
        size_t oi, ni = 0; // original text index, new text index
    
        for (oi = 0; oi < orig_text_sz; ++oi) {
            unsigned char a = orig_text[oi];
            unsigned char b = (++oi < orig_text_sz) ? orig_text[oi] : '\0';
            unsigned char c = (++oi < orig_text_sz) ? orig_text[oi] : '\0';
            new_text[ni++] = base64_table[a >> 2];
            new_text[ni++] = base64_table[((a & 0x03) << 4) | ((b & 0xf0) >> 4)];
            new_text[ni++] = b ? base64_table[((b & 0x0f) << 2) | ((c & 0xc0) >> 6)] : '=';
            new_text[ni++] = c ? base64_table[c & 0x3f] : '=';
        }
        new_text[ni] = '\0';
    
        return new_text;
    }
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  7. #7
    Registered User HelpfulPerson's Avatar
    Join Date
    Jun 2013
    Location
    Over the rainbow
    Posts
    288
    Quote Originally Posted by tabstop View Post
    Just because:
    Code:
    void turn_three_characters_into_base64(char *in[], char *out[]) {
        /* Assuming three characters available in the in char pointer, and out has at least four characters (five if you want to make the last one \0) */
        int val = in[0] >> 2;
        out[0] = base64_table[val];
        val = ((in[0]%4) << 4) + (in[1] >> 4);
        out[1] = base64_table[val];
        val = ((in[1]%16) << 4) + (in[2] >> 6);
        out[2] = base64_table[val];
        val = in[2]%64;
        out[3] = base64_table[val];
    }
    Note: this was typed directly into the box here and not tested in any way. But I'm feeling lucky.
    Well, the output value was correct( Again, basing from wikipedia ), except for the third character.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    
    
    #include <string.h>
    
    
    const char base64_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',
    
    
        '+', '/'
    };
    
    
    inline unsigned sixtet_to_base64( uint8_t sixtet )
    {
        return base64_table[sixtet];
    }
    
    
    void turn_three_characters_into_base64( const char in[] , char out[] )
    {
        int val = in[0] >> 2;
    
    
        out[0] = base64_table[val];
        val = ( ( in[0] % 4 ) << 4 ) + ( in[1] >> 4 );
        out[1] = base64_table[val];
        val = ( ( in[1] % 16 ) << 4 ) + ( in[2] >> 6 );
        out[2] = base64_table[val];
        val = in[2] % 64;
        out[3] = base64_table[val];
    
    
        return;
    }
    
    
    char * string_to_base64( const char * orig_text )
    {
        const int orig_text_sz = strlen( orig_text );
        const int new_text_sz = ( 4 * ( orig_text_sz / 3 ) ) + 1;
        char * new_text = malloc( new_text_sz );
    
    
        turn_three_characters_into_base64( orig_text, new_text );
    
    
        new_text[4] = '\0';
    
    
        return new_text;
    }
    
    
    int main( )
    {
        char * encrypted_string = NULL;
    
    
        printf( "%s", ( encrypted_string = string_to_base64( "Man" ) ) );
    
    
        free( encrypted_string );
    
    
        return 0;
    }
    Output : TWRu

    Besides that, you made a mistake. You declared your parameters as type int ** instead of a plain int *.
    "Some people think they can outsmart me, maybe. Maybe. I've yet to meet one that can outsmart bullet" - Meet the Heavy, Team Fortress 2

  8. #8
    Registered User
    Join Date
    Nov 2012
    Posts
    1,393
    After you've got your implementation, you might also want to check for third-party libraries with these functions. For networking I think the best is the Apache Portable Runtime, which has base64 encode and decode:

    Apache Portable Runtime Utility Library: Base64 Encoding

    It has other useful functions for dealing with this domain

  9. #9
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Yep, line 7 (in my post) should have been shifted two, not four. And I'm hanging my head in shame for not taking out the pointers when I added the arrays to the parameters.

  10. #10
    Registered User HelpfulPerson's Avatar
    Join Date
    Jun 2013
    Location
    Over the rainbow
    Posts
    288
    Quote Originally Posted by oogabooga View Post
    I would do it something like this.
    Code:
    char *string_to_base64(const char * orig_text) {
        size_t orig_text_sz = strlen(orig_text);
        char *new_text = malloc((orig_text_sz + 2) / 3 * 4 + 1);
        size_t oi, ni = 0; // original text index, new text index
    
        for (oi = 0; oi < orig_text_sz; ++oi) {
            unsigned char a = orig_text[oi];
            unsigned char b = (++oi < orig_text_sz) ? orig_text[oi] : '\0';
            unsigned char c = (++oi < orig_text_sz) ? orig_text[oi] : '\0';
            new_text[ni++] = base64_table[a >> 2];
            new_text[ni++] = base64_table[((a & 0x03) << 4) | ((b & 0xf0) >> 4)];
            new_text[ni++] = b ? base64_table[((b & 0x0f) << 2) | ((c & 0xc0) >> 6)] : '=';
            new_text[ni++] = c ? base64_table[c & 0x3f] : '=';
        }
        new_text[ni] = '\0';
    
        return new_text;
    }
    Thanks, that works.
    "Some people think they can outsmart me, maybe. Maybe. I've yet to meet one that can outsmart bullet" - Meet the Heavy, Team Fortress 2

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. IIS 7.5 forgets custom MIME types
    By Elkvis in forum Tech Board
    Replies: 0
    Last Post: 03-18-2013, 11:36 AM
  2. Replies: 40
    Last Post: 06-03-2010, 12:45 PM
  3. Replies: 5
    Last Post: 05-09-2010, 10:58 AM
  4. mime type detection
    By Nyda in forum Linux Programming
    Replies: 3
    Last Post: 08-19-2009, 05:33 PM
  5. best way to base condition on string
    By Kinasz in forum C Programming
    Replies: 6
    Last Post: 07-26-2004, 05:12 PM