与字节无关的base64_encode / decode函数

时间:2017-06-26 07:29:52

标签: c endianness

我正在谷歌搜索我碰巧需要的这两个C函数,而我遇到的最干净的是http://fm4dd.com/programming/base64/base64_stringencode_c.htm但它在我看来就像它的下面一小部分......

void decodeblock(unsigned char in[], char *clrstr) {
  unsigned char out[4];
  out[0] = in[0] << 2 | in[1] >> 4;
  out[1] = in[1] << 4 | in[2] >> 2;
  out[2] = in[2] << 6 | in[3] >> 0;
  out[3] = '\0';
  strncat(clrstr, out, sizeof(out));
}

...将依赖于字节序(与您在上面的url中可以看到的相应的encodeblack()相同)。但它不是很干净,不像其他一些:一个有三个自己的头文件,另一个叫它自己的特殊malloc() - 就像函数一样。等任何人都知道一个漂亮,小巧,干净(没有标题,没有依赖关系等版本,就像这个版本一样,它更独立于架构?

编辑原因我正在寻找这个原因是base64_encode()将在一个PHP脚本中完成,该脚本是html页面的一部分,将该编码的字符串传递给已执行的远程盒子上的cgi程序。那cgi然后必须base64_decode()它。所以架构独立性只是一个额外的安全性,以防cgi在非英特尔大端盒子上运行(英特尔的小)。

根据下面的评论

修改,这里是完整的代码以及我做的一些更改...

/* downloaded from...
   http://fm4dd.com/programming/base64/base64_stringencode_c.htm */
/* ------------------------------------------------------------------------ *
 * file:        base64_stringencode.c v1.0                                  *
 * purpose:     tests encoding/decoding strings with base64                 *
 * author:      02/23/2009 Frank4DD                                         *
 *                                                                          *
 * source:      http://base64.sourceforge.net/b64.c for encoding            *
 *              http://en.literateprograms.org/Base64_(C) for decoding      *
 * ------------------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* ---- Base64 Encoding/Decoding Table --- */
char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

/* decodeblock - decode 4 '6-bit' characters into 3 8-bit binary bytes */
void decodeblock(unsigned char in[], char *clrstr) {
  unsigned char out[4];
  out[0] = in[0] << 2 | in[1] >> 4;
  out[1] = in[1] << 4 | in[2] >> 2;
  out[2] = in[2] << 6 | in[3] >> 0;
  out[3] = '\0';
  strncat(clrstr, out, sizeof(out));
  } /* --- end-of-function decodeblock() --- */

char *base64_decode(char *b64src /*, char *clrdst */) {
  static char clrdstbuff[8192];
         char *clrdst = clrdstbuff;
  int c, phase, i;
  unsigned char in[4];
  char *p;

  clrdst[0] = '\0';
  phase = 0; i=0;
  while(b64src[i]) {
    c = (int) b64src[i];
    if(c == '=') {
      decodeblock(in, clrdst); 
      break; }
    p = strchr(b64, c);
    if(p) {
      in[phase] = p - b64;
      phase = (phase + 1) % 4;
      if(phase == 0) {
        decodeblock(in, clrdst);
        in[0]=in[1]=in[2]=in[3]=0; }
      } /* --- end-of-if(p) --- */
    i++;
    } /* --- end-of-while(b64src[i]) --- */
  return ( clrdstbuff );
  } /* --- end-of-function base64_decode() --- */

/* encodeblock - encode 3 8-bit binary bytes as 4 '6-bit' characters */
void encodeblock( unsigned char in[], char b64str[], int len ) {
  unsigned char out[5];
  out[0] = b64[ in[0] >> 2 ];
  out[1] = b64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
  out[2] = (unsigned char) (len > 1 ? b64[ ((in[1] & 0x0f) << 2) |
           ((in[2] & 0xc0) >> 6) ] : '=');
  out[3] = (unsigned char) (len > 2 ? b64[ in[2] & 0x3f ] : '=');
  out[4] = '\0';
  strncat(b64str, out, sizeof(out));
  } /* --- end-of-function encodeblock() --- */

/* encode - base64 encode a stream, adding padding if needed */
char *base64_encode(char *clrstr /*, char *b64dst */) {
  static char b64dstbuff[8192];
         char *b64dst = b64dstbuff;
  unsigned char in[3];
  int i, len = 0;
  int j = 0;

  b64dst[0] = '\0';
  while(clrstr[j]) {
    len = 0;
    for(i=0; i<3; i++) {
      in[i] = (unsigned char) clrstr[j];
      if(clrstr[j]) {
        len++; j++;   }
      else in[i] = 0;
      } /* --- end-of-for(i) --- */
    if( len ) {
      encodeblock( in, b64dst, len );  }
    } /* --- end-of-while(clrstr[j]) --- */
  return ( b64dstbuff );
  } /* --- end-of-function base64_encode() --- */

#ifdef TESTBASE64
int main( int argc, char *argv[] ) {
  char *mysrc  = (argc>1? argv[1] : "My bonnie is over the ocean      ");
  char *mysrc2 = (argc>2? argv[2] : "My bonnie is over the sea        ");
  char myb64[2048]="", myb642[2048]="";
  char mydst[2048]="", mydst2[2048]="";
  char *base64_enclode(), *base64_decode();
  int  testnum = 1;
  if ( strncmp(mysrc,"test",4) == 0 )
    testnum = atoi(mysrc+4);

  if ( testnum == 1 ) {
    strcpy(myb64,base64_encode(mysrc));
    printf("The string [%s]\n\tencodes into base64 as: [%s]\n",mysrc,myb64);
    strcpy(myb642,base64_encode(mysrc2));
    printf("The string [%s]\n\tencodes into base64 as: [%s]\n",mysrc2,myb642);
    printf("...\n");
    strcpy(mydst,base64_decode(myb64));
    printf("The string [%s]\n\tdecodes from base64 as: [%s]\n",myb64,mydst);
    strcpy(mydst2,base64_decode(myb642));
    printf("The string [%s]\n\tdecodes from base64 as: [%s]\n",myb642,mydst2);
    } /* --- end-of-if(testnum==1) --- */

  if ( testnum == 2 ) {
    strcpy(mydst,base64_decode(mysrc2)); /* input is b64 */
    printf("The string [%s]\n\tdecodes from base64 as: [%s]\n",mysrc2,mydst);
    } /* --- end-of-if(testnum==2) --- */

  if ( testnum == 3 ) {
    int itest, ntests = (argc>2?atoi(argv[2]):999);
    int ichar, nchars = (argc>3?atoi(argv[3]):128);
    unsigned int seed = (argc>4?atoi(argv[4]):987654321);
    char blanks[999] = "                           ";
    srand(seed);
    for ( itest=1; itest<=ntests; itest++ ) {
      for ( ichar=0; ichar<nchars; ichar++ ) mydst[ichar] = 1+(rand()%255);
      mydst[nchars] = '\000';
      if ( strlen(blanks) > 0 ) strcat(mydst,blanks);
      strcpy(myb64,base64_encode(mydst));
      strcpy(mydst2,base64_decode(myb64));
      if ( strcmp(mydst,mydst2) != 0 )
        printf("Test#%d:\n\t in=%s\n\tout=%s\n",itest,mydst,mydst2);
      } /* --- end-of-for(itest) --- */
    } /* --- end-of-if(testnum==3) --- */

  return 0;
  } /* --- end-of-function main() --- */
#endif

1 个答案:

答案 0 :(得分:2)

不,它不依赖于字节序。 Base64本身是4字节到3字节的编码,并不关心内存中的实际表示。但是,如果您希望传输小/大端数据,则必须在编码之前和解码之后规范化字节序

该片段只是独立地处理所有字节。如果它在uint32_t左右加载了4个字节,并且使用一些比特twiddling产生了一个输出,将按原样复制到结果缓冲区中,它将依赖于字节序。

然而,该代码被其strncat危险地破坏,并且不会使用嵌入的NUL字节。相反,你应该使用像

这样的东西
void decodeblock(unsigned char in[], unsigned char **clrstr) {
     *((*clrstr) ++) = in[0] << 2 | in[1] >> 4;
     *((*clrstr) ++) = in[1] << 4 | in[2] >> 2;
     *((*clrstr) ++) = in[2] << 6 | in[3] >> 0;
}

适用于嵌入式NUL。