summaryrefslogtreecommitdiff
path: root/src/base64.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/base64.c')
-rw-r--r--src/base64.c1034
1 files changed, 1034 insertions, 0 deletions
diff --git a/src/base64.c b/src/base64.c
new file mode 100644
index 00000000..53e66945
--- /dev/null
+++ b/src/base64.c
@@ -0,0 +1,1034 @@
+/**
+ * XML Security Library (http://www.aleksey.com/xmlsec).
+ *
+ * Base64 encode/decode transform and utility functions.
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ *
+ * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com>
+ */
+#include "globals.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <libxml/tree.h>
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/keys.h>
+#include <xmlsec/transforms.h>
+#include <xmlsec/base64.h>
+#include <xmlsec/errors.h>
+
+/*
+ * the table to map numbers to base64
+ */
+static const xmlSecByte base64[] =
+{
+/* 0 1 2 3 4 5 6 7 */
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', /* 0 */
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 1 */
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', /* 2 */
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', /* 3 */
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 4 */
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', /* 5 */
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3', /* 6 */
+ '4', '5', '6', '7', '8', '9', '+', '/' /* 7 */
+};
+
+
+/* few macros to simplify the code */
+#define xmlSecBase64Encode1(a) (((a) >> 2) & 0x3F)
+#define xmlSecBase64Encode2(a, b) ((((a) << 4) & 0x30) + (((b) >> 4) & 0x0F))
+#define xmlSecBase64Encode3(b, c) ((((b) << 2) & 0x3c) + (((c) >> 6) & 0x03))
+#define xmlSecBase64Encode4(c) ((c) & 0x3F)
+
+#define xmlSecBase64Decode1(a, b) (((a) << 2) | (((b) & 0x3F) >> 4))
+#define xmlSecBase64Decode2(b, c) (((b) << 4) | (((c) & 0x3F) >> 2))
+#define xmlSecBase64Decode3(c, d) (((c) << 6) | ((d) & 0x3F))
+
+#define xmlSecIsBase64Char(ch) ((((ch) >= 'A') && ((ch) <= 'Z')) || \
+ (((ch) >= 'a') && ((ch) <= 'z')) || \
+ (((ch) >= '0') && ((ch) <= '9')) || \
+ ((ch) == '+') || ((ch) == '/'))
+#define xmlSecIsBase64Space(ch) (((ch) == ' ') || ((ch) == '\t') || \
+ ((ch) == '\x0d') || ((ch) == '\x0a'))
+
+
+
+/***********************************************************************
+ *
+ * Base64 Context
+ *
+ ***********************************************************************/
+typedef enum {
+ xmlSecBase64StatusConsumeAndNext = 0,
+ xmlSecBase64StatusConsumeAndRepeat,
+ xmlSecBase64StatusNext,
+ xmlSecBase64StatusDone,
+ xmlSecBase64StatusFailed
+} xmlSecBase64Status;
+
+struct _xmlSecBase64Ctx {
+ int encode;
+ int inByte;
+ int inPos;
+ xmlSecSize linePos;
+ xmlSecSize columns;
+ int finished;
+};
+
+static xmlSecBase64Status xmlSecBase64CtxEncodeByte (xmlSecBase64CtxPtr ctx,
+ xmlSecByte inByte,
+ xmlSecByte* outByte);
+static xmlSecBase64Status xmlSecBase64CtxEncodeByteFinal (xmlSecBase64CtxPtr ctx,
+ xmlSecByte* outByte);
+static xmlSecBase64Status xmlSecBase64CtxDecodeByte (xmlSecBase64CtxPtr ctx,
+ xmlSecByte inByte,
+ xmlSecByte* outByte);
+static int xmlSecBase64CtxEncode (xmlSecBase64CtxPtr ctx,
+ const xmlSecByte* inBuf,
+ xmlSecSize inBufSize,
+ xmlSecSize* inBufResSize,
+ xmlSecByte* outBuf,
+ xmlSecSize outBufSize,
+ xmlSecSize* outBufResSize);
+static int xmlSecBase64CtxEncodeFinal (xmlSecBase64CtxPtr ctx,
+ xmlSecByte* outBuf,
+ xmlSecSize outBufSize,
+ xmlSecSize* outBufResSize);
+static int xmlSecBase64CtxDecode (xmlSecBase64CtxPtr ctx,
+ const xmlSecByte* inBuf,
+ xmlSecSize inBufSize,
+ xmlSecSize* inBufResSize,
+ xmlSecByte* outBuf,
+ xmlSecSize outBufSize,
+ xmlSecSize* outBufResSize);
+static int xmlSecBase64CtxDecodeIsFinished (xmlSecBase64CtxPtr ctx);
+
+
+static int g_xmlsec_base64_default_line_size = XMLSEC_BASE64_LINESIZE;
+
+/**
+ * xmlSecBase64GetDefaultLineSize:
+ *
+ * Gets the current default line size.
+ *
+ * Returns: the current default line size.
+ */
+int
+xmlSecBase64GetDefaultLineSize(void)
+{
+ return g_xmlsec_base64_default_line_size;
+}
+
+/**
+ * xmlSecBase64SetDefaultLineSize:
+ * @columns: number of columns
+ *
+ * Sets the current default line size.
+ */
+void
+xmlSecBase64SetDefaultLineSize(int columns)
+{
+ g_xmlsec_base64_default_line_size = columns;
+}
+
+/**
+ * xmlSecBase64CtxCreate:
+ * @encode: the encode/decode flag (1 - encode, 0 - decode)
+ * @columns: the max line length.
+ *
+ * Allocates and initializes new base64 context.
+ *
+ * Returns: a pointer to newly created #xmlSecBase64Ctx structure
+ * or NULL if an error occurs.
+ */
+xmlSecBase64CtxPtr
+xmlSecBase64CtxCreate(int encode, int columns) {
+ xmlSecBase64CtxPtr ctx;
+ int ret;
+
+ /*
+ * Allocate a new xmlSecBase64CtxPtr and fill the fields.
+ */
+ ctx = (xmlSecBase64CtxPtr) xmlMalloc(sizeof(xmlSecBase64Ctx));
+ if (ctx == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "sizeof(xmlSecBase64Ctx)=%d",
+ sizeof(xmlSecBase64Ctx));
+ return(NULL);
+ }
+
+ ret = xmlSecBase64CtxInitialize(ctx, encode, columns);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64CtxInitialize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlSecBase64CtxDestroy(ctx);
+ return(NULL);
+ }
+ return(ctx);
+}
+
+/**
+ * xmlSecBase64CtxDestroy:
+ * @ctx: the pointer to #xmlSecBase64Ctx structure.
+ *
+ * Destroys base64 context.
+ */
+void
+xmlSecBase64CtxDestroy(xmlSecBase64CtxPtr ctx) {
+ xmlSecAssert(ctx != NULL);
+
+ xmlSecBase64CtxFinalize(ctx);
+ xmlFree(ctx);
+}
+
+/**
+ * xmlSecBase64CtxInitialize:
+ * @ctx: the pointer to #xmlSecBase64Ctx structure,
+ * @encode: the encode/decode flag (1 - encode, 0 - decode)
+ * @columns: the max line length.
+ *
+ * Initializes new base64 context.
+ *
+ * Returns: 0 on success and a negative value otherwise.
+ */
+int
+xmlSecBase64CtxInitialize(xmlSecBase64CtxPtr ctx, int encode, int columns) {
+ xmlSecAssert2(ctx != NULL, -1);
+
+ memset(ctx, 0, sizeof(xmlSecBase64Ctx));
+
+ ctx->encode = encode;
+ ctx->columns = columns;
+ return(0);
+}
+
+/**
+ * xmlSecBase64CtxFinalize:
+ * @ctx: the pointer to #xmlSecBase64Ctx structure,
+ *
+ * Frees all the resources allocated by @ctx.
+ */
+void
+xmlSecBase64CtxFinalize(xmlSecBase64CtxPtr ctx) {
+ xmlSecAssert(ctx != NULL);
+
+ memset(ctx, 0, sizeof(xmlSecBase64Ctx));
+}
+
+/**
+ * xmlSecBase64CtxUpdate:
+ * @ctx: the pointer to #xmlSecBase64Ctx structure
+ * @in: the input buffer
+ * @inSize: the input buffer size
+ * @out: the output buffer
+ * @outSize: the output buffer size
+ *
+ * Encodes or decodes the next piece of data from input buffer.
+ *
+ * Returns: the number of bytes written to output buffer or
+ * -1 if an error occurs.
+ */
+int
+xmlSecBase64CtxUpdate(xmlSecBase64CtxPtr ctx,
+ const xmlSecByte *in, xmlSecSize inSize,
+ xmlSecByte *out, xmlSecSize outSize) {
+ xmlSecSize inResSize = 0, outResSize = 0;
+ int ret;
+
+ xmlSecAssert2(ctx != NULL, -1);
+ xmlSecAssert2(in != NULL, -1);
+ xmlSecAssert2(out != NULL, -1);
+
+ if(ctx->encode != 0) {
+ ret = xmlSecBase64CtxEncode(ctx, in, inSize, &inResSize,
+ out, outSize, &outResSize);
+ if((ret < 0) || (inResSize != inSize)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64CtxEncode",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ } else {
+ ret = xmlSecBase64CtxDecode(ctx, in, inSize, &inResSize,
+ out, outSize, &outResSize);
+ if((ret < 0) || (inResSize != inSize)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64CtxDecode",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ }
+
+ return(outResSize);
+}
+
+/**
+ * xmlSecBase64CtxFinal:
+ * @ctx: the pointer to #xmlSecBase64Ctx structure
+ * @out: the output buffer
+ * @outSize: the output buffer size
+ *
+ * Encodes or decodes the last piece of data stored in the context
+ * and finalizes the result.
+ *
+ * Returns: the number of bytes written to output buffer or
+ * -1 if an error occurs.
+ */
+int
+xmlSecBase64CtxFinal(xmlSecBase64CtxPtr ctx,
+ xmlSecByte *out, xmlSecSize outSize) {
+ xmlSecSize outResSize = 0;
+ int ret;
+
+ xmlSecAssert2(ctx != NULL, -1);
+ xmlSecAssert2(out != NULL, -1);
+ xmlSecAssert2(outSize > 0, -1);
+
+ if(ctx->encode != 0) {
+ ret = xmlSecBase64CtxEncodeFinal(ctx, out, outSize, &outResSize);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64CtxEncodeFinal",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "outSize=%d", outSize);
+ return(-1);
+ }
+ } else {
+ if(!xmlSecBase64CtxDecodeIsFinished(ctx)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64CtxIsFinished",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ }
+
+ /* add \0 */
+ if((outResSize + 1) < outSize) {
+ out[outResSize] = '\0';
+ }
+ return(outResSize);
+}
+
+static xmlSecBase64Status
+xmlSecBase64CtxEncodeByte(xmlSecBase64CtxPtr ctx, xmlSecByte inByte, xmlSecByte* outByte) {
+ xmlSecAssert2(ctx != NULL, xmlSecBase64StatusFailed);
+ xmlSecAssert2(outByte != NULL, xmlSecBase64StatusFailed);
+
+ if((ctx->columns > 0) && (ctx->linePos >= ctx->columns)) {
+ (*outByte) = '\n';
+ ctx->linePos = 0;
+ return(xmlSecBase64StatusConsumeAndRepeat);
+ } else if(ctx->inPos == 0) {
+ /* we just started new block */
+ (*outByte) = base64[xmlSecBase64Encode1(inByte)];
+ ctx->inByte = inByte;
+ ++ctx->linePos;
+ ++ctx->inPos;
+ return(xmlSecBase64StatusConsumeAndNext);
+ } else if(ctx->inPos == 1) {
+ (*outByte) = base64[xmlSecBase64Encode2(ctx->inByte, inByte)];
+ ctx->inByte = inByte;
+ ++ctx->linePos;
+ ++ctx->inPos;
+ return(xmlSecBase64StatusConsumeAndNext);
+ } else if(ctx->inPos == 2) {
+ (*outByte) = base64[xmlSecBase64Encode3(ctx->inByte, inByte)];
+ ctx->inByte = inByte;
+ ++ctx->linePos;
+ ++ctx->inPos;
+ return(xmlSecBase64StatusConsumeAndRepeat);
+ } else if(ctx->inPos == 3) {
+ (*outByte) = base64[xmlSecBase64Encode4(ctx->inByte)];
+ ++ctx->linePos;
+ ctx->inByte = 0;
+ ctx->inPos = 0;
+ return(xmlSecBase64StatusConsumeAndNext);
+ }
+
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_DATA,
+ "ctx->inPos=%d", ctx->inPos);
+ return(xmlSecBase64StatusFailed);
+}
+
+static xmlSecBase64Status
+xmlSecBase64CtxEncodeByteFinal(xmlSecBase64CtxPtr ctx, xmlSecByte* outByte) {
+ xmlSecAssert2(ctx != NULL, xmlSecBase64StatusFailed);
+ xmlSecAssert2(outByte != NULL, xmlSecBase64StatusFailed);
+
+ if(ctx->inPos == 0) {
+ return(xmlSecBase64StatusDone);
+ } else if((ctx->columns > 0) && (ctx->linePos >= ctx->columns)) {
+ (*outByte) = '\n';
+ ctx->linePos = 0;
+ return(xmlSecBase64StatusConsumeAndRepeat);
+ } else if(ctx->finished == 0) {
+ ctx->finished = 1;
+ return(xmlSecBase64CtxEncodeByte(ctx, 0, outByte));
+ } else if(ctx->inPos < 3) {
+ (*outByte) = '=';
+ ++ctx->inPos;
+ ++ctx->linePos;
+ return(xmlSecBase64StatusConsumeAndRepeat);
+ } else if(ctx->inPos == 3) {
+ (*outByte) = '=';
+ ++ctx->linePos;
+ ctx->inPos = 0;
+ return(xmlSecBase64StatusConsumeAndRepeat);
+ }
+
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_DATA,
+ "ctx->inPos=%d", ctx->inPos);
+ return(xmlSecBase64StatusFailed);
+}
+
+static xmlSecBase64Status
+xmlSecBase64CtxDecodeByte(xmlSecBase64CtxPtr ctx, xmlSecByte inByte, xmlSecByte* outByte) {
+ xmlSecAssert2(ctx != NULL, xmlSecBase64StatusFailed);
+ xmlSecAssert2(outByte != NULL, xmlSecBase64StatusFailed);
+
+ if((ctx->finished != 0) && (ctx->inPos == 0)) {
+ return(xmlSecBase64StatusDone);
+ } if(inByte == '=') {
+ ctx->finished = 1;
+ if(ctx->inPos < 2) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_DATA,
+ "ctx->inPos=%d", ctx->inPos);
+ return(xmlSecBase64StatusFailed);
+ } else if(ctx->inPos == 2) {
+ ++ctx->inPos;
+ return(xmlSecBase64StatusNext);
+ } else if(ctx->inPos == 3) {
+ ctx->inPos = 0;
+ return(xmlSecBase64StatusNext);
+ } else {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_DATA,
+ "ctx->inPos=%d", ctx->inPos);
+ return(xmlSecBase64StatusFailed);
+ }
+ } else if(xmlSecIsBase64Space(inByte)) {
+ return(xmlSecBase64StatusNext);
+ } else if(!xmlSecIsBase64Char(inByte) || (ctx->finished != 0)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_DATA,
+ "inByte=0x%02x", inByte);
+ return(xmlSecBase64StatusFailed);
+ }
+
+ /* convert from character to position in base64 array */
+ if((inByte >= 'A') && (inByte <= 'Z')) {
+ inByte = (inByte - 'A');
+ } else if((inByte >= 'a') && (inByte <= 'z')) {
+ inByte = 26 + (inByte - 'a');
+ } else if((inByte >= '0') && (inByte <= '9')) {
+ inByte = 52 + (inByte - '0');
+ } else if(inByte == '+') {
+ inByte = 62;
+ } else if(inByte == '/') {
+ inByte = 63;
+ }
+
+ if(ctx->inPos == 0) {
+ ctx->inByte = inByte;
+ ++ctx->inPos;
+ return(xmlSecBase64StatusNext);
+ } else if(ctx->inPos == 1) {
+ (*outByte) = xmlSecBase64Decode1(ctx->inByte, inByte);
+ ctx->inByte = inByte;
+ ++ctx->inPos;
+ return(xmlSecBase64StatusConsumeAndNext);
+ } else if(ctx->inPos == 2) {
+ (*outByte) = xmlSecBase64Decode2(ctx->inByte, inByte);
+ ctx->inByte = inByte;
+ ++ctx->inPos;
+ return(xmlSecBase64StatusConsumeAndNext);
+ } else if(ctx->inPos == 3) {
+ (*outByte) = xmlSecBase64Decode3(ctx->inByte, inByte);
+ ctx->inByte = 0;
+ ctx->inPos = 0;
+ return(xmlSecBase64StatusConsumeAndNext);
+ }
+
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_DATA,
+ "ctx->inPos=%d", ctx->inPos);
+ return(xmlSecBase64StatusFailed);
+}
+
+
+static int
+xmlSecBase64CtxEncode(xmlSecBase64CtxPtr ctx,
+ const xmlSecByte* inBuf, xmlSecSize inBufSize, xmlSecSize* inBufResSize,
+ xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize) {
+ xmlSecBase64Status status = xmlSecBase64StatusNext;
+ xmlSecSize inPos, outPos;
+
+ xmlSecAssert2(ctx != NULL, -1);
+ xmlSecAssert2(inBuf != NULL, -1);
+ xmlSecAssert2(inBufResSize != NULL, -1);
+ xmlSecAssert2(outBuf != NULL, -1);
+ xmlSecAssert2(outBufResSize != NULL, -1);
+
+ /* encode */
+ for(inPos = outPos = 0; (inPos < inBufSize) && (outPos < outBufSize); ) {
+ status = xmlSecBase64CtxEncodeByte(ctx, inBuf[inPos], &(outBuf[outPos]));
+ switch(status) {
+ case xmlSecBase64StatusConsumeAndNext:
+ ++inPos;
+ ++outPos;
+ break;
+ case xmlSecBase64StatusConsumeAndRepeat:
+ ++outPos;
+ break;
+ case xmlSecBase64StatusNext:
+ case xmlSecBase64StatusDone:
+ case xmlSecBase64StatusFailed:
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64CtxEncodeByte",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "status=%d", status);
+ return(-1);
+ }
+ }
+
+ (*inBufResSize) = inPos;
+ (*outBufResSize) = outPos;
+
+ return(0);
+}
+
+static int
+xmlSecBase64CtxEncodeFinal(xmlSecBase64CtxPtr ctx,
+ xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize) {
+ xmlSecBase64Status status = xmlSecBase64StatusNext;
+ xmlSecSize outPos;
+
+ xmlSecAssert2(ctx != NULL, -1);
+ xmlSecAssert2(outBuf != NULL, -1);
+ xmlSecAssert2(outBufResSize != NULL, -1);
+
+ /* encode final bytes */
+ for(outPos = 0; (outPos < outBufSize) && (status != xmlSecBase64StatusDone); ) {
+ status = xmlSecBase64CtxEncodeByteFinal(ctx, &(outBuf[outPos]));
+ switch(status) {
+ case xmlSecBase64StatusConsumeAndNext:
+ case xmlSecBase64StatusConsumeAndRepeat:
+ ++outPos;
+ break;
+ case xmlSecBase64StatusDone:
+ break;
+ case xmlSecBase64StatusNext:
+ case xmlSecBase64StatusFailed:
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64CtxEncodeByteFinal",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "status=%d", status);
+ return(-1);
+ }
+ }
+
+ if(status != xmlSecBase64StatusDone) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_SIZE,
+ "outBufSize=%d", outBufSize);
+ return(-1);
+ }
+ if(outPos < outBufSize) {
+ outBuf[outPos] = '\0'; /* just in case */
+ }
+
+ (*outBufResSize) = outPos;
+ return(0);
+}
+
+
+static int
+xmlSecBase64CtxDecode(xmlSecBase64CtxPtr ctx,
+ const xmlSecByte* inBuf, xmlSecSize inBufSize, xmlSecSize* inBufResSize,
+ xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize) {
+ xmlSecBase64Status status = xmlSecBase64StatusNext;
+ xmlSecSize inPos, outPos;
+
+ xmlSecAssert2(ctx != NULL, -1);
+ xmlSecAssert2(inBuf != NULL, -1);
+ xmlSecAssert2(inBufResSize != NULL, -1);
+ xmlSecAssert2(outBuf != NULL, -1);
+ xmlSecAssert2(outBufResSize != NULL, -1);
+
+ /* decode */
+ for(inPos = outPos = 0; (inPos < inBufSize) && (outPos < outBufSize) && (status != xmlSecBase64StatusDone); ) {
+ status = xmlSecBase64CtxDecodeByte(ctx, inBuf[inPos], &(outBuf[outPos]));
+ switch(status) {
+ case xmlSecBase64StatusConsumeAndNext:
+ ++inPos;
+ ++outPos;
+ break;
+ case xmlSecBase64StatusConsumeAndRepeat:
+ ++outPos;
+ break;
+ case xmlSecBase64StatusNext:
+ ++inPos;
+ break;
+ case xmlSecBase64StatusDone:
+ break;
+ case xmlSecBase64StatusFailed:
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64CtxDecodeByte",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "status=%d", status);
+ return(-1);
+ }
+ }
+
+ /* skip spaces at the end */
+ while((inPos < inBufSize) && xmlSecIsBase64Space(inBuf[inPos])) {
+ ++inPos;
+ }
+
+ (*inBufResSize) = inPos;
+ (*outBufResSize) = outPos;
+
+ return(0);
+}
+
+static int
+xmlSecBase64CtxDecodeIsFinished(xmlSecBase64CtxPtr ctx) {
+ xmlSecAssert2(ctx != NULL, -1);
+
+ return((ctx->inPos == 0) ? 1 : 0);
+}
+
+/**
+ * xmlSecBase64Encode:
+ * @buf: the input buffer.
+ * @len: the input buffer size.
+ * @columns: the output max line length (if 0 then no line breaks
+ * would be inserted)
+ *
+ * Encodes the data from input buffer and allocates the string for the result.
+ * The caller is responsible for freeing returned buffer using
+ * xmlFree() function.
+ *
+ * Returns: newly allocated string with base64 encoded data
+ * or NULL if an error occurs.
+ */
+xmlChar*
+xmlSecBase64Encode(const xmlSecByte *buf, xmlSecSize len, int columns) {
+ xmlSecBase64Ctx ctx;
+ xmlChar *ptr;
+ xmlSecSize size;
+ int size_update, size_final;
+ int ret;
+
+ xmlSecAssert2(buf != NULL, NULL);
+
+ ret = xmlSecBase64CtxInitialize(&ctx, 1, columns);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64CtxInitialize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+
+ /* create result buffer */
+ size = (4 * len) / 3 + 4;
+ if(columns > 0) {
+ size += (size / columns) + 4;
+ }
+ ptr = (xmlChar*) xmlMalloc(size);
+ if(ptr == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ NULL,
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", size);
+ xmlSecBase64CtxFinalize(&ctx);
+ return(NULL);
+ }
+
+ ret = xmlSecBase64CtxUpdate(&ctx, buf, len, (xmlSecByte*)ptr, size);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64CtxUpdate",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "len=%d", len);
+ xmlFree(ptr);
+ xmlSecBase64CtxFinalize(&ctx);
+ return(NULL);
+ }
+ size_update = ret;
+
+ ret = xmlSecBase64CtxFinal(&ctx, ((xmlSecByte*)ptr) + size_update, size - size_update);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64CtxFinal",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFree(ptr);
+ xmlSecBase64CtxFinalize(&ctx);
+ return(NULL);
+ }
+ size_final = ret;
+ ptr[size_update + size_final] = '\0';
+
+ xmlSecBase64CtxFinalize(&ctx);
+ return(ptr);
+}
+
+/**
+ * xmlSecBase64Decode:
+ * @str: the input buffer with base64 encoded string
+ * @buf: the output buffer
+ * @len: the output buffer size
+ *
+ * Decodes input base64 encoded string and puts result into
+ * the output buffer.
+ *
+ * Returns: the number of bytes written to the output buffer or
+ * a negative value if an error occurs
+ */
+int
+xmlSecBase64Decode(const xmlChar* str, xmlSecByte *buf, xmlSecSize len) {
+ xmlSecBase64Ctx ctx;
+ int size_update;
+ int size_final;
+ int ret;
+
+ xmlSecAssert2(str != NULL, -1);
+ xmlSecAssert2(buf != NULL, -1);
+
+ ret = xmlSecBase64CtxInitialize(&ctx, 0, 0);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64CtxInitialize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ ret = xmlSecBase64CtxUpdate(&ctx, (const xmlSecByte*)str, xmlStrlen(str), buf, len);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64CtxUpdate",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlSecBase64CtxFinalize(&ctx);
+ return(-1);
+ }
+
+ size_update = ret;
+ ret = xmlSecBase64CtxFinal(&ctx, buf + size_update, len - size_update);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64CtxFinal",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlSecBase64CtxFinalize(&ctx);
+ return(-1);
+ }
+ size_final = ret;
+
+ xmlSecBase64CtxFinalize(&ctx);
+ return(size_update + size_final);
+}
+
+/**************************************************************
+ *
+ * Base64 Transform
+ *
+ * xmlSecBase64Ctx is located after xmlSecTransform
+ *
+ **************************************************************/
+#define xmlSecBase64Size \
+ (sizeof(xmlSecTransform) + sizeof(xmlSecBase64Ctx))
+#define xmlSecBase64GetCtx(transform) \
+ ((xmlSecTransformCheckSize((transform), xmlSecBase64Size)) ? \
+ (xmlSecBase64CtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \
+ (xmlSecBase64CtxPtr)NULL)
+
+static int xmlSecBase64Initialize (xmlSecTransformPtr transform);
+static void xmlSecBase64Finalize (xmlSecTransformPtr transform);
+static int xmlSecBase64Execute (xmlSecTransformPtr transform,
+ int last,
+ xmlSecTransformCtxPtr transformCtx);
+
+static xmlSecTransformKlass xmlSecBase64Klass = {
+ /* klass/object sizes */
+ sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */
+ xmlSecBase64Size, /* xmlSecSize objSize */
+
+ xmlSecNameBase64, /* const xmlChar* name; */
+ xmlSecHrefBase64, /* const xmlChar* href; */
+ xmlSecTransformUsageDSigTransform, /* xmlSecAlgorithmUsage usage; */
+
+ xmlSecBase64Initialize, /* xmlSecTransformInitializeMethod initialize; */
+ xmlSecBase64Finalize, /* xmlSecTransformFinalizeMethod finalize; */
+ NULL, /* xmlSecTransformNodeReadMethod readNode; */
+ NULL, /* xmlSecTransformNodeWriteMethod writeNode; */
+ NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */
+ NULL, /* xmlSecTransformSetKeyMethod setKey; */
+ NULL, /* xmlSecTransformValidateMethod validate; */
+ xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */
+ xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */
+ xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */
+ NULL, /* xmlSecTransformPushXmlMethod pushXml; */
+ NULL, /* xmlSecTransformPopXmlMethod popXml; */
+ xmlSecBase64Execute, /* xmlSecTransformExecuteMethod execute; */
+
+ NULL, /* void* reserved0; */
+ NULL, /* void* reserved1; */
+};
+
+/**
+ * xmlSecTransformBase64GetKlass:
+ *
+ * The Base64 transform klass (http://www.w3.org/TR/xmldsig-core/#sec-Base-64).
+ * The normative specification for base64 decoding transforms is RFC 2045
+ * (http://www.ietf.org/rfc/rfc2045.txt). The base64 Transform element has
+ * no content. The input is decoded by the algorithms. This transform is
+ * useful if an application needs to sign the raw data associated with
+ * the encoded content of an element.
+ *
+ * Returns: base64 transform id.
+ */
+xmlSecTransformId
+xmlSecTransformBase64GetKlass(void) {
+ return(&xmlSecBase64Klass);
+}
+
+/**
+ * xmlSecTransformBase64SetLineSize:
+ * @transform: the pointer to BASE64 encode transform.
+ * @lineSize: the new max line size.
+ *
+ * Sets the max line size to @lineSize.
+ */
+void
+xmlSecTransformBase64SetLineSize(xmlSecTransformPtr transform, xmlSecSize lineSize) {
+ xmlSecBase64CtxPtr ctx;
+
+ xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id));
+
+ ctx = xmlSecBase64GetCtx(transform);
+ xmlSecAssert(ctx != NULL);
+
+ ctx->columns = lineSize;
+}
+
+static int
+xmlSecBase64Initialize(xmlSecTransformPtr transform) {
+ xmlSecBase64CtxPtr ctx;
+ int ret;
+
+ xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id), -1);
+
+ ctx = xmlSecBase64GetCtx(transform);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ transform->operation = xmlSecTransformOperationDecode;
+ ret = xmlSecBase64CtxInitialize(ctx, 0, xmlSecBase64GetDefaultLineSize());
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBase64CtxInitialize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ return(0);
+}
+
+static void
+xmlSecBase64Finalize(xmlSecTransformPtr transform) {
+ xmlSecBase64CtxPtr ctx;
+
+ xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id));
+
+ ctx = xmlSecBase64GetCtx(transform);
+ xmlSecAssert(ctx != NULL);
+
+ xmlSecBase64CtxFinalize(ctx);
+}
+
+static int
+xmlSecBase64Execute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) {
+ xmlSecBase64CtxPtr ctx;
+ xmlSecBufferPtr in, out;
+ xmlSecSize inSize, outSize, outLen;
+ int ret;
+
+ xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id), -1);
+ xmlSecAssert2((transform->operation == xmlSecTransformOperationEncode) || (transform->operation == xmlSecTransformOperationDecode), -1);
+ xmlSecAssert2(transformCtx != NULL, -1);
+
+ ctx = xmlSecBase64GetCtx(transform);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ in = &(transform->inBuf);
+ out = &(transform->outBuf);
+
+ if(transform->status == xmlSecTransformStatusNone) {
+ ctx->encode = (transform->operation == xmlSecTransformOperationEncode) ? 1 : 0;
+ transform->status = xmlSecTransformStatusWorking;
+ }
+
+ switch(transform->status) {
+ case xmlSecTransformStatusWorking:
+ inSize = xmlSecBufferGetSize(in);
+ outSize = xmlSecBufferGetSize(out);
+ if(inSize > 0) {
+ if(ctx->encode != 0) {
+ outLen = 4 * inSize / 3 + 8;
+ if(ctx->columns > 0) {
+ outLen += inSize / ctx->columns + 4;
+ }
+ } else {
+ outLen = 3 * inSize / 4 + 8;
+ }
+ ret = xmlSecBufferSetMaxSize(out, outSize + outLen);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBufferSetMaxSize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "size=%d", outSize + outLen);
+ return(-1);
+ }
+
+ /* encode/decode the next chunk */
+ ret = xmlSecBase64CtxUpdate(ctx, xmlSecBufferGetData(in), inSize,
+ xmlSecBufferGetData(out) + outSize,
+ outLen);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBase64CtxUpdate",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ outLen = ret;
+
+ /* set correct size */
+ ret = xmlSecBufferSetSize(out, outSize + outLen);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBufferSetSize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "size=%d", outSize + outLen);
+ return(-1);
+ }
+
+ /* remove chunk from input */
+ ret = xmlSecBufferRemoveHead(in, inSize);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBufferRemoveHead",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "size=%d", inSize);
+ return(-1);
+ }
+ }
+
+ if(last) {
+ outSize = xmlSecBufferGetSize(out);
+
+ ret = xmlSecBufferSetMaxSize(out, outSize + 16);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBufferSetMaxSize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "size=%d", outSize + 16);
+ return(-1);
+ }
+
+ /* add from ctx buffer */
+ ret = xmlSecBase64CtxFinal(ctx, xmlSecBufferGetData(out) + outSize, 16);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBase64CtxFinal",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ outLen = ret;
+
+ /* set correct size */
+ ret = xmlSecBufferSetSize(out, outSize + outLen);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ "xmlSecBufferSetSize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "size=%d", outSize + outLen);
+ return(-1);
+ }
+ transform->status = xmlSecTransformStatusFinished;
+ }
+ break;
+ case xmlSecTransformStatusFinished:
+ /* the only way we can get here is if there is no input */
+ xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1);
+ break;
+ default:
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecTransformGetName(transform)),
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_STATUS,
+ "status=%d", transform->status);
+ return(-1);
+ }
+ return(0);
+}
+
+