While working on an AMX project involving a lot of HTTP requests I came across some methods that required Basic Authentication. In regards to HTTP, Basic Authentication allows for a web client, such as a browser, to provider user credentials to the server when making a request. A colon ‘:’ is appended to the user name and concatenated with the password before having Base64 encoding applied and sent off in the HTTP header to the server. The server then receives and decodes the message to retrieve the original user name and password.
Most browsers natively support Base64 encoding and a lot of programming languages either support or have libraries already built to add the support to make Base64 encoding a simple hurdle to jump while programming on a PC. Unfortunately, AMX NetLinx has no such libraries or modules so the encoding needs to be added to each project.
This article will give you the functions required to add Base64 encoding to your next HTTP project. Also stay tuned for Part 2 which will give you the functions required to decode a Base64 string.
Base64 was created from the problems caused when binary files were needed to be encapsulated in other documents. A binary file can contain many zeroes and as we know from various issues with NetLinx, zeroes represent the end of strings or end of files for many different documents and programs. The binary bytes also have the chance of representing reserved or special characters that may cause misrepresentation in the document.
Base64 solved this problem by representing the data as one of a 64 character alphabet ( 0-9, a-z, A-Z, +, / ). Base64 works by converting the binary data into 6-bit long chunks which then gives you a value between 0 and 63 when represented as a decimal. This value represents one of the letters in the Base64 alphabet. It also compresses the original data 6:1.
This works really efficiently when the binary data being encoded is divisible by 3 bytes but when not problems can occur. Diving any number by 3 will always results in 3 different scenarios. There will either be no remainder, a remainder of 1 and a remainder of 2. The problems occur in the last 2 situations. The solution is rather simple and might appear as common sense to some but to turn the 1 byte with 2 remainders to a 3 byte sequence simply pad an extra two bytes of zeroes onto the end. This 3 byte sequence can now be divided into 4 Base64 characters. The character used to represent the 0000’s is an ‘=’. The same is done when there is one byte remaining. Add one byte of zeroes and divided the new sequence by 4.
Another requirement of Base64 implementation is that specifies a maximum line length of 76 characters. Lines can be delimited by a carriage return and line feed to encode long data.
The NetLinx code for encoding is broken up into two different functions. The first function is used to encode a byte into its Base64 equivalent. Each byte is offset by a different printable char to put it within the printable range.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | define_function char fnBase64_helperEncode( char c )
{
if (c < 26)
{
return 'A' + c
}
if (c < 52)
{
return 'a' + (c - 26)
}
if (c < 62)
{
return '0' + (c - 52)
}
if (c == 62)
{
return '+'
}
return '/'
} |
The following function is the main process used to encode the inputted string into its Base64 representation. The function takes 3 bytes of the string and converts it using bit shifting to four 6 bit chunks. These 6 bit chunks are then converted to Base64 and appended to the return string. The string is checked to see if the length has reached 76 characters and if so a carriage return and line feed is appended as specified.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | define_function char[1024] fnBase64_encode( char strIn[1024] )
{
stack_var char strReturn[1024]
stack_var integer i
stack_var integer len
stack_var char by1,by2,by3,by4,by5,by6,by7
len = length_string(strIn)
if( len == 0 )
{
return strReturn;
}
for( i = 1; i <= len; i = i + 3 )
{
by1 = 0
by2 = 0
by3 = 0
by4 = 0
by5 = 0
by6 = 0
by7 = 0
by1 = strIn[i]
if( i + 1 <= len )
{
by2 = strIn[i+1]
}
if( i + 2 <= len )
{
by3 = strIn[i+2]
}
by4 = type_cast( by1 >> 2 )
by5 = type_cast( (( by1 & $03) << 4) | (by2 >> 4) )
by6 = type_cast( (( by2 & $0F) << 2) | (by3 >> 6) )
by7 = type_cast( by3 & $3F )
strReturn = "strReturn, fnBase64_helperEncode(by4)"
strReturn = "strReturn, fnBase64_helperEncode(by5)"
if( i+1 <= len)
{
strReturn = "strReturn, fnBase64_helperEncode(by6)"
}
else
{
strReturn = "strReturn, '='"
}
if( i+2 <= len)
{
strReturn = "strReturn, fnBase64_helperEncode(by7)"
}
else
{
strReturn = "strReturn, '='"
}
if ((len % 76) == 0)
{
strReturn = "strReturn, $0D, $0A"
}
}
return strReturn
} |
These functions can be now used for Basic Authorisation in HTTP headers or for more advanced features such as emailing binary files over the AMX NetLinx platform. This article will be followed up with the functions required to reverse the process and decode a Base64 string into its original form.
If you have any questions or requests about other HTTP features you need clarifying for your AMX project then feel free to send me an email or post a comment here and I will look to covering it in the future.
by Business Loans
02 Feb 2010 at 06:25
I see your point. I have always though that encoding is as simple as it is, but its not. Fortunately there are plenty of people like you who are ready to help and enlighten us when given the chance.