Base64: Difference between revisions
No edit summary |
m (comment fail.. two > four) |
||
Line 283: | Line 283: | ||
; aaaaaa shifted two bits to the left | ; aaaaaa shifted two bits to the left | ||
; the two left-most bits of bbbbbb, | ; the two left-most bits of bbbbbb, | ||
; which you can do by shifting it | ; which you can do by shifting it four bits to the right | ||
IntOp $R5 $R1 << 2 | IntOp $R5 $R1 << 2 | ||
IntOp $R6 $R2 >> 4 | IntOp $R6 $R2 >> 4 |
Latest revision as of 01:01, 25 September 2010
BASE64 Encoding/Decoding Functions
As a result of needing to send data in a URL from my NSIS Installer, and because I didn't want to include another dependency, 99999999 wrote the below Base64 Encoder.
Please note: this header depends on the CharToASCII header.
Forum thread: http://forums.winamp.com/showthread.php?t=297879 "Base64 Encoder in NSIS"
Usage example as follows:
!include "CharToASCII.nsh" !include "Base64.nsh" OutFile "$%temp%\temp.exe" Section ${Base64_Encode} "THIS WILL BE ENCODED" Pop $0 ; $0 now equals VEhJUyBXSUxMIEJFIEVOQ09ERUQ= MessageBox MB_OK "$0" SectionEnd
Also there is a variant for encoding in a URL safe form, ${Base64_URLEncode}, which just uses a different encoding table, (but a standard one,) from the original version. I don't know how this works with Binary Data, but it works great with string data, which you need to put into a consistent form.
Animaether added decoding routines.
Forum thread: http://forums.winamp.com/showthread.php?t=322673 "Base64 decoder"
!include "CharToASCII.nsh" !include "Base64.nsh" OutFile "$%temp%\temp.exe" Section ${Base64_Decode} "VEhJUyBXSUxMIEJFIERFQ09ERUQ=" Pop $0 ; $0 now equals "THIS WILL BE DECODED" MessageBox MB_OK "$0" SectionEnd
As with the encoding functions, a URL safe form exists in the form of ${Base64_URLDecode}.
The header code
!ifndef BASE64_NSH !define BASE64_NSH !define BASE64_ENCODINGTABLE "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" !define BASE64_ENCODINGTABLEURL "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" !define BASE64_PADDING "=" VAR OCTETVALUE VAR BASE64TEMP !define Base64_Encode "!insertmacro Base64_Encode" !define Base64_URLEncode "!insertmacro Base64_URLEncode" !macro Base64_Encode _cleartext push $R0 push $R1 push $R2 push $0 push $1 push $2 push $3 push $4 push $5 push $6 push $7 push `${_cleartext}` push `${BASE64_ENCODINGTABLE}` Call Base64_Encode Pop $BASE64TEMP Pop $7 Pop $6 Pop $5 Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 pop $R2 pop $R1 pop $R0 Push $BASE64TEMP !macroend !macro Base64_URLEncode _cleartext push $R0 push $R1 push $R2 push $0 push $1 push $2 push $3 push $4 push $5 push $6 push $7 push `${_cleartext}` push `${BASE64_ENCODINGTABLEURL}` Call Base64_Encode Pop $BASE64TEMP Pop $7 Pop $6 Pop $5 Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 pop $R2 pop $R1 pop $R0 Push $BASE64TEMP !macroend Function Base64_Encode pop $R2 ; Encoding table pop $R0 ; Clear Text StrCpy "$R1" "" # The result StrLen $1 "$R0" StrCpy $0 0 ${WHILE} $0 < $1 # Copy 3 characters, and for each character push their value. StrCpy $OCTETVALUE 0 StrCpy $5 $0 StrCpy $4 "$R0" 1 $5 ${CharToASCII} $4 "$4" IntOp $OCTETVALUE $4 << 16 IntOp $5 $5 + 1 ${IF} $5 < $1 StrCpy $4 "$R0" 1 $5 ${CharToASCII} $4 "$4" IntOp $4 $4 << 8 IntOp $OCTETVALUE $OCTETVALUE + $4 IntOp $5 $5 + 1 ${IF} $5 < $1 StrCpy $4 "$R0" 1 $5 ${CharToASCII} $4 "$4" IntOp $OCTETVALUE $OCTETVALUE + $4 ${ENDIF} ${ENDIF} # Now take the 4 indexes from the encoding table, based on 6bits each of the octet's value. IntOp $4 $OCTETVALUE >> 18 IntOp $4 $4 & 63 StrCpy $5 "$R2" 1 $4 StrCpy $R1 "$R1$5" IntOp $4 $OCTETVALUE >> 12 IntOp $4 $4 & 63 StrCpy $5 "$R2" 1 $4 StrCpy $R1 "$R1$5" StrCpy $6 $0 StrCpy $7 2 IntOp $6 $6 + 1 ${IF} $6 < $1 IntOp $4 $OCTETVALUE >> 6 IntOp $4 $4 & 63 StrCpy $5 "$R2" 1 $4 StrCpy $R1 "$R1$5" IntOp $7 $7 - 1 ${ENDIF} IntOp $6 $6 + 1 ${IF} $6 < $1 IntOp $4 $OCTETVALUE & 63 StrCpy $5 "$R2" 1 $4 StrCpy $R1 "$R1$5" IntOp $7 $7 - 1 ${ENDIF} # If there is any padding required, we now write that here. ${IF} $7 > 0 ${WHILE} $7 > 0 StrCpy $R1 "$R1${BASE64_PADDING}" IntOp $7 $7 - 1 ${ENDWHILE} ${ENDIF} IntOp $0 $0 + 3 ${ENDWHILE} Push "$R1" FunctionEnd !define Base64_Decode "!insertmacro Base64_Decode" !define Base64_URLDecode "!insertmacro Base64_URLDecode" !macro Base64_Decode _encodedtext push `${_encodedtext}` push `${BASE64_ENCODINGTABLE}` Call Base64_Decode !macroend !macro Base64_URLDecode _encodedtext push `${_encodedtext}` push `${BASE64_ENCODINGTABLEURL}` Call Base64_Decode !macroend Function base64_Decode ; Stack: strBase64table strEncoded Push $9 ; Stack: $9 strBase64table strEncoded ; $9 = strDecoded Exch 2 ; Stack: strEncoded strBase64table $9 Exch ; Stack: strBase64table strEncoded $9 Exch $0 ; Stack: $0 strEncoded $9 ; $0 = strBase64table Exch ; Stack: strEncoded $0 $9 Exch $1 ; Stack: $1 $0 $9 ; $1 = strEncoded Push $2 ; strBase64table.length Push $3 ; strEncoded.length Push $4 ; strBase64table.counter Push $5 ; strEncoded.counter Push $6 ; strBase64table.char Push $7 ; strEncoded.char Push $R0 ; 6bit-group.counter Push $R1 ; 6bit-group.a Push $R2 ; 6bit-group.b Push $R3 ; 6bit-group.c Push $R4 ; 6bit-group.d Push $R5 ; bit-group.tempVar.a Push $R6 ; bit-group.tempVar.b Push $R7 ; 8bit-group.A Push $R8 ; 8bit-group.B Push $R9 ; 8bit-group.C StrCpy $9 "" ; Result string StrLen $2 "$0" ; Get the length of the base64 table into $2 StrLen $3 "$1" ; Get the length of the encoded text into $3 IntOp $3 $3 - 1 ; Subtract one as the StrCpy offset is zero-based StrCpy $R0 4 ; Initialize the 6bit-group.counter ${ForEach} $5 0 $3 + 1 ; Loop over the encoded string StrCpy $7 $1 1 $5 ; Grab the character at the loop counter's index ${If} $7 == "${BASE64_PADDING}" ; If it's the padding char Push 0 ; Push value 0 (no impact on decoded string) ${Else} ; Otherwise ${ForEach} $4 0 $2 + 1 ; Loop over the base64 lookup table StrCpy $6 $0 1 $4 ; Grab the character at this loop counter's index ${If} $6 S== $7 ; If that character matches the encoded string character ${ExitFor} ; Exit this loop early ${EndIf} ${Next} Push $4 ; Push the lookup's index to the stack ${EndIf} IntOp $R0 $R0 - 1 ; Decrease the 6bit-group counter ${If} $R0 = 0 ; If that counter reaches zero ; Pop the index values off the stack to variables Pop $R4 Pop $R3 Pop $R2 Pop $R1 ; The way the base64 decoding works is like this... ; Normal ASCII has 8 bits, base64 has 6 bits. ; Those 8 bits need to be presented as 6 bits somehow ; Turns out you can easily do that by taking their common multiple: 24 ; This results in 3 8bit characters per each 4 6bit characters: ; AAAAAAAA BBBBBBBB CCCCCCCC ; aaaaaabb bbbbcccc ccdddddd ; So to go back to AAAAAAAA, you need: ; aaaaaa shifted two bits to the left ; the two left-most bits of bbbbbb, ; which you can do by shifting it four bits to the right IntOp $R5 $R1 << 2 IntOp $R6 $R2 >> 4 IntOp $R5 $R5 | $R6 IntFmt $R7 "%c" $R5 ; IntFmt turns the resulting 8bit value to a character ; For BBBBBBBB, you need: ; the four least significant bits of bbbbbb ; which you can get by binary OR'ing with 2^4-1 = 15 ; the four most significant bits of cccccc ; which you can get by just shifting it two bits to the right IntOp $R5 $R2 & 15 InTop $R5 $R5 << 4 IntOp $R6 $R3 >> 2 IntOp $R5 $R5 | $R6 IntFmt $R8 "%c" $R5 ; For CCCCCCCC, the procedure is entirely similar. IntOp $R5 $R3 & 3 IntOp $R5 $R5 << 6 IntOp $R5 $R5 | $R4 IntFmt $R9 "%c" $R5 StrCpy $9 "$9$R7$R8$R9" ; Tack it all onto the result StrCpy $R0 4 ; Reset the 6bit-group counter ${EndIf} ${Next} ; Done. Now let's restore the user's variables Pop $R9 Pop $R8 Pop $R7 Pop $R6 Pop $R5 Pop $R4 Pop $R3 Pop $R2 Pop $R1 Pop $R0 Pop $7 Pop $6 Pop $5 Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 Exch $9 ; Stack: strDecoded FunctionEnd !endif ;BASE64_NSH