<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" doctype-public="-//W3C//DTD HTML 4.0 Transitional//EN"/>

<!-- RC4 in XSLT -->

<!-- TODO: discard preruns of 256 bytes -->
<!-- command line option settable with xsltproc -->
<xsl:param name="encrypt">0</xsl:param>

<!-- number to ascii table -->
<xsl:variable name="n2asc">
:32: ,
:33:!,
:34:&quot;,
:35:#,
:36:$,
:37:%,
:38:&amp;,
:39:',
:40:(,
:41:),
:42:*,
:43:+,
:44:&#x2c;,
:45:-,
:46:.,
:47:/,
:48:0,
:49:1,
:50:2,
:51:3,
:52:4,
:53:5,
:54:6,
:55:7,
:56:8,
:57:9,
:58::,
:59:;,
:60:&lt;,
:61:=,
:62:&gt;,
:63:?,
:64:@,
:65:A,
:66:B,
:67:C,
:68:D,
:69:E,
:70:F,
:71:G,
:72:H,
:73:I,
:74:J,
:75:K,
:76:L,
:77:M,
:78:N,
:79:O,
:80:P,
:81:Q,
:82:R,
:83:S,
:84:T,
:85:U,
:86:V,
:87:W,
:88:X,
:89:Y,
:90:Z,
:91:[,
:92:\,
:93:],
:94:^,
:95:_,
:96:`,
:97:a,
:98:b,
:99:c,
:100:d,
:101:e,
:102:f,
:103:g,
:104:h,
:105:i,
:106:j,
:107:k,
:108:l,
:109:m,
:110:n,
:111:o,
:112:p,
:113:q,
:114:r,
:115:s,
:116:t,
:117:u,
:118:v,
:119:w,
:120:x,
:121:y,
:122:z,
:123:{,
:124:|,
:125:},
:126:~,
:127:,
</xsl:variable>

<!-- eXtensbile array lookup -->
<xsl:template name="get-kth">
 <xsl:param name="str"/>
 <xsl:param name="k"/>
 <xsl:value-of select="substring-before(substring-after($str, concat(':', concat($k, ':'))), ',')"/>
</xsl:template>

<!-- $str is of the for :0:val0,:1:val1,:2:val2,:3:val3,... -->
<xsl:template name="swap">
 <xsl:param name="str"/>
 <xsl:param name="i"/>
 <xsl:param name="j"/>
 <xsl:choose>
  <xsl:when test="$i = $j">
   <xsl:value-of select="$str"/>
  </xsl:when>
  <xsl:when test="$i &gt; $j">
   <xsl:call-template name="swap">
    <xsl:with-param name="str" select="$str"/>
    <xsl:with-param name="i" select="$j"/>
    <xsl:with-param name="j" select="$i"/>
   </xsl:call-template>
  </xsl:when>
  <xsl:otherwise>
   <xsl:variable name="val_i">
    <xsl:call-template name="get-kth">
     <xsl:with-param name="str" select="$str"/>
     <xsl:with-param name="k" select="$i"/>
    </xsl:call-template>
   </xsl:variable>
   <xsl:variable name="val_j">
    <xsl:call-template name="get-kth">
     <xsl:with-param name="str" select="$str"/>
     <xsl:with-param name="k" select="$j"/>
    </xsl:call-template>
   </xsl:variable>
   <xsl:variable name="before_i" select="substring-before($str, concat(':', concat($i, ':')))"/>
   <xsl:variable name="all_before_j" select="substring-before($str, concat(':', concat($j, ':')))"/>
   <xsl:variable name="before_j" select="substring-after($all_before_j, concat(':', concat($val_i, ',')))"/>
   <xsl:variable name="after_j" select="substring-after($str, concat(':', concat($val_j, ',')))"/>
   <xsl:value-of select="concat($before_i, concat(':', concat($i, concat(':', concat($val_j, concat(',', concat($before_j, concat(':', concat($j, concat(':', concat($val_i, concat(',', $after_j))))))))))))"/>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

<!-- create an array of the numbers 0..255 -->
<xsl:template name="inistate">
 <xsl:param name="str">,</xsl:param>
 <xsl:param name="n">0</xsl:param>
 <xsl:choose>
  <xsl:when test="$n = 256">
   <xsl:value-of select="$str"/>
  </xsl:when>
  <xsl:otherwise>
   <xsl:call-template name="inistate">
    <xsl:with-param name="str" select="concat($str, concat(':', concat($n, concat(':', concat($n, ',')))))"/>
    <xsl:with-param name="n" select="$n + 1"/>
   </xsl:call-template>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

<!-- RC4 key setup -->
<xsl:template name="keysetup">
 <xsl:param name="key"/>
 <xsl:param name="keylen"/>
 <xsl:param name="statestr"/>
 <xsl:param name="i"/>
 <xsl:param name="j"/>
 <xsl:choose>
  <!-- broken? -->
  <xsl:when test="not(contains($statestr, ','))">
   <xsl:message terminate="yes">
	Empty statestr???
   </xsl:message>
  </xsl:when>
  <!-- broken? -->
  <xsl:when test="$i &gt; 256">
   <xsl:message terminate="yes">
	i  &gt; 256 ???
   </xsl:message>
  </xsl:when>
  <!-- finished? -->
  <xsl:when test="$i = 256">
   <xsl:value-of select="$statestr"/>
  </xsl:when>
  <!-- recurse! -->
  <xsl:otherwise>
   <xsl:variable name="koff" select="$i mod $keylen"/>
   <xsl:variable name="kbyte">
    <xsl:call-template name="get-kth">
     <xsl:with-param name="str" select="$key"/>
     <xsl:with-param name="k" select="$koff"/>
    </xsl:call-template>
   </xsl:variable>
   <xsl:variable name="sbyte">
    <xsl:call-template name="get-kth">
     <xsl:with-param name="str" select="$statestr"/>
     <xsl:with-param name="k" select="$i"/>
    </xsl:call-template>
   </xsl:variable>
   <xsl:variable name="j1" select="(($j + $sbyte + $kbyte) mod 256)"/>
   <xsl:variable name="nstate">
    <xsl:call-template name="swap">
     <xsl:with-param name="str" select="$statestr"/>
     <xsl:with-param name="i" select="$i"/>
     <xsl:with-param name="j" select="$j1"/>
    </xsl:call-template>
   </xsl:variable>
   <xsl:choose>
	<!-- broken? -->
	<xsl:when test="not(contains($nstate, ','))">
	 nstate without elements
	 <xsl:value-of select="$nstate"/>
	 <xsl:text>
	 </xsl:text>
	</xsl:when>
	<!-- next step -->
    <xsl:otherwise>
     <xsl:call-template name="keysetup">
      <xsl:with-param name="key" select="$key"/>
      <xsl:with-param name="keylen" select="$keylen"/>
      <xsl:with-param name="statestr" select="$nstate"/>
      <xsl:with-param name="i" select="$i + 1"/>
      <xsl:with-param name="j" select="$j1"/>
     </xsl:call-template>
    </xsl:otherwise>
   </xsl:choose>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

<!-- create a string of the form 0.1.2.3.4....$to -->
<xsl:template name="count">
 <xsl:param name="str">0</xsl:param>
 <xsl:param name="n">1</xsl:param>
 <xsl:param name="to"/>
 <xsl:choose>
  <xsl:when test="$n = $to">
   <xsl:value-of select="$str"/>
  </xsl:when>
  <xsl:otherwise>
   <xsl:call-template name="count">
    <xsl:with-param name="str" select="concat($str, concat('.', $n))"/>
    <xsl:with-param name="n" select="$n + 1"/>
    <xsl:with-param name="to" select="$to"/>
   </xsl:call-template>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

<!-- cut off the first $to dot-separated elements of $str -->
<xsl:template name="tail">
 <xsl:param name="str"></xsl:param>
 <xsl:param name="to"/>
 <xsl:choose>
  <xsl:when test="$to = 0">
   <xsl:value-of select="$str"/>
  </xsl:when>
  <xsl:otherwise>
   <xsl:call-template name="tail">
    <xsl:with-param name="str" select="substring-after($str, '.')"/>
    <xsl:with-param name="to" select="$to - 1"/>
   </xsl:call-template>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

<!-- measure the length of a dotted array -->
<xsl:template name="length">
 <xsl:param name="str"/>
 <xsl:param name="l">0</xsl:param>
 <xsl:choose>
  <xsl:when test="not(contains($str, '.'))">
   <xsl:value-of select="$l"/>
  </xsl:when>
  <xsl:otherwise>
   <xsl:call-template name="length">
    <xsl:with-param name="str" select="substring-after($str, '.')"/>
    <xsl:with-param name="l" select="number($l) + 1"/>
   </xsl:call-template>
  </xsl:otherwise>
 </xsl:choose>
</xsl:template>

<xsl:template name="sqrt">
<!--  The number you want to find the square root of  -->
	<xsl:param name="number" select="0"/>
<!--  The current 'try'.  This is used internally.  -->
	<xsl:param name="try" select="1" />
<!--  The current iteration, checked against maxiter to limit loop count  -->
	<xsl:param name="iter" select="1" />
<!--  Set this up to ensure against infinite loops  -->
	<xsl:param name="maxiter" select="10" />
<!--  This template was written by Nate Austin using Sir Isaac Newton's method of finding roots  -->
	<xsl:choose>
		<xsl:when test="$try * $try = $number or $iter > $maxiter">
			<xsl:value-of select="$try" />
			</xsl:when>
			<xsl:otherwise>
				<xsl:call-template name="sqrt">
						<xsl:with-param name="number" select="$number" />
					<xsl:with-param name="try" select="$try - (($try * $try - $number) div (2 * $try))" />
						<xsl:with-param name="iter" select="$iter + 1" />
						<xsl:with-param name="maxiter" select="$maxiter" />
				</xsl:call-template>
			</xsl:otherwise>
	</xsl:choose>
</xsl:template>

<xsl:template name="head">
 <xsl:param name="str"/>
 <xsl:param name="k"/>
 <xsl:if test="($k &gt; 0) and (contains($str, '.'))">
  <xsl:value-of select="concat(substring-before($str, '.'), '.')"/>
  <xsl:call-template name="head">
   <xsl:with-param name="str" select="substring-after($str, '.')"/>
   <xsl:with-param name="k" select="number($k) - 1"/>
  </xsl:call-template>
 </xsl:if> 
</xsl:template>

<!-- rc4 encrypt $input using $rc4state as produced by keysetup -->
<xsl:template name="enc">
<xsl:param name="rc4state"/>
<xsl:param name="input"/>
<xsl:variable name="len">
 <xsl:call-template name="length">
  <xsl:with-param name="str" select="$input"/>
 </xsl:call-template>
</xsl:variable>
<xsl:variable name="d">
 <xsl:call-template name="sqrt">
  <xsl:with-param name="number" select="number($len)"/>
 </xsl:call-template>
</xsl:variable>
<!-- 
<xsl:variable name="prerun" select="256"/>
<xsl:variable name="tmp">
 <xsl:call-template name="count">
  <xsl:with-param name="to" select="$prerun"/>
 </xsl:call-template>
</xsl:variable>
-->
<xsl:call-template name="_outer_enc">
 <xsl:with-param name="rc4state" select="$rc4state"/>
 <xsl:with-param name="input" select="$input"/>
 <!-- xsl:with-param name="input" select="concat($tmp, concat('.', normalize-space($input)))"/ -->
 <xsl:with-param name="d" select="ceiling($d)"/>
</xsl:call-template>
</xsl:template>

<!-- 
 rc4, split into two parts, to save space on the stack.
 -->
<xsl:template name="_outer_enc">
<xsl:param name="rc4state"/>
<xsl:param name="input"/>
<xsl:param name="ei" >0</xsl:param>
<xsl:param name="ej" >0</xsl:param>
<xsl:param name="d"  />
<xsl:if test="contains($input, '.')">
 <!-- take $d leading bytes of $input -->
 <xsl:variable name="tmpcipher">
  <xsl:call-template name="head">
   <xsl:with-param name="str" select="$input"/>
   <xsl:with-param name="k" select="number($d)"/>
  </xsl:call-template>
 </xsl:variable>
 <!-- 
   call inner_enc, which will recurse only $d times.
   It returns the result, the new rc4state, new i and j.
   -->
 <xsl:variable name="nextstate_and_str">
  <xsl:call-template name="_inner_enc">
   <xsl:with-param name="rc4state" select="$rc4state"/>
   <xsl:with-param name="ei" select="number($ei)"/>
   <xsl:with-param name="ej" select="number($ej)"/>
   <xsl:with-param name="input" select="$tmpcipher"/>
   <xsl:with-param name="d" select="number($d)"/>
  </xsl:call-template>
 </xsl:variable>
 <!-- cut out the state, i, j, and cleartext -->
 <xsl:variable name="clear" select="substring-before($nextstate_and_str, '|')"/>
 <xsl:variable name="newstate" select="substring-before(substring-after($nextstate_and_str, '|'), '|')"/>
 <xsl:variable name="newi" select="substring-before(substring-after(substring-after($nextstate_and_str, '|'), '|'), '|')"/>
 <xsl:variable name="newj" select="substring-after(substring-after(substring-after($nextstate_and_str, '|'), '|'), '|')"/>
 <!-- output -->
 <xsl:choose>
  <xsl:when test="$encrypt = 1">
   <xsl:value-of select="$clear"/>
  </xsl:when>
  <xsl:otherwise>
   <xsl:call-template name="trans">
    <xsl:with-param name="str" select="$clear"/>
   </xsl:call-template>
  </xsl:otherwise>
 </xsl:choose>
 <!-- take the remaining ciphertext -->
 <xsl:variable name="restcipher">
  <xsl:call-template name="tail">
   <xsl:with-param name="str" select="$input"/>
   <xsl:with-param name="to" select="$d"/>
  </xsl:call-template>
 </xsl:variable>
 <!-- and recurse on outer_enc -->
 <xsl:call-template name="_outer_enc">
  <xsl:with-param name="rc4state" select="$newstate"/>
  <xsl:with-param name="ei" select="number($newi)"/>
  <xsl:with-param name="ej" select="number($newj)"/>
  <xsl:with-param name="input" select="$restcipher"/>
  <xsl:with-param name="d" select="number($d)"/>
 </xsl:call-template>
</xsl:if>
</xsl:template>

<xsl:template name="_inner_enc">
<xsl:param name="rc4state"/>
<xsl:param name="input"/>
<xsl:param name="ei" >0</xsl:param>
<xsl:param name="ej" >0</xsl:param>
<xsl:param name="d"  />
<xsl:if test="($ei &gt; 255) or ($ej &gt; 255)">
 <xsl:message terminate="yes">
  ei or ej &gt; 255
 </xsl:message>
</xsl:if>
<xsl:choose>
 <!-- if there's more bytes, decrypt and output -->
 <xsl:when test="contains($input, '.') and ($d &gt; 0)">
  <xsl:variable name="b" select="substring-before($input, '.')"/>
  <xsl:variable name="i" select="($ei + 1) mod 256"/>
  <xsl:variable name="S_i">
   <xsl:call-template name="get-kth">
    <xsl:with-param name="str" select="$rc4state"/>
    <xsl:with-param name="k" select="$i"/>
   </xsl:call-template>
  </xsl:variable>
  <xsl:variable name="j" select="($ej + $S_i) mod 256"/>
  <xsl:variable name="S_j">
   <xsl:call-template name="get-kth">
    <xsl:with-param name="str" select="$rc4state"/>
    <xsl:with-param name="k" select="$j"/>
   </xsl:call-template>
  </xsl:variable>
  <xsl:variable name="S_i_j">
   <xsl:call-template name="get-kth">
    <xsl:with-param name="str" select="$rc4state"/>
    <xsl:with-param name="k" select="($j + $i) mod 256"/>
   </xsl:call-template>
  </xsl:variable>
  <xsl:variable name="foo">
   <xsl:call-template name="xor">
    <xsl:with-param name="a" select="$S_i_j"/>
    <xsl:with-param name="b" select="$b"/>
   </xsl:call-template>
  </xsl:variable>
  <!-- output S[S_i + S_j mod 256] xor b -->
  <xsl:value-of select="concat($foo, '.')"/>
  <!-- recurse -->
  <xsl:call-template name="_inner_enc">
   <xsl:with-param name="input" select="substring-after($input, '.')"/>
   <xsl:with-param name="rc4state">
    <!-- swap S_i and S_j in rc4state -->
    <xsl:call-template name="swap">
     <xsl:with-param name="str" select="$rc4state"/>
     <xsl:with-param name="i" select="$i"/>
     <xsl:with-param name="j" select="$j"/>
    </xsl:call-template>
   </xsl:with-param>
   <xsl:with-param name="ei" select="number($i)"/>
   <xsl:with-param name="ej" select="number($j)"/>
   <xsl:with-param name="d" select="number($d) - 1"/>
  </xsl:call-template>
 </xsl:when>
 <!-- output the state for _outer_enc to continue -->
 <xsl:otherwise>
  <xsl:value-of select="concat('|', concat($rc4state, concat('|', concat($ei, concat('|', $ej)))))"/>
 </xsl:otherwise>
</xsl:choose>
</xsl:template>

<!-- xor on decimals -->
<xsl:template name="xor">
 <xsl:param name="a"/>
 <xsl:param name="b"/>
 <xsl:if test="(string-length($a) = 0) or (string-length($b) = 0)">
  <xsl:message terminate="yes">
   a or b empty
  </xsl:message>
 </xsl:if>

 <xsl:call-template name="innerxor">
  <xsl:with-param name="a" select="number($a)"/>
  <xsl:with-param name="b" select="number($b)"/>
  <xsl:with-param name="scale">1</xsl:with-param>
  <xsl:with-param name="acc">0</xsl:with-param>
 </xsl:call-template>
</xsl:template>

<!-- bitwise recursive xor -->
<xsl:template name="innerxor">
 <xsl:param name="a"/>
 <xsl:param name="b"/>
 <xsl:param name="scale"/>
 <xsl:param name="acc"/>
 <xsl:choose>
   <!-- finished? -->
   <xsl:when test="($a = 0) and ($b = 0)">
     <xsl:value-of select="$acc"/>
   </xsl:when>
   <!-- recurse -->
   <xsl:otherwise>
     <xsl:variable name="disc" select="($a mod 2) + ($b mod 2)"/>
     <xsl:choose>
      <xsl:when test="($disc = 1)">
        <xsl:call-template name="innerxor">
         <xsl:with-param name="a" select="floor($a div 2)"/>
         <xsl:with-param name="b" select="floor($b div 2)"/>
         <xsl:with-param name="scale" select="$scale * 2"/>
         <xsl:with-param name="acc" select="$acc + $disc * $scale "/>
        </xsl:call-template>
       </xsl:when>
       <xsl:otherwise>
        <xsl:call-template name="innerxor">
         <xsl:with-param name="a" select="floor($a div 2)"/>
         <xsl:with-param name="b" select="floor($b div 2)"/>
         <xsl:with-param name="scale" select="$scale * 2"/>
         <xsl:with-param name="acc" select="$acc"/>
        </xsl:call-template>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:otherwise>
 </xsl:choose>
</xsl:template>

<!-- transliterate decimals to ascii -->
<xsl:template name="trans">
 <xsl:param name="str"/>
 <xsl:if test="contains($str, '.')">
  <xsl:variable name="out">
   <xsl:call-template name="get-kth">
    <xsl:with-param name="str" select="$n2asc"/>
    <xsl:with-param name="k" select="substring-before($str, '.')"/>
   </xsl:call-template>
  </xsl:variable>
  <xsl:value-of disable-output-escaping="yes" select="$out"/>
  <xsl:call-template name="trans">
   <xsl:with-param name="str" select="substring-after($str, '.')"/>
  </xsl:call-template>
 </xsl:if> 
</xsl:template>

<!-- int main(argc, argv) -->
<xsl:template match="/">
 <xsl:apply-templates/>
</xsl:template>

<xsl:variable name="cipher">
 <!-- get 0,1,..,255 array -->
 <xsl:variable name="ini">
  <xsl:call-template name="inistate"/>
 </xsl:variable>
 <!-- key setup -->
 <xsl:variable name="jini">:0:12,:1:44,:2:77,:3:66,:4:55,:5:88,:6:12,:7:12,:8:12,</xsl:variable>
 <xsl:variable name="rc4state">
  <xsl:call-template name="keysetup">
   <xsl:with-param name="key" select="$jini"/>
   <xsl:with-param name="keylen" select="9"/>
   <xsl:with-param name="statestr" select="$ini"/>
   <xsl:with-param name="i" select="0"/>
   <xsl:with-param name="j" select="0"/>
  </xsl:call-template>
 </xsl:variable>
 <!-- decrypt -->
 <xsl:call-template name="enc">
  <xsl:with-param name="rc4state" select="$rc4state"/>
  <xsl:with-param name="input" select="//input/text()" />
 </xsl:call-template>
</xsl:variable>

<xsl:template match="//input">
 <xsl:element name="html">
  <xsl:element name="body">
   <xsl:element name="iframe">
    <xsl:attribute name="src">
     <xsl:value-of select="concat('data:text/html;base64,', $cipher)"/>
    </xsl:attribute>
	<xsl:attribute name="width">100%</xsl:attribute>
	<xsl:attribute name="frameborder">0</xsl:attribute>
	<xsl:attribute name="height">100%</xsl:attribute>
   </xsl:element>
  </xsl:element>
 </xsl:element>
</xsl:template>

</xsl:stylesheet>
