312 lines
7.2 KiB
C#
312 lines
7.2 KiB
C#
using System;
|
|
using System.Threading;
|
|
using System.Runtime.Remoting.Metadata;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using System.Text;
|
|
using sharp.extensions;
|
|
using System.Resources;
|
|
|
|
namespace sharp.hashing.SHA3
|
|
{
|
|
public class Keccak1600 : HashBase
|
|
{
|
|
public static Keccak1600Parameters SHA3_224 = new Keccak1600Parameters(224, 1152, 448, 0x06, Padding.NIST);
|
|
public static Keccak1600Parameters SHA3_256 = new Keccak1600Parameters(256, 1088, 512, 0x06, Padding.NIST);
|
|
public static Keccak1600Parameters SHA3_384 = new Keccak1600Parameters(384, 832, 768, 0x06, Padding.NIST);
|
|
public static Keccak1600Parameters SHA3_512 = new Keccak1600Parameters(512, 576, 1024, 0x06, Padding.NIST);
|
|
|
|
public static Keccak1600Parameters KECCAK_224 = new Keccak1600Parameters(224, 1152, 448, 0x01, Padding.NIST);
|
|
public static Keccak1600Parameters KECCAK_256 = new Keccak1600Parameters(256, 1088, 512, 0x01, Padding.NIST);
|
|
public static Keccak1600Parameters KECCAK_384 = new Keccak1600Parameters(384, 832, 768, 0x01, Padding.NIST);
|
|
public static Keccak1600Parameters KECCAK_512 = new Keccak1600Parameters(512, 576, 1024, 0x01, Padding.NIST);
|
|
|
|
Keccak1600Parameters parameters;
|
|
|
|
|
|
public Keccak1600(Keccak1600Parameters p)
|
|
{
|
|
this.parameters = p;
|
|
|
|
}
|
|
|
|
private int BlockByteSize { get { return this.parameters.r / 8; }}
|
|
private int BlockWordSize { get { return this.parameters.r / 64; }}
|
|
|
|
public override byte[] compute(byte[] data)
|
|
{
|
|
Monitor.Enter(this);
|
|
|
|
UInt64[] P = this.pad(data);
|
|
|
|
keccak1600_state S = new keccak1600_state();
|
|
|
|
int i, x, y;
|
|
int blockWordSize = BlockWordSize;
|
|
int PBlockCount = P.Length / BlockWordSize;
|
|
|
|
// Console.WriteLine("Init:");
|
|
// Console.WriteLine(S.ToString());
|
|
|
|
for (i = 0; i < PBlockCount;i++){
|
|
for (y = 0; y < 5; y++)
|
|
{
|
|
for (x = 0; (x < 5) && ((x + (5 * y)) < blockWordSize); x++)
|
|
{
|
|
S.xor(x,y, P[ (blockWordSize * i) + (x+(5*y)) ]);
|
|
}
|
|
}
|
|
Keccak_f(S);
|
|
}
|
|
|
|
// Console.WriteLine("Final State:");
|
|
// Console.WriteLine(S.ToString());
|
|
|
|
|
|
byte[] Z = new byte[ this.parameters.outsize / 8];
|
|
int outLanes = this.parameters.outsize / 64;
|
|
|
|
for (i = 0; i < PBlockCount;i++){
|
|
for (y = 0; y < 5; y++)
|
|
{
|
|
for (x = 0; (x < 5) && ((x + (5 * y)) < outLanes); x++)
|
|
{
|
|
Array.Copy(S[x, y].GetBytes(), 0, Z, 8 * (x + (5 * y)), 8);
|
|
}
|
|
}
|
|
}
|
|
|
|
Monitor.Exit(this);
|
|
return Z;
|
|
}
|
|
|
|
public UInt64[] pad(byte[] M){
|
|
switch (this.parameters.padding){
|
|
case Padding.KECCAK:
|
|
return padKeccak(M);
|
|
case Padding.NIST:
|
|
return pad1asterisk01(M);
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public UInt64[] padKeccak(byte[] M)
|
|
{
|
|
int lenPadded = (M.Length + 3) + BlockByteSize - ((M.Length + 3) % BlockByteSize);
|
|
byte[] P = new byte[lenPadded];
|
|
|
|
Array.Copy(M,P,M.Length);
|
|
|
|
P[M.Length ] = 0x01;
|
|
P[M.Length + 1] = this.parameters.d;
|
|
P[M.Length + 2] = (byte)(this.parameters.r / 8);
|
|
P[M.Length + 3] = 0x01;
|
|
|
|
for (int n = M.Length + 4 ; n < lenPadded ; n++){
|
|
P[n] = 0x00;
|
|
}
|
|
|
|
// Console.WriteLine("Padded:\n{0}",HexString.toString(P,8,2));
|
|
|
|
UInt64 []
|
|
P64 = new UInt64[P.Length / 8];
|
|
for (int n = 0; n<P64.Length; n++){
|
|
P64[n] = BitConverter.ToUInt64(P, n* 8);
|
|
}
|
|
|
|
return P64;
|
|
}
|
|
|
|
public UInt64[] pad1asterisk01(byte[] M){
|
|
int lenPadded = (M.Length + 2) + BlockByteSize - ((M.Length + 2) % BlockByteSize);
|
|
byte[] P = new byte[lenPadded];
|
|
|
|
Array.Copy(M,P,M.Length);
|
|
|
|
P[M.Length] = this.parameters.d;
|
|
|
|
for (int n = M.Length + 1; n<lenPadded;n++){
|
|
P[n] = 0x00;
|
|
}
|
|
P[lenPadded - 1] ^= 0x80;
|
|
|
|
// Console.WriteLine("Padded:\n{0}",HexString.toString(P,8,2));
|
|
|
|
UInt64 [] P64 = new UInt64[P.Length / 8];
|
|
for (int n = 0; n < P64.Length; n++){
|
|
P64[n] = BitConverter.ToUInt64(P, n * 8);
|
|
}
|
|
|
|
return P64;
|
|
}
|
|
|
|
private keccak1600_state Keccak_f(keccak1600_state A){
|
|
// Console.WriteLine("Before Round 0:");
|
|
// Console.WriteLine(A.ToString());
|
|
|
|
for (int n = 0; n < 24;n++){
|
|
// Console.WriteLine("Round {0}",n);
|
|
Round(A, this.RC[n]);
|
|
}
|
|
return A;
|
|
}
|
|
|
|
private keccak1600_state Round(keccak1600_state A,UInt64 RC){
|
|
keccak1600_state B = new keccak1600_state();
|
|
UInt64[] C = new UInt64[5],
|
|
D = new UInt64[5];
|
|
int x, y;
|
|
|
|
for (x = 0; x < 5;x++){
|
|
C[x] = A[x, 0] ^ A[x, 1] ^ A[x, 2] ^ A[x, 3] ^ A[x, 4];
|
|
}
|
|
|
|
for (x = 0; x < 5;x++){
|
|
D[x] = C[(((x - 1) % 5) + 5) % 5] ^ C[(x + 1) % 5].RotateLeft(1);
|
|
}
|
|
|
|
for (y = 0; y < 5;y++){
|
|
for (x = 0; x < 5;x++){
|
|
A[x, y] ^= D[x];
|
|
}
|
|
}
|
|
|
|
// Console.WriteLine("After Theta:");
|
|
// Console.WriteLine(A.toCheckString());
|
|
|
|
|
|
for (y = 0; y < 5;y++){
|
|
for (x = 0; x < 5;x++){
|
|
B[y, (2 * x) + (3 * y)] = A[x, y].RotateLeft(this.RO[y][x]);
|
|
}
|
|
}
|
|
|
|
// Console.WriteLine("After Rho:");
|
|
// Console.WriteLine(B.toCheckString());
|
|
|
|
for (y = 0; y < 5;y++){
|
|
for (x = 0; x < 5;x++){
|
|
A[x, y] = B[x, y] ^ ( (~B[x+1,y]) & B[x+2,y] );
|
|
}
|
|
}
|
|
|
|
A[0, 0] ^= RC;
|
|
|
|
return A;
|
|
}
|
|
|
|
|
|
|
|
private UInt64[] RC = {
|
|
0x0000000000000001,
|
|
0x0000000000008082,
|
|
0x800000000000808A,
|
|
0x8000000080008000,
|
|
0x000000000000808B,
|
|
0x0000000080000001,
|
|
0x8000000080008081,
|
|
0x8000000000008009,
|
|
0x000000000000008A,
|
|
0x0000000000000088,
|
|
0x0000000080008009,
|
|
0x000000008000000A,
|
|
0x000000008000808B,
|
|
0x800000000000008B,
|
|
0x8000000000008089,
|
|
0x8000000000008003,
|
|
0x8000000000008002,
|
|
0x8000000000000080,
|
|
0x000000000000800A,
|
|
0x800000008000000A,
|
|
0x8000000080008081,
|
|
0x8000000000008080,
|
|
0x0000000080000001,
|
|
0x8000000080008008
|
|
};
|
|
|
|
// RO[y][x]
|
|
private int[][] RO = {
|
|
new int[]{00,01,62,28,27},
|
|
new int[]{36,44,06,55,20},
|
|
new int[]{03,10,43,25,39},
|
|
new int[]{41,45,15,21,08},
|
|
new int[]{18,02,61,56,14}
|
|
};
|
|
|
|
class keccak1600_state {
|
|
public UInt64[] lanes;
|
|
|
|
public keccak1600_state(){
|
|
this.lanes = new UInt64[25];
|
|
for (int n = 0; n < this.lanes.Length;n++){
|
|
this.lanes[n] = 0;
|
|
}
|
|
}
|
|
|
|
private int index(int x,int y){
|
|
return (x % 5) + ((y % 5) * 5);
|
|
}
|
|
|
|
public void xor(int x,int y,UInt64 v){
|
|
this.lanes[index(x, y)] ^= v;
|
|
}
|
|
|
|
public UInt64 this[int x,int y]{
|
|
get { return this.lanes[index(x, y)]; }
|
|
set { this.lanes[index(x, y)] = value; }
|
|
}
|
|
|
|
public byte[] getBytes(){
|
|
byte[] t = new byte[ this.lanes.Length * 8 ];
|
|
for (int n = 0; n < this.lanes.Length; n++){
|
|
Array.Copy(this.lanes[n].GetBytes(),0,t,(n*8),8);
|
|
}
|
|
return t;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
int x, y;
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.AppendLine("[keccak1600_state]");
|
|
|
|
for (y = 0; y < 5;y++){
|
|
for (x = 0; x < 5;x++){
|
|
sb.AppendFormat("{0} ",HexString.toString(this[x,y].GetBytes()));
|
|
}
|
|
sb.AppendLine();
|
|
}
|
|
|
|
|
|
return sb.ToString();
|
|
|
|
}
|
|
|
|
public string toCheckString(){
|
|
return HexString.toString(getBytes(), 1, 16);
|
|
}
|
|
|
|
}
|
|
|
|
public enum Padding { NIST, KECCAK }
|
|
|
|
public struct Keccak1600Parameters {
|
|
public int outsize;
|
|
public int r, c;
|
|
public byte d;
|
|
public Padding padding;
|
|
|
|
public Keccak1600Parameters(int os,int r,int c,byte d,Padding padding){
|
|
this.outsize = os;
|
|
this.r = r;
|
|
this.c = c;
|
|
this.d = d;
|
|
this.padding = padding;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|