internal static Tweak EncodeTweak(UInt64 position, bool bitPad, TweakType type, bool first, bool final) { // // Takes tweak parameters and encodes them in a 128 bit value. The lower half of the 128 byte value (only the position) // is stuck in low64 and the high half in stuck in high64. // // N.B SimpleSkeinManaged specifies that position can be upto 2^96 but we support only 2^64. We could add support by rolling our own BigInteger // // The encoding is as follows (ASCII art not to scale) // // 128 120 112 96 0 // -------------------------------------------------------------------------------------------- // F1|F2| Type |B| TreeLevel | reserved | Position | // | | | | | | | // -------------------------------------------------------------------------------------------- // F1 = First // F2 = Final // B - BitPad // Tweak tweak = new Tweak(0,0); tweak.high64 = 0; // // The shift numbers are calculated using 64 - (128 - end-byte-from-diagram-above) // if (final) tweak.high64 |= (UInt64)1L << 63; // Set F1 in diagram above if (first) tweak.high64 |= (UInt64)1L << 62; // Set F2 in diagram above tweak.high64 |= (UInt64)type << 56; // Set type if (bitPad) tweak.high64 |= (UInt64)1L << 55; // Set bit pad tweak.low64 = position; return tweak; }
internal void Update(UInt64[] message, Tweak tweak) { // // Takes encoded tweak value and message, encrypts using current state as key and XORs // result with message. The block size is determined by looking at input message length // TODO: Reuse block cipher instance // if (_Hi.Length != message.Length){ throw new InvalidOperationException("Can't change block size in mid flight"); } Threefish threeFish = new Threefish(_Hi, tweak, _blockSize); threeFish.Encrypt(message, _Hi); for (int i = 0; i < _Hi.Length; i++){ _Hi[i] ^= message[i]; } }
public Threefish(UInt64[] key, Tweak tweak, ThreeFishBlockSize blockSize) { // // TODO: Move non-onetime initialization so that consumers can cache instances // if (key.Length != (int)blockSize/8) { throw new ArgumentException("Key size should match block size"); } this.BlockSize = blockSize; // // Set number of words rounds based on block size // _numWords = (int)BlockSize / sizeof(UInt64); switch (BlockSize) { case ThreeFishBlockSize.BLOCKSIZE_256_BITS: this._rounds = ThreeFishRounds.ROUNDS_72; this.RotationConstants = Rdj_Nw_4; this.PermutationPi = Threefish.PI_I_Nw_4; break; case ThreeFishBlockSize.BLOCKSIZE_512_BITS: this._rounds = ThreeFishRounds.ROUNDS_72; this.RotationConstants = Rdj_Nw_8; this.PermutationPi = Threefish.PI_I_Nw_8; break; case ThreeFishBlockSize.BLOCKSIZE_1024_BITS: this._rounds = ThreeFishRounds.ROUNDS_80; this.RotationConstants = Rdj_Nw_16; this.PermutationPi = Threefish.PI_I_Nw_16; break; } // // KeyWords is special in that it has an extra element kNw at the end // this.KeyWords = new UInt64[key.Length + 1]; Array.Copy(key, KeyWords, key.Length) ; // // Initialize Vd, Ed, fd and Ksd // _vd = new UInt64[_numWords]; _ed = new UInt64[_numWords]; _kdi = new UInt64[_numWords]; _fd = new UInt64[_numWords]; // // Initialize ts values(as per section 3.3.2) // _ts[0] = tweak.low64; _ts[1] = tweak.high64; _ts[2] = _ts[0] ^ _ts[1]; // // Initialize kNw (as per section 3.3.2). Already set to 2^64/3 // for (int i = 0; i < _numWords; i++) { _kNw ^= KeyWords[i]; } KeyWords[_numWords] = _kNw; }