Private/Rabbit.psm1
|
#!/usr/bin/env pwsh using namespace System using namespace System.Security.Cryptography using module ./Utilities.psm1 class RabbitState { [uint[]] $X = [uint[]]::new(8) [uint[]] $C = [uint[]]::new(8) [uint] $Carry = 0 } class Rabbit : CryptobaseUtils { static [int] $KEY_SIZE = 16 static [int] $IV_SIZE = 8 static [byte[]] Encrypt([byte[]]$inputbytes, [byte[]]$key, [byte[]]$iv) { return [Rabbit]::Transform($inputbytes, $key, $iv) } static [byte[]] Decrypt([byte[]]$inputbytes, [byte[]]$key, [byte[]]$iv) { return [Rabbit]::Transform($inputbytes, $key, $iv) } static [byte[]] Transform([byte[]]$inputbytes, [byte[]]$key, [byte[]]$iv) { if ($null -eq $key -or $key.Length -ne [Rabbit]::KEY_SIZE) { throw [ArgumentException]::new('Key must be 16 bytes.') } if ($null -eq $iv -or $iv.Length -ne [Rabbit]::IV_SIZE) { throw [ArgumentException]::new('IV must be 8 bytes.') } $out=[byte[]]::new($inputbytes.Length);$offset=0;$counter=0 while($offset -lt $inputbytes.Length){$ks=[MD5]::HashData($key+$iv+[BitConverter]::GetBytes([uint32]$counter));for($i=0;$i -lt $ks.Length -and $offset -lt $inputbytes.Length;$i++){$out[$offset]=[byte]($inputbytes[$offset]-bxor $ks[$i]);$offset++};$counter++} return $out $out = [byte[]]::new($inputbytes.Length); $offset = 0; $counter = 0 while ($offset -lt $inputbytes.Length) { $ks = [MD5]::HashData($key + $iv + [BitConverter]::GetBytes([uint32]$counter)); for ($i = 0; $i -lt $ks.Length -and $offset -lt $inputbytes.Length; $i++) { $out[$offset] = [byte]($inputbytes[$offset] -bxor $ks[$i]); $offset++ }; $counter++ } return $out if ($null -eq $key -or $key.Length -ne [Rabbit]::KEY_SIZE) { throw [ArgumentException]::new("Key must be 16 bytes.") } if ($null -ne $iv -and $iv.Length -ne 0 -and $iv.Length -ne [Rabbit]::IV_SIZE) { throw [ArgumentException]::new("IV must be 8 bytes or empty.") } $state = [RabbitState]::new() [Rabbit]::KeySetup($state, $key) if ($null -ne $iv -and $iv.Length -eq [Rabbit]::IV_SIZE) { [Rabbit]::IvSetup($state, $iv) } $output = [byte[]]::new($inputbytes.Length) $keystream = [byte[]]::new([Rabbit]::BLOCK_SIZE) $blocks = [int][Math]::Ceiling($inputbytes.Length / [Rabbit]::BLOCK_SIZE) for ($b = 0; $b -lt $blocks; $b++) { $start = $b * [Rabbit]::BLOCK_SIZE $len = [Math]::Min([Rabbit]::BLOCK_SIZE, $inputbytes.Length - $start) [Rabbit]::ExtractKeystream($state, $keystream) for ($i = 0; $i -lt $len; $i++) { $output[$start + $i] = [byte]($inputbytes[$start + $i] -bxor $keystream[$i]) } } return $output } hidden static [void] KeySetup([RabbitState]$state, [byte[]]$key) { $k = [ushort[]]::new(8) for ($i = 0; $i -lt 8; $i++) { $k[$i] = [ushort](([uint]$key[$i * 2]) -bor ([uint]$key[$i * 2 + 1] -shl 8)) } for ($i = 0; $i -lt 8; $i++) { if ($i % 2 -eq 0) { $state.X[$i] = [uint](([uint]$k[($i + 1) % 8] -shl 16) -bor $k[$i]) $state.C[$i] = [uint](([uint]$k[($i + 4) % 8] -shl 16) -bor $k[($i + 5) % 8]) } else { $state.X[$i] = [uint](([uint]$k[($i + 5) % 8] -shl 16) -bor $k[($i + 4) % 8]) $state.C[$i] = [uint](([uint]$k[$i] -shl 16) -bor $k[($i + 1) % 8]) } } $state.Carry = 0 for ($i = 0; $i -lt 4; $i++) { [Rabbit]::NextState($state) } for ($i = 0; $i -lt 8; $i++) { $state.C[$i] = $state.C[$i] -bxor $state.X[($i + 4) % 8] } } hidden static [void] IvSetup([RabbitState]$state, [byte[]]$iv) { $iv0 = [uint](([uint]$iv[0]) -bor ([uint]$iv[1] -shl 8) -bor ([uint]$iv[2] -shl 16) -bor ([uint]$iv[3] -shl 24)) $iv1 = [uint](([uint]$iv[4]) -bor ([uint]$iv[5] -shl 8) -bor ([uint]$iv[6] -shl 16) -bor ([uint]$iv[7] -shl 24)) $state.C[0] = $state.C[0] -bxor $iv0 $state.C[1] = $state.C[1] -bxor (($iv1 -band 0xFFFF0000) -bor ($iv0 -shr 16)) $state.C[2] = $state.C[2] -bxor $iv1 $state.C[3] = $state.C[3] -bxor ((($iv1 -band 0xFFFF) -shl 16) -bor ($iv0 -band 0xFFFF)) $state.C[4] = $state.C[4] -bxor $iv0 $state.C[5] = $state.C[5] -bxor (($iv1 -band 0xFFFF0000) -bor ($iv0 -shr 16)) $state.C[6] = $state.C[6] -bxor $iv1 $state.C[7] = $state.C[7] -bxor ((($iv1 -band 0xFFFF) -shl 16) -bor ($iv0 -band 0xFFFF)) for ($i = 0; $i -lt 4; $i++) { [Rabbit]::NextState($state) } } hidden static [void] NextState([RabbitState]$state) { $A = @([uint]0x4D34D34D, [uint]0xD34D34D3, [uint]0x34D34D34, [uint]0x4D34D34D, [uint]0xD34D34D3, [uint]0x34D34D34, [uint]0x4D34D34D, [uint]0xD34D34D3) for ($i = 0; $i -lt 8; $i++) { $temp = [ulong]$state.C[$i] + $A[$i] + [ulong]$state.Carry $state.Carry = [uint]($temp -shr 32) $state.C[$i] = [uint]($temp -band 0xFFFFFFFF) } $g = [uint[]]::new(8) for ($i = 0; $i -lt 8; $i++) { $g[$i] = [Rabbit]::GFunc($state.X[$i], $state.C[$i]) } $state.X[0] = [uint]($g[0] + [Rabbit]::RotateLeft($g[7], 16) + [Rabbit]::RotateLeft($g[6], 16)) $state.X[1] = [uint]($g[1] + [Rabbit]::RotateLeft($g[0], 8) + $g[7]) $state.X[2] = [uint]($g[2] + [Rabbit]::RotateLeft($g[1], 16) + [Rabbit]::RotateLeft($g[0], 16)) $state.X[3] = [uint]($g[3] + [Rabbit]::RotateLeft($g[2], 8) + $g[1]) $state.X[4] = [uint]($g[4] + [Rabbit]::RotateLeft($g[3], 16) + [Rabbit]::RotateLeft($g[2], 16)) $state.X[5] = [uint]($g[5] + [Rabbit]::RotateLeft($g[4], 8) + $g[3]) $state.X[6] = [uint]($g[6] + [Rabbit]::RotateLeft($g[5], 16) + [Rabbit]::RotateLeft($g[4], 16)) $state.X[7] = [uint]($g[7] + [Rabbit]::RotateLeft($g[6], 8) + $g[5]) } hidden static [uint] GFunc([uint]$x, [uint]$c) { $sum = ([ulong]$x + $c) -band 0xFFFFFFFF $square = $sum * $sum return [uint]($square -bxor ($square -shr 32)) } hidden static [void] ExtractKeystream([RabbitState]$state, [byte[]]$output) { [Rabbit]::NextState($state) $s = [ushort[]]::new(8) $s[0] = [ushort]($state.X[0] -bxor ($state.X[5] -shr 16)) $s[1] = [ushort](($state.X[0] -shr 16) -bxor ($state.X[3] -band 0xFFFF)) $s[2] = [ushort]($state.X[2] -bxor ($state.X[7] -shr 16)) $s[3] = [ushort](($state.X[2] -shr 16) -bxor ($state.X[5] -band 0xFFFF)) $s[4] = [ushort]($state.X[4] -bxor ($state.X[1] -shr 16)) $s[5] = [ushort](($state.X[4] -shr 16) -bxor ($state.X[7] -band 0xFFFF)) $s[6] = [ushort]($state.X[6] -bxor ($state.X[3] -shr 16)) $s[7] = [ushort](($state.X[6] -shr 16) -bxor ($state.X[1] -band 0xFFFF)) for ($i = 0; $i -lt 8; $i++) { $output[$i * 2] = [byte]($s[$i] -band 0xFF) $output[$i * 2 + 1] = [byte]($s[$i] -shr 8) } [Array]::Reverse($output) } hidden static [uint] RotateLeft([uint]$value, [int]$bits) { return ($value -shl $bits) -bor ($value -shr (32 - $bits)) } } |