HR$BINSTRING$VERSION = "2005-01-07"
//* ====================================================================================================================
//* hr$binstring.js -- Copyright (c) 2004,2005 Henk Reints (http://henk-reints.nl)
//* ------------------------------------------------------------------------------
//#
//# Description:
//# ------------
//# It is possible to read (parts of) binary files into JavaScript String Objects and process the binary content.
//# However, the 'charCodeAt' and 'fromCharCode' methods of the String Object do not always return a single byte
//# value, but for some values (in the range 128..159) these standard methods do an implicit conversion to/from
//# Unicode values greater than 255.
//# This script extends the String Object with properties and methods that compensate for that behaviour, thus
//# enabling the processing of binary data stored in a String Object, and it also adds some useful String methods
//# for performing such operations.
//# Also provided are some useful methods for encoding/decoding to/from various internet formats, such as
//# Hexadecimal, Base64, and Quoted Printable, as well as MD5 and SHA computation and ARCFOUR encryption/decryption.
//#
//# --------------------------------------------------------------------------------------------------------------------
//# References:
//# - RFC2045: Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
//# http://www.rfc-editor.org/rfc/rfc2045.txt
//# (contains definitions of Base64 and Quoted Printable data representation).
//#
//# - RFC1321: The MD5 Message-Digest Algorithm
//# http://www.rfc-editor.org/rfc/rfc1321.txt
//#
//# - FIPS PUB 180-2: Secure Hash Standard (SHS)
//# http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf
//#
//# - RFC3174: US Secure Hash Algorithm 1 (SHA1)
//# http://www.rfc-editor.org/rfc/rfc3174.txt
//#
//# - RFC2104: HMAC: Keyed-Hashing for Message Authentication
//# http://www.rfc-editor.org/rfc/rfc2104.txt
//#
//# - ARCFOUR: A Stream Cipher Encryption Algorithm "Arcfour"
//# http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt
//#
//# --------------------------------------------------------------------------------------------------------------------
//# Notes:
//# - In most cases, the String Objects manipulated by the methods provided here will contain BINARY data,
//# not to be interpreted as text. If you do not understand what this is about, then you probably won't
//# need this package...
//#
//# - Interpreting Strings as Byte arrays should be familiar to you if you used to program in FORTRAN or
//# ASSEMBLER or so, where it was in fact the other way around. In FORTRAN you would use a BYTE array to
//# store strings. And when I say BYTE then of course I mean LOGICAL*1, but I prefer BYTE since I have a
//# |D|I|G|I|T|A|L| background, programming PDPs and VAXes (lucky me).
//#
//# - For file i/o the FileSystemObject is needed and the i/o should of course be done in Ascii mode,
//# not in Unicode (as far as I can find out the WScript StdIn/StdOut/StdErr streams are in Ascii mode).
//#
//# - The FileSystemObject supports only sequential i/o, so you are still a little bit restricted,
//# and you should NOT use ReadLine or WriteLine methods for binary i/o.
//# NOTE: the built-in ReadAll method of TextStream Objects does NOT always return a correct result when it must
//# be interpreted as binary data! (it probably does something with bytes of which it THINKS they are newlines).
//# it is better (and much easier) to use the methods provided by THIS library to read or write entire files.
//# For reading large files you should write something to process it in blocks, using the stream.Read(blocksize)
//# method.
//#
//# - This package is for handling binary data read from a file as a string of bytes, not Strings containing text.
//# The 'byteAt' method will return -1 if special characters are encountered that cannot be converted to a byte
//# value, leading to incorrect and meaningless results.
//# For handling String Objects containing TEXT with other Unicode Characters than those few that can be converted
//# to byte values you should use the to7bit/from7bit or the toURLtext/fromURLtext methods provided in this package.
//#
//# - This package contains some methods for Base64 and Quoted-Printable encode/decoding.
//# Both are designed for transmission of data containing special (non-ascii) characters via a communication
//# channel that cannot handle or does not allow such characters. This is achieved by encoding them using
//# normal ascii-characters.
//# Quoted Printable is intended for encoding PLAIN TEXT containing SOME special characters, and Base64 is
//# to be used for encoding raw BINARY data (which can be interpreted as LOTS of special characters!).
//# Since, ultimately, text is also stored as binary data, both methods CAN be used for either sort of data.
//# Best practice is however to use Quoted Printable for PLAIN TEXT and Base64 for anything else.
//# Quoted Printable has a special way of handling line terminators (which is necessary because not all platforms
//# use the same way of internally storing a 'new line') so encoding+decoding MAY give output not exactly
//# equal to the original input. For plain text that would be no real problem, s
//# ince you can eas
//# ily con
//# tinue reading and understand a text even if there would be some extra line te
//# rminators or so, but binary data would become corrupted.
//#
//# - In JavaScript, the standard Objects have a CONSTRUCTOR and they can have INSTANCES.
//# The Constructor is merely the definition of the object type and it may contain some initialisation code
//# for new Object Instances when they are created.
//# 'String' is the Constructor for the String Object and the statement x="abc" creates an Instance of the
//# String Object, identified by its name 'x' and holding the value "abc".
//# Methods added to the Constructor of the String Object should be used as normal functions and they are not
//# available as methods to individual Object Instances. Their input can be via function arguments only and
//# they usually return a String Object Instance as their result.
//# Methods added to the 'prototype' property of the String Object become available to each individual
//# variable that is a String Object Instance and they can (and usually will) operate on the actual value of
//# that specific Instance and return a value of arbitrary type which is not necessarily a String.
//# So methods and properties of the Constructor are general purpose functions not being part of each individual
//# Object Instance and methods and properties of the Prototype become part of each individual Object Instance.
//#
//# EXAMPLES (given that 'fromCharCode' is a Constructor method and 'charCodeAt' is a Prototype method):
//#
//# var x = String.fromCharCode(13,10) creates a String Object Instance named 'x'
//# holding the good old CRLF combination as its value.
//#
//# var a = "Henk" creates a String Object Instance named 'a' with value "Henk"
//# var n = a.charCodeAt(1) creates a Number Object Instance named 'n' with value 101 (the "e")
//# var b = a.fromCharCode(65) this will produce an ERROR message and the script will halt
//# ('fromCharCode' belongs to the Constructor, not to the Instance)
//#
//#
//# - In binary arithmetic, numerical byte values are usually stored with the lowest order bit at the lowest bit
//# address and the highest order bit at the highest bit address (little-endian bit notation). The highest order
//# bit is called leftmost and the lowest order bit is called rightmost, like in normal numerical notation.
//# The bitwise left-shift and right-shift operations refer to these directions.
//#
//# - When talking about addresses, the only meaningful indication of a direction is 'low-to-high' or 'high-to-low',
//# referring to the numerical values of the addresses. Since memory is not topological, terms like 'left-to-right'
//# or so are meaningless. When drawing a table on paper to visualise a portion of memory, you can do it in any
//# direction you like, be it from left to right, from right to left, from top to bottom, or from bottom to top.
//# In different books you can find all variants.
//#
//# - About big-endian & little-endian words
//# Since a byte can store (unsigned) numbers from 0 to 255, more bytes are needed to store larger numbers.
//# For example: for storing the number: 23433 = (91 * 256) + 137, two bytes are needed, where 91 is the high
//# order value and 137 the low order. But now we have a small problem: should they be stored
//# as 91,137 (i.e. the high order byte at the low address and the low order byte at the high address) or
//# as 137,91 (i.e. the low order byte at the low address and the high order byte at the high address) ?
//# In fact, both sequences are actually used on various computer systems. The sequence where the low byte
//# is at the low address is called "little-endian", and the other one is called "big-endian".
//# Most modern computer platforms use the little-endian convention, but big-endian is also frequently used
//# (especially on IBM mainframes). In THIS script, whenever I say "word", I mean the little-endian notation,
//# unless explicitly stated otherwise (the Secure Hash Algorithm [RFC3174] [FIPS PUB 180-2] uses big-endian).
//#
//# - You should take good notice of the difference between Internet order and Numerical order when representing
//# binary data as a textual string of digits. We usually write numbers with the highest order digit at the left
//# side and the lowest order digit at the right. In little-endian binary notation that's not different. Since
//# computers are actually designed to crunch numbers, it is convenient to use "numerical" order for internal
//# storage of numbers. Ascii strings however are stored with each character as a numerical value in one single
//# byte with the first (leftmost) character at the lowest address and the last (rightmost) character at the
//# highest address. So for Numbers the addresses are determined by the right-to-left SIGNIFICANCE of the digits
//# and for Strings they are determined by the left-to-right POSITION within the string. For transmission of data,
//# the actual numerical value is not relevant and then it is easier not to interpret the data but simply
//# address the individual bytes from low to high, which is called Internet order.
//# For example: (to improve readability some blanks are inserted in the numerical representation)
//#
//# internal storage at (relative) byte addresses: byte3 byte2 byte1 byte0
//# binary representation of the (decimal) number 123456789 is: 00000111 01011011 11001101 00010101
//# NUMERICAL hexadecimal representation is 07 5b cd 15: 0 7 5 b c d 1 5
//#
//# In Internet order bytes are addressed from low to high: byte0 byte1 byte2 byte3
//# but WITHIN the bytes it's still numerical order: 00010101 11001101 01011011 00000111
//# so hex notation in INTERNET order is 15 cd 5b 07: 1 5 c d 5 b 0 7
//#
//# the Ascii string "ABCD" is internally stored as: byte0 byte1 byte2 byte3
//# "A" "B" "C" "D"
//# and the corresponding binary byte values are: 01000001 01000010 01000011 01000100
//# which in hex notation is 41 42 43 44: 4 1 4 2 4 3 4 4
//#
//# interpreting that binary pattern as a NUMBER gives: byte3 byte2 byte1 byte0
//# 01000100 01000011 01000010 01000001
//# which is decimal 1,145,258,561 and hex 44 43 42 41: 4 4 4 3 4 2 4 1
//#
//# --------------------------------------------------------------------------------------------------------------------
//# Properties added to the Constructor of the String Object:
//# ---------------------------------------------------------
//#
//# String.CRLF, String.CR, String.LF
//#
//# guess what?
//#
//#
//# String.ByteTable
//#
//# INTENDED FOR INTERNAL USE ONLY. DO NOT MODIFY THIS.
//# this is a 256 character String made up of the byte values 0 through 255.
//# String.ByteTable.charAt(byte) returns the corresponding character.
//#
//#
//# String.Base64chars
//#
//# INTENDED FOR INTERNAL USE ONLY. DO NOT MODIFY THIS.
//# this is the set of characters used for base64 encoding/decoding.
//#
//#
//# String.HashPad512
//# String.MD5table
//#
//# INTENDED FOR INTERNAL USE ONLY. DO NOT MODIFY THIS.
//# HashPad512 is for padding messages in MD5, SHA1, or SHA256; it is a single one-bit plus 511 zero-bits.
//# MD5table is the "T" array as defined in RFC1321; for performance reasons it has been defined as a
//# static Array instead of recomputing it every time when an MD5 is computed; it has been computed as
//# follows (where two32 equals 2 raised to the power 32):
//# for (var T = [], i = 0; i < 64; T[i++] = Math.floor(Math.abs(Math.sin(i)) * two32) );
//#
//# --------------------------------------------------------------------------------------------------------------------
//# Methods added to the Constructor of the String Object:
//# ------------------------------------------------------
//#
//# String.randomGenerator = Math.random
//#
//# the String.random method (below) uses String.randomGenerator to obtain random numbers
//# between 0 (inclusive) and 1 (exclusive).
//# By default it is just another name for the built-in Math.random method, but you can redefine it
//# to use another random number generator, which SHOULD return random real numbers in [0,1)
//# For example you could use a MersenneTwister Object (see hr$mersenntwister.js) as follows:
//#
//#
//#
//# Please note that the MersenneTwister Object also has a method to generate random Strings, but those
//# strings will be reproducible (and thus predictable) if the same seed is used to init the MersenneTwister
//# Object. The String.random method below always includes a hashed timestamp, in an attempt to make it
//# unpredictable. Even better is to create some entropy pool based on events that are fully out of control
//# of the software, for example the user's mouse and keyboard events and their timing.
//# (I am planning to make a script to do just that.)
//#
//#
//# String.random = function random(length)
//#
//# returns a random string of 7-bit characters from the same set as used for base64.
//# it is made up of the base64 encoded MD5 of a time stamp and a series of randomly generated characters.
//# the minimum length of the result is 44 characters (twice the size of the timestamp part).
//# this has little to do with binary string handling, but it is provided here for completeness.
//# the result can be used to generate keys for the arcfour encoding/decoding provided in this library.
//# Please note that NEITHER the built-in Math.random method NOR the Mersenne Twister is considered
//# cryptographycally secure! For cryptographic purposes a random string should not only be statistically
//# good, but also unpredictable and the algorithm should never reproduce the same string.
//#
//#
//# String.fromByte(byte)
//#
//# converts a single byte value to its corresponding character.
//#
//#
//# String.fromBytes([byte1[, byte2[, ...[, byteN]]]])
//#
//# accepts any number of arguments, interprets them as byte values, and returns a String
//# made up of those byte values (similar to the standard 'String.fromCharCode' method).
//# extension w.r.t. fromCharCode: each argument can be either a byte value OR AN ARRAY OF BYTE VALUES.
//#
//# EXAMPLE:
//# String.fromBytes(13,10)
//# or: String.fromBytes(0x0d,0x0a) yields the good old CRLF combination
//#
//#
//# String.fromWord (wordsize, value)
//# String.beFromWord(wordsize, value)
//#
//# converts a single word value (see 'fromWords' below) to a binary string.
//# fromWord = little-endian, beFromWord = big-endian.
//#
//#
//# String.fromWords (wordsize, [word1[, word2[, ...[, wordN]]]])
//# String.beFromWords(wordsize, [word1[, word2[, ...[, wordN]]]])
//#
//# similar to 'fromBytes', but accepts binary values larger than 1 byte. wordsize is interpreted
//# as the number of bytes in each value and each value will be converted to 'wordsize' bytes.
//# fromWords uses little-endian notation, beFromWords uses big-endian notation.
//# if a value is larger than what fits in wordsize bytes then the high order remainder is ignored.
//# NOTE: JavaScript stores numbers with a 52 bit mantissa, so the maximum wordsize = 6 bytes.
//# (in practice you will probably use only 2 and 4).
//#
//# EXAMPLE:
//# String.fromWords(2,10*256+13) yields the good old CRLF combination
//# or: String.fromWords(2,0x0a0d) (note the little-endian NUMERICAL order of the hex digits)
//#
//# String.fromWords (4,0x44434241,0x64636261) yields "ABCDabcd" (little-endian)
//# String.befromWords(4,0x44434241,0x64636261) yields "DCBAdcba" (big-endian)
//#
//# String.fromHex([hexstring1[, hexstring2[, ...[, hexstringN]]]])
//#
//# accepts any number of printable hexadecimal strings (in internet order) and converts them
//# to binary internal storage as one large string of byte values. arguments can be either a
//# hexadecimal string or an array of such strings.
//#
//# EXAMPLE:
//# String.fromHex("0d0a") yields the good old CRLF combination, (0d = CR, 0a = LF)
//# (please note the INTERNET order of the hex digits)
//#
//# NOTE: there is also a fromHex method added to the Prototype, which acts on individual
//# String Object Instances only (and this one uses that one to translate each argument).
//# DO NOT CONFUSE THEM !!!
//#
//#
//# String.fromBase64([b64string1[, b64string2[, ...[, b64stringN]]]])
//#
//# accepts any number of base-64 encoded strings and converts them to binary internal storage as one
//# large string of byte values. arguments can be either a b64 string or or an array of such strings.
//# (see RFC2045).
//#
//# NOTE: there is also a fromBase64 method added to the Prototype, which acts on individual
//# String Object Instances only (and this one uses that one to translate each argument).
//# DO NOT CONFUSE THEM !!!
//#
//#
//# String.toQuotedPrintable([string1[, string2[, ...[, stringN]]]])
//#
//# accepts any number of strings and encodes them to quoted printable.
//# result is not a String Object but an Array of String Objects, each element being one line
//# of QP-encoded text. each input argument can be a string or an array of strings.
//# (see RFC2045).
//#
//# NOTE: there is also a toQuotedPrintable method added to the Prototype, which acts on individual
//# String Object Instances only (and this one uses that one to translate each argument).
//# DO NOT CONFUSE THEM !!!
//#
//#
//# String.fromQuotedPrintable([qpr1[, qpr2[, ...[, qprN]]]])
//#
//# accepts any number of quoted printable encoded strings and converts them to normal strings.
//# result is not a String Object but an Array of String Objects, each element being one line
//# of the original text that was encoded. each input argument can be a QPencoded string or an
//# array of such strings (as produced by String.prototype.toQuotedPrintable).
//# (see RFC2045).
//#
//# NOTE: there is also a fromQuotedPrintable method added to the Prototype, which acts on individual
//# String Object Instances only (and this one uses that one to translate each argument).
//# DO NOT CONFUSE THEM !!!
//#
//# --------------------------------------------------------------------------------------------------------------------
//# Methods added to the prototype of the String Object:
//# ----------------------------------------------------
//#
//# String.prototype.byteAt(pos)
//#
//# similar to the standard 'charCodeAt' method, but returns the byte value as a Number from 0 to 255.
//# if the given position of the string contains an unrecognised Unicode character then -1 is returned.
//#
//# EXAMPLES:
//# "ABCD".byteAt(0) yields 65
//# "xy€z".byteAt(2) yields 128
//#
//#
//# String.prototype.wordAt (pos,wordsize)
//# String.prototype.beWordAt(pos,wordsize)
//#
//# returns the binary value of a word taken from the string at given position and given size.
//# wordAt = little-endian, beWordAt = big-endian
//#
//#
//# String.prototype.toBytes()
//#
//# returns an Array with all byte values of the string's characters.
//#
//# EXAMPLES:
//# "ABCD".toBytes() yields [65,66,67,68]
//# "xy€z".toBytes() yields [120,121,128,122]
//#
//#
//# String.prototype.toWords (wordsize)
//# String.prototype.beToWords(wordsize)
//#
//# interprets the entire string as raw data consisting of a series of words of 'wordsize' bytes
//# toWords = little-endian, beToWords = big-endian.
//#
//# EXAMPLE:
//# "ABCD".toWords(2) yields [0x4241,0x4443] (little-endian)
//# "ABCD".beToWords(2) yields [0x4142,0x4344] (big-endian)
//#
//#
//# --------------------------------------------------------------------------------------------------------------------
//# MIME (and other) encoding/decoding w/o encryption:
//# --------------------------------------------------
//#
//# String.prototype.to7bit()
//# String.prototype.from7bit()
//# String.prototype.toURLtext()
//# String.prototype.fromURLtext()
//#
//# these 4 methods do encoding/decoding to and from 7 bit printable ascii text of a String.
//# these function can be used to convert a String containing text with very special characters,
//# especially Strings with Unicode characters that cannot be converted to 8-bits.
//# the to7bit and from7bit are a weaker version of the javascript built-in escape/unescape methods,
//# converting only the non-printables, the "%", and the non-7-bit values (from7bit is identical to unescape).
//# the URL variants are a stronger version of escape/unescape,
//# they also do the space/"+" conversion used in URL's, which the escape/unescape methods don't.
//#
//#
//# String.prototype.toHex(sep)
//#
//# translates the binary content of the string to a printable string of hexadecimal digits.
//# conversion is done in internet order.
//# the 'sep' argument is optional, if given then any hex digits are removed from it and the remainder
//# is used as a spearator between the individual byte values.
//#
//# EXAMPLES:
//# "ABCD".toHex() yields "41424344"
//# "ABCD".toHex(",") yields "41,42,43,44"
//#
//#
//# String.prototype.fromHex()
//#
//# assumes the string is a printable hexadecimal string (in internet order) and returns a string
//# made up of the corresponding byte values.
//# allows reasonably free input format, all single commas and all patterns of non-hex characters are
//# used as substring separator, blank substrings are translated to null bytes and all odd-length
//# substrings will have a "0" prepended to it (allowing single digit byte values).
//#
//# EXAMPLES:
//# "0d0a".fromHex() yields the good old CRLF combination
//# "0d,0a".fromHex() yields the good old CRLF combination
//# "d,a".fromHex() yields the good old CRLF combination
//# "d,,a".fromHex() yields a CR + a null byte + a LF
//# "dgg0a".fromHex() yields the good old CRLF combination
//# "dgg0,a".fromHex() yields a CR + a null byte + a LF
//#
//# NOTE: there is also a fromHex method added to the Constructor, which accepts input via
//# function arguments only (but it uses this one for the actual translation).
//# DO NOT CONFUSE THEM !!!
//#
//#
//# String.prototype.toBase64()
//#
//# translates the binary content of the string to an Array of Base64 encoded printable strings.
//# each returned array element holds 76 base64 characters (except the last one, which may be shorter).
//# (see RFC2045).
//#
//# EXAMPLE:
//# var b64 = datastring.toBase64()
//# WriteLine (b64.join(String.CRLF)) outputs the base64 result in standard internet format
//#
//#
//# String.prototype.fromBase64()
//#
//# translate a single base-64 encoded string to a string containing the corresponding binary data.
//# (see RFC2045).
//#
//# NOTE: there is also a fromBase64 method added to the Constructor,
//# which accepts input via function arguments only.
//# DO NOT CONFUSE THEM !!!
//#
//#
//# String.prototype.toQuotedPrintable()
//#
//# translates the content of the string to an Array of Quoted Printable encoded strings (see RFC2045).
//# each returned array element is a string of up to 76 characters.
//# (see RFC2045).
//#
//#
//# String.prototype.fromQuotedPrintable()
//#
//# translates one single line of Quoted Printable encode text to normal text and returns an Array
//# Array Object with the resulting text in element 0 and a boolean end-of-line flag in element 1.
//# Quoted Printable ENcoding splits long lines into smaller portions of one String each and it has
//# a special way to mark the hard end of line. As long as that hard end of line is not seen all
//# consecutive input should be concatenated to one single decoded result line.
//# (see RFC2045).
//#
//# NOTE: there is also a fromQuotedPrintable method added to the Constructor, which accepts input
//# via function arguments only (but it uses this one for the actual translation).
//# DO NOT CONFUSE THEM !!!
//#
//#
//# --------------------------------------------------------------------------------------------------------------------
//# Hashing algorithms:
//# -------------------
//#
//# String.prototype.MD5()
//#
//# returns the MD5 value of a string. (see RFC1321).
//# result is a string holding the raw binary result, which for textual representation
//# still needs to be converted to hexadecimal or base64 or whatever format is needed.
//#
//# String.prototype.SHA1()
//# String.prototype.SHA256()
//#
//# return a String's Secure Hash according to the Secure Hash Standard FIPS180-2.
//# result is a string holding the raw binary result, which for textual representation
//# still needs to be converted to hexadecimal or base64 or whatever format is needed.
//#
//# String.prototype.HMAC (hashfun, key)
//#
//# returns a keyed hash conform RFC2104.
//# hashfun should be a String with the name of the hash function (i.e. "MD5", "SHA1", or "SHA256")
//# if it equals "" then it defaults to "SHA256".
//# key should be a String with the key to use, preferable 64 bytes long (the blocksize of the
//# hashing algorithm), as recommended in the RFC.
//#
//# EXAMPLE (from rfc2104):
//# message = "what do ya want for nothing?"
//# key = "Jefe"
//# hash = message.HMAC (key, "MD5")
//# hash.toHex() => 750c783e6ab0b503eaa86e310a5db738
//#
//# String.prototype.hashtext ( [hashfun [, key] ] )
//#
//# creates a textual and reasonably pronounceable text from a message's hash. It computes the hash and uses
//# that as the seed for a MersenneTwister Object, thus causing it to reproduce the same sequence if invoked
//# for the same message once again. Then it creates a RandomTextGenerator Object with the MersenneTwister's
//# 'random' method as its random number generator. This RandomTextGenerator is then used to produce a
//# phrase of several nonsense words. Essentially, this phrase is a textual hash of the original message.
//# It will be reasonably pronounceable according to Dutch pronunciation rules. The length of the phrase is
//# based on the size of the hash. This method is intended to be used when users may need to do a visual
//# check if two message hashes are the same. By translating it to readable and pronounceable text the
//# comparison will be much easier.
//#
//# hashfun = the name of the hash method to be used, either "MD5", "SHA1", "SHA256"
//# this is an optional argument, if omitted it defaults to "SHA256"
//# key = if this argument is given, then the hash will be done using HMAC with this key and the given
//# hash function. if this argument is omitted or a null string then hashfun is used as is.
//#
//# EXAMPLES (based on the RandomTextGenerator100 version 1-00 from 07-JAN-2005):
//#
//# "Henk.Reints".hashtext()
//# => "Pite tra, eirfed putifble aadfou veo, irhiarmenmij umzie guphe ja ungt wordou ou old ho to."
//#
//# "Henk Reints".hashtext()
//# => "Huinwo gwolen ij la eo, eu ugpek ja fea nulra tha ofisijsla ea eo hia nij foef rijnzork ea."
//#
//# "Henk Reints".hashtext("SHA1")
//# => "Aungstarp hei erwauw wedwaglei trie zuis, ria ikabderia."
//#
//# "Henk Reints".hashtext("MD5")
//# => "Haufuigta swo buje ou, kiekep ligza oetnear ia."
//#
//# "Henk Reints".hashtext("MD5","e pur si muove")
//# => "Op aupoud ooppog okgo aundga fre nou epga tit."
//#
//# PREREQUISITE:
//# hr$mersennetwister.js and hr$randomtext1-00.js must be included before hr$binstring.js.
//# the constructors of the MersenneTwister and the RandomTextGenerator Objects must both have been
//# defined before running this script. If either one of them is missing, then the hashtext method
//# will be unavailable.
//#
//# --------------------------------------------------------------------------------------------------------------------
//# ARCFOUR encryption/decryption:
//# ------------------------------
//#
//# String.prototype.arcfour(passphrase)
//# String.prototype.arcfourEncode(passphrase)
//# String.prototype.arcfourDecode(passphrase)
//#
//# methods for arcfour encoding and decoding of a string.
//# the arcfour method is intended for internal use only. it performs the arcfour algorithm using the
//# byte values of the string, not allowing encoding of special Unicode characters that cannot be converted
//# to byte values. by apllying the arcfour algorithm with the same passphrase on its own result, the
//# original text should be returned.
//# (see also http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt
//# or use any internet search engine with keyword "arcfour")
//#
//# the arcfourEncode and -Decode methods are wrappers around arcfour itself, using the built-in
//# javascript escape and unescape functions, allowing any String to be encoded and the result to be
//# transmitted via a 7-bit channel.
//#
//# a good method is to combine the passphrase with a random once-only text
//# ('passphrase' is actually the same as 'password', but it can contain blanks as well),
//# so that encoding of the same text yields a different result every time.
//# the once-only part of the key should be transmitted together with the encoded result
//# or, even better, as a separate message at a later time or via another channel.
//# the passphrase itself should be kept secret, you should only share it with intended and
//# trusted recipients via a secure channel!
//#
//# EXAMPLE:
//# sender:
//# message = "Albert Einstein: My wife doesn't understand me..."
//# passphrase = "Gott wuerfelt nicht."
//# keyonce = String.random(64)
//# encoded = message.arcfourEncode(keyonce+passphrase)
//# // transmit 'keyonce' and 'encoded' to recipient via internet
//# // call him by phone to tell him the exact passphrase
//# recipient:
//# message = encoded.arcfourDecode(keyonce+passphrase)
//#
//# String.prototype.arcfourEncrypt(passphrase[,keylen])
//# String.prototype.arcfourDecrypt(passphrase)
//#
//# these methods do more or less (more less than more) what the above example shows.
//# the 'arcfourEncrypt' method generates a random key using String.random(keylen),
//# (keylen is optional, if omitted it reverts to the default of String.random).
//# this key is intermixed with the passphrase.
//# it returns the generated key (w/o the passphrase) + CRLF + the encoded message.
//# the 'arcfourDecrypt' method accepts such input and decodes it.
//#
//# String.prototype.arcfourEncodeHashed (passphrase [, hashfun] )
//# String.prototype.arcfourDecodeHashed (passphrase [, hashfun] )
//# String.prototype.arcfourEncryptHashed (passphrase [, hashfun [, keylen] ] )
//# String.prototype.arcfourDecryptHashed (passphrase [, hashfun] )
//#
//# these methods do the arcfour stuff including a hash of the original message, thus allowing an
//# integrity check when decoding. the encode/encrypt methods simply include the message's hash in
//# their result. the decode/decrypt methods split the decoded result into hash and message and then
//# check if the hash is ok. the decode/decrypt methods return an unnamed Object with two properties:
//# 'value' = the decoded message, 'ok' = a boolean indicating if the hash check was OK or not.
//# hashfun is an optional argument specifying the name of the hash function to be used ("MD5", "SHA1",
//# or "SHA256"). if omitted or a null string then it defaults to "SHA256".
//#
//# EXAMPLE:
//# theSecret = "The world goes round and round."
//# encrypted = theSecret.arcfourEncodeHashed("NobodyKnowsThisExceptYouAndMe")
//#
//# decrypted = encrypted.arcfourDecodeHashed("NobodyKnowsThisExceptMeAndYou") // wrong!
//# WScript.Echo(decrypted.value) => an incorrectly decoded unreadable string containing nonsense
//# WScript.Echo(decrypted.ok ) => false
//#
//# decrypted = encrypted.arcfourDecodeHashed("NobodyKnowsThisExceptYouAndMe") // good!
//# WScript.Echo(decrypted.value) => "The world goes round and round."
//# WScript.Echo(decrypted.ok ) => true
//#
//# --------------------------------------------------------------------------------------------------------------------
//# file I/O methods:
//# -----------------
//#
//# String.prototype.ReadFile (fso)
//# String.prototype.CreateFile (fso, data, overwrite)
//#
//# These methods perform binary file I/O by reading or writing ENTIRE files at once.
//# They use the String itself as the file specification (path) to be read or written.
//# 'ReadFile' returns the full uninterpreted content of the file,
//# 'CreateFile' writes 'data' to a new file. The 'overwrite' argument is a boolean that determines
//# whether or not to overwrite any existing file, it is an optional argument, default value = 'false'.
//# In all 3 methods, _YOU_ (i.e. the calling script) must supply a FileSystemObject in the 'fso' argument.
//# All I/O is in uninterpreted binary mode as far as is possible in JavaScript, with one exception: if the
//# 'data' argument is an Array, then each Array element will be written as a normal String _WITH_ a
//# trailing new line after every array element (so nothing binary at all). In other cases: if data is
//# not a String Object then its own 'toString' method will be used implicitly by JavaScript.
//#
//# These methods do not perform error checking, so they will cause a fatal script termination if you supply
//# incorrect data (e.g. if attempting to read a non-existing file or). You can embed the method invocation
//# in a try/catch structure to prevent errors being fatal and take corrective actions in your script.
//#
//# EXAMPLES:
//# fso = WScript.CreateObject ("Scripting.FileSystemObject")
//# path = "C:\temp\test.dat"
//# data = String.fromBytes (byte0, byte1, etc.)
//# path.CreateFile (fso, data) // writes data to c:\temp\test.dat w/o trailing newline
//# temp = path.ReadFile (fso) // reads binary content of c:\temp\test.dat into temp
//# if (temp != data) WScript.Echo("error!")
//#
//# try
//# { temp = path.CreateFile (fso, data) // will fail since file exists
//# }
//# catch (e)
//# { // interpret 'e' to find out what error occurred and take appropriate corrective action
//# }
//#
//# fso.DeleteFile(path)
//# temp = path.ReadFile (fso) // causes a fatal script error
//#
//# NOTE:
//# When you read an entire file using the built-in 'ReadAll' method of the TextStream Object, it does not
//# always return the correct BINARY file content, as I found out during testing of my SHA1 method (it cost
//# me quite a lot of headache to find out that it was this built-in method that caused all the trouble).
//# Instead of 'stream.ReadAll()', the 'ReadFile' method uses 'stream.Read(file.Size)', which appears
//# to return the correct result as far as I can find out.
//#
//# ====================================================================================================================
//# ====================================================================================================================
// ---------------------------------------------
// properties added to the String Object itself:
// ---------------------------------------------
String.CRLF = String.fromCharCode(13,10)
String.CR = String.fromCharCode(13)
String.LF = String.fromCharCode(10)
String.ByteTable // conversion table determined empirically by reading a binary file containing 0 throug 255
= unescape
("%00%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F"
+" !\"#$%25&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~%7F"
+"%u20AC%81%u201A%u0192%u201E%u2026%u2020%u2021%u02C6%u2030%u0160%u2039%u0152%8D%u017D%8F%90"
+"%u2018%u2019%u201C%u201D%u2022%u2013%u2014%u02DC%u2122%u0161%u203A%u0153%9D%u017E%u0178"
+"%A0%A1%A2%A3%A4%A5%A6%A7%A8%A9%AA%AB%AC%AD%AE%AF%B0%B1%B2%B3%B4%B5%B6%B7%B8%B9%BA%BB%BC%BD%BE%BF"
+"%C0%C1%C2%C3%C4%C5%C6%C7%C8%C9%CA%CB%CC%CD%CE%CF%D0%D1%D2%D3%D4%D5%D6%D7%D8%D9%DA%DB%DC%DD%DE%DF"
+"%E0%E1%E2%E3%E4%E5%E6%E7%E8%E9%EA%EB%EC%ED%EE%EF%F0%F1%F2%F3%F4%F5%F6%F7%F8%F9%FA%FB%FC%FD%FE%FF"
)
String.Base64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
// HashPad512 is a single "1" bit plus 511 "0" bits, left justified
// in hex it is 0x80 padded with 63 times 0x00, byte code 0x80 corresponds to unicode %u20AC (euro-sign "€")
// MD5table is the "T" array needed for MD5 computation as defined in RFC1321, computed as follows:
// for (var T = [], i = 0; i < 64; T[i++] = Math.floor(Math.abs(Math.sin(i)) * two32) );
// (where two32 equals 2 raised to the power 32)
String.HashPad512 = unescape("%u20AC") + (new Array(64)).join(String.fromCharCode(0))
String.MD5table
= [3614090360,3905402710, 606105819,3250441966,4118548399,1200080426,2821735955,4249261313
,1770035416,2336552879,4294925233,2304563134,1804603682,4254626195,2792965006,1236535329
,4129170786,3225465664, 643717713,3921069994,3593408605, 38016083,3634488961,3889429448
, 568446438,3275163606,4107603335,1163531501,2850285829,4243563512,1735328473,2368359562
,4294588738,2272392833,1839030562,4259657740,2763975236,1272893353,4139469664,3200236656
, 681279174,3936430074,3572445317, 76029189,3654602809,3873151461, 530742520,3299628645
,4096336452,1126891415,2878612391,4237533241,1700485571,2399980690,4293915773,2240044497
,1873313359,4264355552,2734768916,1309151649,4149444226,3174756917, 718787259,3951481745
]
// ------------------------------------------------------------------------------------------------------
// next is intended for internal use only! it is not documented above. it list available hash functions
// and which one is the default, and a method to check a given hash function name:
// ------------------------------------------------------------------------------------------------------
String.hashFuns = "/MD5/SHA1/SHA256/"
String.defaultHashFun = "SHA256"
String.checkHashFun = function checkHashFun(hashfun,caller)
{ var hfun = "" + hashfun
if (hfun == "") hfun = String.defaultHashFun
if (String.hashFuns.indexOf("/"+hfun+"/") >= 0) return hfun
throw "Invalid hash function '" + hfun + "' for hr$binstring.js " + caller
}
// ------------------------------------------
// methods added to the String Object itself:
// ------------------------------------------
String.randomGenerator = Math.random
String.random = function random(length)
{ var C = String.Base64chars
var T = new Date(), t = T.toString().split(" "), M = T.getMilliseconds(), L = T.toLocaleString()
var x = [t[0],t[2],t[1],t[5],t[3]+"."+("000"+M).slice(-3),t[4],L].join(" ")
var X = x.MD5().toBase64().join("").replace(/=/g,"")
var r = "", i=0, j=0, Lr=Math.max(length,2*X.length)
for (; i < Lr;
r += ((i++)&1 && j 0; v = v * 256 + x.byteAt(--j) );
return v
}
String.prototype.beWordAt = function beWordAt(pos,wordsize)
{ for (var x = this.substr(pos,wordsize), v = 0, j = 0; j < x.length; v = v * 256 + x.byteAt(j++) );
return v
}
String.prototype.toBytes = function toBytes()
{ for (var result = [], k = 0, i = 0; i < this.length; result[k++] = this.byteAt(i++) );
return result
}
String.prototype.toWords = function toWords(wordsize)
{ for (var result = [], k = 0, i = 0; i < this.length; result[k++] = this.wordAt(i,wordsize), i+=wordsize);
return result
}
String.prototype.beToWords = function beToWords(wordsize)
{ for (var result = [], k = 0, i = 0; i < this.length; result[k++] = this.beWordAt(i,wordsize), i+=wordsize);
return result
}
// ----------------------------------------------------
// methods for (MIME or other) encoding w/o encryption:
// ----------------------------------------------------
String.prototype.to7bit = function to7bit()
{ var r="",c,b,i
for(i=0;i126?escape(c):c));
return r
}
String.prototype.from7bit = function from7bit()
{ return unescape(this)
}
String.prototype.toURLtext= function toURLtext()
{ return escape(this).replace(/\+/g,"%2B").replace(/%20/g,"+")
}
String.prototype.fromURLtext = function fromURLtext()
{ return unescape(this.replace(/\+/g," "))
}
String.prototype.toHex = function toHex(sep)
{ var S = (arguments.length > 0 ? (""+sep).replace(/[0-9A-Fa-f]+/g,"") : ""), s = ""
for (var result="", i=0; i < this.length; result+=s+("0"+this.byteAt(i++).toString(16)).slice(-2),s=S);
return result
}
// -------------------------------------------------------------------------------------------------------------
// in the fromHex function we'll allow a reasonably free format. every single comma or non-hex pattern is
// interpreted as a substring separator. if a substring is blank (between commas) it is interpreted as a single
// byte with value 0 (so ",,," represents a 32 bit zero). if a substring has odd length a "0" will be PREpended
// to it, mainly to allow bytes represented by single hex digits separated by non-hex characters (longer
// substrings SHOULD have an even length)
// -------------------------------------------------------------------------------------------------------------
String.prototype.fromHex = function fromHex()
{ if (this.length == 0) return ""
for (var result = "", A = this.replace(/[^0-9A-Fa-f,]+/g,",").split(","), i = 0; i < A.length; i++)
{ var L = A[i].length, H = (L < 1 ? "00" : L%2 == 1 ? "0" + A[i] : A[i])
for (var j=0; j < H.length; result += String.ByteTable.charAt(parseInt(H.slice(j++,++j),16)) );
}
return result
}
String.prototype.toBase64 = function toBase64()
{ var C = String.Base64chars + "="
var L = this.length, M = L - L % 3, R = [], r = ""
for (var k = 0, i = 0, t = 0; i < M; )
{ r += C.charAt( (this.byteAt(i)&0xff) >>>2)
r += C.charAt(((this.byteAt(i)&0x03) << 4) | ((this.byteAt(++i)&0xf0) >>> 4))
r += C.charAt(((this.byteAt(i)&0x0f) << 2) | ((this.byteAt(++i)&0xc0) >>> 6))
r += C.charAt(this.byteAt(i++)&0x3f)
if (r.length == 76) {R[k++] = r; r = ""}
}
if (M < L)
{ r += C.charAt((this.byteAt(M)&0xff) >>>2)
r += C.charAt((this.byteAt(M)&0x03) << 4 | (++M < L ? (this.byteAt(M)&0xf0) >>> 4 : 0))
r += C.charAt(M < L ? (this.byteAt(M)&0x0f) << 2 : 64)
r += "="
}
if (r != "") R[k++] = r
return R
}
String.prototype.fromBase64 = function fromBase64()
{ var C = String.Base64chars
var Q = [], R = ""
for (var k = 0, i = 0; i < this.length; i++)
{ var c = C.indexOf(this.charAt(i))
if (c >= 0) Q[k++] = c
if (Q.length == 4)
{ R += String.ByteTable.charAt( ( Q[0] << 2) | (Q[1] >>> 4) )
R += String.ByteTable.charAt( ( (Q[1]&0x0f) << 4) | (Q[2] >>> 2) )
R += String.ByteTable.charAt( ( (Q[2]&0x03) << 6) | Q[3] )
Q = [], k = 0
}
}
if (Q.length > 1) R += String.ByteTable.charAt ( ( Q[0] << 2) | (Q[1] >>> 4) )
if (Q.length > 2) R += String.ByteTable.charAt ( ( (Q[1]&0x0f) << 4) | (Q[2] >>> 2) )
return R
}
String.prototype.toQuotedPrintable = function toQuotedPrintable()
{ var R = [], r = "", k = 0
function pad (x) {if (r.length + x.length < 76) {r += x} else {R[k++] = r + "="; r = x} }
for (var i = 0; i < this.length; i++)
{ var c = this.byteAt(i)
if (c > 31 && c != 61 && c < 127) pad (this.charAt(i))
else pad ("=" + (0x100+c).toString(16).slice(-2).toUpperCase())
}
if (i == 0) {R[k++] = "" }
else if (r.slice(-1) != " ") {R[k++] = r }
else if (r.length < 74) {R[k++] = r.slice( 0,-1) + "=20"}
else {R[k++] = r.slice( 0,74) + "="
;R[k++] = r.slice(74,-1) + "=20"}
return R
}
String.prototype.fromQuotedPrintable = function fromQuotedPrintable()
{ var c, R = "", L = this.replace(/\s+$/,"").length, eol = this.charAt(--L) != "="; if (eol) L++
for (var i = 0; i < L; c = this.charAt(i++),
R += (c != "=" ? c : String.ByteTable.charAt(parseInt(this.slice(i++,++i),16))) );
return [R,eol]
}
// --------------------------------------------------------
// Hashing algorithms (they all operate in byte mode only):
// --------------------------------------------------------
String.prototype.MD5 = function MD5()
{ var m = 0x100000000, L=this.length, L1=L%64, L0=L-L1, L2=64-L1, len=L*8, llo=len%m, lhi=(len-llo)/m
var pad = String.HashPad512.slice(0,1+((959-(len&511))&511)>>>3) + String.fromWords(4,llo,lhi)
var N = (L+pad.length)/4, M=0xffffffff, A=0x67452301, B=0xefcdab89, C=0x98badcfe, D=0x10325476
var Q = [7,12,17,22,5,9,14,20,4,11,16,23,6,10,15,21], T = String.MD5table
function blk(k,x) {return k>> (32 - n) ) ) & M}
function S (f,a,b,c,d) {return (b + R (a + f(b,c,d) + W[P] + T[J], Q[((J>>>4)<<2)|(J++)&3] ) )&M}
for (var k = 0; k < N; k += 16)
{ var AA = A, BB = B, CC = C, DD = D, J = 0, W = blk(k<<2,this).toWords(4)
for (var P=15,i=0; i<4; A=S(F,A,B,C,D), D=S(F,D,A,B,C), C=S(F,C,D,A,B), B=S(F,B,C,D,A), i++);
for (var P=12,i=0; i<4; A=S(G,A,B,C,D), D=S(G,D,A,B,C), C=S(G,C,D,A,B), B=S(G,B,C,D,A), i++);
for (var P= 2,i=0; i<4; A=S(H,A,B,C,D), D=S(H,D,A,B,C), C=S(H,C,D,A,B), B=S(H,B,C,D,A), i++);
for (var P= 9,i=0; i<4; A=S(I,A,B,C,D), D=S(I,D,A,B,C), C=S(I,C,D,A,B), B=S(I,B,C,D,A), i++);
A = (A + AA) & M; B = (B + BB) & M; C = (C + CC) & M; D = (D + DD) & M;
}
return String.fromWords(4,A,B,C,D)
} // Please note that the sample c-program of the MD5 algorithm in rfc1321 is SEVENTEEN PAGES!
// -------------------------------------------------------------------------------------------------------------
// SHA1 padding is the same as for MD5, except for the last two words (MD5 uses little endian, SHA big endian);
// the core is coded w/o any function calls, which reduces computation time significantly (factor 2).
// (maybe I'll rewrite MD5 all inline as well. some time.)
//
// NOTE 1:
// http://csrc.nist.gov/cryptval/shs/sha1-vectors.zip gives a lot of test messages and their SHA1 values.
// I've tested them all successfully with the implementation below (only the byte-mode samples).
//
// NOTE 2:
// RFC3174 defines f(t;B,C,D) for 0<=t<20 as: (B AND C) OR ((NOT B) AND D)
// FIPS180-2 defines f(t;x,y,z) for 0<=t<20 as: Ch(x,y,z) which is: (x AND y) XOR ( NOT x AND z)
// RFC3174 defines f(t;B,C,D) for 40<=t<60 as: (B AND C) OR (B AND D) OR (C AND D)
// FIPS180-2 defines f(t;x,y,z) for 40<=t<60 as: Maj(x,y,z) which is: (x AND y) XOR (x AND z) XOR (y AND z)
// My tests (mentioned above) have passed with _BOTH_ variants! I've implemented the FIPS180-2 thing below,
// considering the FIPS document as the primary source having precedence over the RFC.
// the table below shows that both are in fact equivalent:
// x,y,z (x&y)|((~x)&z) (x&y)^((~x)&z) (x&y)|(x&z)|(y&z) (x&y)^(x&z)^(y&z)
// ----- -------------- -------------- ----------------- -----------------
// 0,0,0 0 0 0 0
// 0,0,1 1 1 0 0
// 0,1,0 0 0 0 0
// 0,1,1 1 1 1 1
// 1,0,0 0 0 0 0
// 1,0,1 0 0 1 1
// 1,1,0 1 1 1 1
// 1,1,1 1 1 1 1
// -------------------------------------------------------------------------------------------------------------
String.prototype.SHA1 = function SHA1()
{ var m = 0x100000000, L=this.length, L1=L%64, L0=L-L1, L2=64-L1, len=L*8, llo=len%m, lhi=(len-llo)/m
var pad = String.HashPad512.slice(0,1+((959-(len&511))&511)>>>3) + String.beFromWords(4,lhi,llo)
var N = (L+pad.length)/4, M=0xffffffff, t,X,A,B,C,D,E, k,k4,W,w
var H0 = 0x67452301, H1 = 0xefcdab89, H2 = 0x98badcfe, H3 = 0x10325476, H4 = 0xc3d2e1f0
var K0 = 0x5a827999, K1 = 0x6ed9eba1, K2 = 0x8f1bbcdc, K3 = 0xca62c1d6
for (k = 0; k < N; k += 16)
{ k4 = k<<2
W =(k4>>31) );
A=H0, B=H1, C=H2, D=H3, E=H4, t=0
for(;t<20;){X=(((A<<5)|(A>>>27))+((B&C)^((~B)&D)) +E+W[t++]+K0)&M,E=D,D=C,C=(B<<30)|(B>>>2),B=A,A=X}
for(;t<40;){X=(((A<<5)|(A>>>27))+(B^C^D) +E+W[t++]+K1)&M,E=D,D=C,C=(B<<30)|(B>>>2),B=A,A=X}
for(;t<60;){X=(((A<<5)|(A>>>27))+((B&C)^(B&D)^(C&D))+E+W[t++]+K2)&M,E=D,D=C,C=(B<<30)|(B>>>2),B=A,A=X}
for(;t<80;){X=(((A<<5)|(A>>>27))+(B^C^D) +E+W[t++]+K3)&M,E=D,D=C,C=(B<<30)|(B>>>2),B=A,A=X}
H0 = (H0 + A) & M; H1 = (H1 + B) & M; H2 = (H2 + C) & M; H3 = (H3 + D) & M; H4 = (H4 + E) & M;
}
return String.beFromWords(4,H0,H1,H2,H3,H4)
}
// -------------------------------------------------------------------------------------------------------------
// SHA256 padding is the same as SHA1 padding.
// Coding it all inline - instead of the well-structured thing with function calls - gained a speed factor 3.
// Code is comform FIPS180-2 (see notes above about 'Ch' and 'Maj').
// -------------------------------------------------------------------------------------------------------------
String.prototype.SHA256 = function SHA256()
{ var m = 0x100000000, L=this.length, L1=L%64, L0=L-L1, L2=64-L1, len=L*8, llo=len%m, lhi=(len-llo)/m
var pad = String.HashPad512.slice(0,1+((959-(len&511))&511)>>>3) + String.beFromWords(4,lhi,llo)
var N = (L+pad.length)/4, M=0xffffffff, k,k4,blk,W,t
var K = [0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
,0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
,0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
,0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
,0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
,0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070
,0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
,0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
]
var H0 = 0x6a09e667, H1 = 0xbb67ae85, H2 = 0x3c6ef372, H3 = 0xa54ff53a
var H4 = 0x510e527f, H5 = 0x9b05688c, H6 = 0x1f83d9ab, H7 = 0x5be0cd19
for (k = 0; k < N; k += 16)
{ k4 = k<<2
blk = (k4>>17)|(x<<15))^((x>>>19)|(x<<13))^(x>>>10)
var y = W[t-15], sigma0y = ((y>>> 7)|(y<<25))^((y>>>18)|(y<<14))^(y>>> 3)
W[t] = (sigma1x + W[t-7] + sigma0y + W[t-16] )&M
}
var a = H0, b = H1, c = H2, d = H3, e = H4, f = H5, g = H6, h = H7
for (t = 0; t < 64; t++)
{ var SIGMA1e = ((e>>> 6)|(e<<26))^((e>>>11)|(e<<21))^((e>>>25)|(e<< 7))
var SIGMA0a = ((a>>> 2)|(a<<30))^((a>>>13)|(a<<19))^((a>>>22)|(a<<10))
var Ch_efg = (e&f)^((~e)&g)
var Maj_abc = (a&b)^(a&c)^(b&c)
var T1 = h + SIGMA1e + Ch_efg + K[t] + W[t]
var T2 = SIGMA0a + Maj_abc
h = g, g = f, f = e, e = (d+T1)&M, d = c, c = b, b = a, a = (T1+T2)&M
}
H0=(H0+a)&M,H1=(H1+b)&M,H2=(H2+c)&M,H3=(H3+d)&M,H4=(H4+e)&M,H5=(H5+f)&M,H6=(H6+g)&M,H7=(H7+h)&M
}
return String.beFromWords(4,H0,H1,H2,H3,H4,H5,H6,H7)
}
// ----------------------------------------------------------------------------------------------------
// the HMAC method sets the hash function blocksize B hard-coded to 64 bytes (ok for MD5, SHA1, SHA256)
// which will need more sophistication when other hash functions are implemented:
// ----------------------------------------------------------------------------------------------------
String.prototype.HMAC = function HMAC (hashfun, key)
{ var hfun = String.checkHashFun(hashfun,"HMAC")
var B = 64
var H = new Function ("x", "return x." + hfun + "()")
var K = (key.length > B ? H(key) : key); K += (new Array(1+B-K.length)).join(String.fromByte(0))
for (var Ki = "", i = 0; i < B; Ki += String.fromByte(K.byteAt(i)^0x36), i++); // Ki = K xor ipad
for (var Ko = "", i = 0; i < B; Ko += String.fromByte(K.byteAt(i)^0x5c), i++); // Ko = K xor opad
return H (Ko + H (Ki + this) )
}
// the hashtext method will only be available if both MersenneTwister
// and RandomTextGenerator100 have already been defined:
if ( (typeof MersenneTwister == "function") && (typeof RandomTextGenerator100 == "function") )
{
String.prototype.hashtext = function hashtext (hashfun, key)
{ var na = arguments.length, hfun = String.checkHashFun( (na < 1 ? "" : hashfun), "hashtext")
var seed = (na > 1 && key != "" ? this.HMAC(hfun,key) : eval("this."+hfun+"()") ).beToWords(4)
var mt = new MersenneTwister(seed.shift(),seed)
return (new RandomTextGenerator100(function(){return mt.random()})).Zin(13+seed.length*11)
}
}
// ------------------------------------------
// ARCFOUR encryption and decryption methods:
// ------------------------------------------
String.prototype.arcfour = function arcfour(passphrase)
{ var r="", k=""+passphrase, L=k.length, s,t,i,j,m
for (s=[],i=0; i<256; s[i]=i++);
for (i=0 ,j=0; i<256; j=(j+s[i]+k.charCodeAt(i%L))&255, t=s[i],s[i++]=s[j],s[j]=t); k=""
for (i=0 ,j=0,m=0; m 1 ? keylen : 0)
var Lk = k.length, Lp = passphrase.length, L = Math.max(Lk,Lp)
for (var kp = "", i = 0; i < L; kp += passphrase.charAt(i%Lp)+k.charAt(i%Lk), i++);
return k + String.CRLF + this.arcfourEncode(kp)
}
String.prototype.arcfourDecrypt = function arcfourDecrypt(passphrase)
{ var i = this.indexOf(String.CRLF), k = this.slice(0,i)
var Lk = k.length, Lp = passphrase.length, L = Math.max(Lk,Lp)
for (var kp = "", i = 0; i < L; kp += passphrase.charAt(i%Lp)+k.charAt(i%Lk), i++);
return this.slice(i+String.CRLF.length).arcfourDecode(kp)
}
String.prototype.arcfourEncodeHashed = function arcfourEncodeHashed(passphrase,hashfun)
{ var hfun = String.checkHashFun( (arguments.length < 2 ? "" : hashfun), "arcfourEncodeHashed")
return (eval("this."+hfun+"()").toBase64()+"|"+this).arcfourEncode(passphrase)
}
String.prototype.arcfourDecodeHashed = function arcfourDecodeHashed(passphrase,hashfun)
{ var hfun = String.checkHashFun( (arguments.length < 2 ? "" : hashfun), "arcfourDecodeHashed")
var x = this.arcfourDecode(passphrase), m = x.indexOf("|"), h = x.slice(0,m), y = x.slice(++m)
return {value: y, ok: (eval("y."+hfun+"()").toBase64() == h ? true : false) }
}
String.prototype.arcfourEncryptHashed = function arcfourEncryptHashed(passphrase,hashfun,keylen)
{ var hfun = String.checkHashFun( (arguments.length < 2 ? "" : hashfun), "arcfourEncryptHashed")
var temp = (eval("this."+hfun+"()").toBase64()+"|"+this)
return (arguments.length < 3 ? temp.arcfourEncrypt(passphrase) : temp.arcfourEncrypt(passphrase,keylen))
}
String.prototype.arcfourDecryptHashed = function arcfourDecryptHashed(passphrase,hashfun)
{ var hfun = String.checkHashFun( (arguments.length < 2 ? "" : hashfun), "arcfourDecryptHashed")
var x = this.arcfourDecrypt(passphrase), m = x.indexOf("|"), h = x.slice(0,m), y = x.slice(++m)
return {value: y, ok: (eval("y."+hfun+"()").toBase64() == h ? true : false) }
}
// -----------------
// file I/O methods:
// -----------------
String.prototype.ReadFile = function ReadFile (fso)
{ var file = fso.GetFile(this)
var inp = file.OpenAsTextStream(1,0) // ForReading,AsciiMode
var data = inp.Read(file.Size) // 'ReadAll' does _NOT_ give the correct result!
inp.Close()
return data
}
String.prototype.CreateFile = function CreateFile (fso, data, overwrite)
{ var out = fso.CreateTextFile (this, (overwrite ? true : false), false) // arg3 = false => ascii mode
if (data.constructor == Array)
out.Write (data.join(String.CRLF) + String.CRLF)
else out.Write (data) // do _NOT_ use 'WriteLine' !!!
out.Close()
}
// ---------------------------------------------------------------------------------------------------------------------
// Finally, there's a bonus!
// The methods below convert an Array of Numbers to a String representation of the Array in JavaScript syntax,
// where each word is truncated to the given number of bits (8, 16, or 32) and represented in '0x' hexadecimal
// numerical notation, e.g. if an Array would contain the values 13, 35, and 65535, then toHex32() returns
// "[0x0000000d,0x00000023,0x0000ffff]", which can be re-interpreted as normal JavaScript code for an Array definition.
// 'toHex$' is intended for internal use only; the 'bits' argument MUST be a multiple of 4, with 4 <= bits <= 32.
// ---------------------------------------------------------------------------------------------------------------------
Array.prototype.toHex32 = function toHex32() {return this.toHex$(32)}
Array.prototype.toHex16 = function toHex16() {return this.toHex$(16)}
Array.prototype.toHex8 = function toHex8 () {return this.toHex$( 8)}
Array.prototype.toHex$ = function toHex$(bits)
{ var D = -bits/4, M = 0xffffffff>>>(32-bits), R = M+1, r = "[", i = 0
for (; i < this.length; r += (i>0?",":"") + "0x" + (R+(this[i++]&M)).toString(16).slice(D) );
return r + "]"
}
//* ====================================================================================================================
//* [end of file] hr$binstring.js -- Copyright (c) 2004,2005 Henk Reints (http://henk-reints.nl)
//* --------------------------------------------------------------------------------------------