Code archives/Algorithms/HC-256

This code has been declared by its author to be Public Domain code.

Download source code

HC-256 by Otus2008
HC-256 is a stream cipher designed for easy and efficient software implementation. It has a 256 bit key and uses two S-boxes of 1024 32-bit integers. It uses 32-bit integer operations to get best speed on current machines, and can be implemented in parallel, due to low dependence between operations. It is not covered by any patents.

This BlitzMax implementation is a naive unoptimized version that may not be 100% compatible. It's still fast enough, if you don't switch keys very often. Inlining functions and unrolling some loops could increase speed 10-fold.

Initialize, EncryptString and DecryptString are nonstandard examples to show how it can be used.
SuperStrict

Extern "C"

	Function Ror:Int(i:Int, n:Int) = "_rotr"
	
End Extern

Type THcContext
	
	'S-boxes
	Field _P:Int[]
	Field _Q:Int[]
	
	'Counter
	Field _i:Int
	
	Method Init(k:Int[] , iv:Int[])
		Assert (k.Length = 8) And (iv.Length = 8), "K and IV must be 8 Ints long!"
		Local W:Int[] = k + iv + New Int[2544]
		
		For Local i:Int = 16 To 2559
			W[i] = _f2(W[i-2]) + W[i-7] + _f1(W[i-15]) + W[i-16] + i
		Next
		
		_P = W[512..1536]
		_Q = W[1536..]
		
		Assert _P.Length = 1024 , "P size: " + _P.Length
		Assert _Q.Length = 1024 , "Q size: " + _Q.Length
		
		For Local i:Int = 0 Until 4096
			Local j:Int = i & 1023
			If (i & 2047) < 1024
				_P[j] :+ _P[(j - 10) & 1023] ..
					+ _g1( _P[(j-3) & 1023], _P[(j-1023) & 1023] )
			Else
				_Q[j] :+ _Q[(j - 10) & 1023] ..
					+ _g2( _Q[(j-3) & 1023], _Q[(j-1023) & 1023] )
			End If
		Next
		
		_i = 0
	End Method
	
	Method Initialize(key:String , salt:String) 
		If key.Length < 8 Then key = key[..8]
		If salt.Length < 8 Then salt = salt[..8]
		Local k:Int[8] , iv:Int[8]
		Local l:Int = key.Length
		For Local i:Int = 0 Until l
			k[i & 7] = key[i] + _f1( key[(i+3) Mod l] ) + _f2( key[(i+5) Mod l] )
		Next
		l = salt.Length
		For Local i:Int = 0 Until l
			iv[i & 7] = salt[i] + _f1( salt[(i+3) Mod l] ) + _f2( salt[(i+5) Mod l] )
		Next
		Init k, iv
	End Method
	
	Method Output:Int() 
		Local j:Int = _i & 1023
		If (_i & 2047) < 1024
			_i :+ 1
			_P[j] :+ _P[(j - 10) & 1023] ..
				+ _g1( _P[(j-3) & 1023], _P[(j-1023) & 1023] ) 
			Return _h1( _P[(j-12) & 1023] ) ~ _P[j]
		Else
			_i :+ 1
			_Q[j] :+ _Q[(j - 10) & 1023] ..
				+ _g2( _Q[(j-3) & 1023], _Q[(j-1023) & 1023] ) 
			Return _h2( _Q[(j-12) & 1023] ) ~ _Q[j]
		End If
	End Method
	
	Method DecryptString:String(s:String)
		Local s2:String , i:Int, k:Int
		Local j:Int, slen:Int
		
		For k = 0 To 3
			j :+ s[k] Shl (k Shl 3)
		Next
		slen = j ~ Output()
		s = s[4..]
		
		While i < slen
			j = s[i] + (s[i + 1] Shl 8) + (s[i + 2] Shl 16) + (s[i + 3] Shl 24) 
			j :~ Output() 
			For k = 0 To 3
				If s2.Length = slen Then Exit
				s2 :+ Chr( (j Shr (k Shl 3) ) & 255 )
			Next
			i :+ 4
		Wend
		
		Return s2
	End Method
	
	Method EncryptString:String(s:String)
		Local s2:String , i:Int, k:Int
		Local j:Int = s.Length ~ Output() 
		
		For k = 0 To 3
			s2 :+ Chr( (j Shr (k Shl 3)) & 255 ) 
		Next
		
		While i < s.Length
			j = s[i] + (s[i + 1] Shl 8) + (s[i + 2] Shl 16) + (s[i + 3] Shl 24) 
			j :~ Output() 
			For k = 0 To 3
				s2 :+ Chr( (j Shr (k Shl 3)) & 255 ) 
			Next
			i :+ 4
		Wend
		
		Return s2
	End Method
	
	Function _f1:Int(x:Int) 
		Return Ror(x , 7) ~ Ror(x , 18) ~ Ror(x , 3) 
	End Function
	
	Function _f2:Int(x:Int) 
		Return Ror(x , 17) ~ Ror(x , 19) ~ Ror(x , 10) 
	End Function
	
	Method _g1:Int(x:Int , y:Int) 
		Return ( Ror(x , 10) ~ Ror(y , 23) ) + _Q[ (x ~ y) & 1023 ]
	End Method
	
	Method _g2:Int(x:Int , y:Int) 
		Return ( Ror(x , 10) ~ Ror(y , 23) ) + _P[ (x ~ y) & 1023 ]
	End Method
	
	Method _h1:Int(x:Int) 
		Local b:Byte Ptr = Byte Ptr( Varptr x ) 
		Return _Q[ b[0] ] + _Q[ 256 + b[1] ] + _Q[ 512 + b[2] ] + _Q[ 768 + b[3] ]
	End Method
	
	Method _h2:Int(x:Int) 
		Local b:Byte Ptr = Byte Ptr( Varptr(x) ) 
		Return _P[ b[0] ] + _P[ 256 + b[1] ] + _P[ 512 + b[2] ] + _P[ 768 + b[3] ]
	End Method
	
End Type

Comments

Otus2008
Test program. Update the CLOCK_SPEED constant to get the speeds on your computer correctly.




Blueapples2010
I get this error on Mac OS 10.6 when I try to build this:

Building baGrabbar
Compiling:ini.bmx
Compiling:md5.bmx
Compiling:hc256.bmx
Compiling:parseparams.bmx
Compiling:baGrabbar.bmx
Linking:baGrabbar.debug
Undefined symbols:
  "__rotr", referenced from:
      __bb_THcContext__f1 in hc256.bmx.debug.macos.x86.o
      __bb_THcContext__f1 in hc256.bmx.debug.macos.x86.o
      __bb_THcContext__f1 in hc256.bmx.debug.macos.x86.o
      __bb_THcContext__f2 in hc256.bmx.debug.macos.x86.o
      __bb_THcContext__f2 in hc256.bmx.debug.macos.x86.o
      __bb_THcContext__f2 in hc256.bmx.debug.macos.x86.o
      _522 in hc256.bmx.debug.macos.x86.o
      _522 in hc256.bmx.debug.macos.x86.o
      _530 in hc256.bmx.debug.macos.x86.o
      _530 in hc256.bmx.debug.macos.x86.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Build Error: Failed to link /Users/isaac/Documents/Projects/BlitzMax/baGrabbar/baGrabbar.debug.app/Contents/MacOS/baGrabbar.debug
Process complete


Any ideas?


grable2010
_rotr is probably not exposed on that platform.. try removing or adding some underscores. if that fails your sol ;)
Unless you can find an appropriate replacement that is.


Otus2010
Well, you can just implement it yourself. Somethings like:
Function Ror:Int(i:Int, n:Int)
	Return (i Shr n) | (i Shl (32-n))
End Function

(Untested.)


Blueapples2010
Thank Otus, that makes up with implementations I have seen in C but had trouble translating (and finding against after I saw them once). We'll see if it works!


Blueapples2010
I had to make some additions to get the demo code to run. EncryptString now pads out the input string to a multiple of 4 (due to the way it is implemented), and DecryptString now calls .Trim() on it's result.

Marked with begin iraway ... end iraway



Blueapples2010
Otherwise this is awesome and super easy to use. Thanks for the contribution, Otus!


Code Archives Forum