public SymmetricCipherResult ProcessPayload(IFfxModeBlockCipherParameters param) { var key = param.Key.ToBytes(); var engineParam = new EngineInitParameters(param.Direction, key, param.UseInverseCipherMode); _engine.Init(engineParam); CheckPayloadRequirements(param.Payload); if (param.Direction == BlockCipherDirections.Encrypt) { return(new SymmetricCipherResult(Encrypt(param))); } return(new SymmetricCipherResult(Decrypt(param))); }
protected abstract BitString Decrypt(IFfxModeBlockCipherParameters param);
protected override BitString Decrypt(IFfxModeBlockCipherParameters param) { var mode = _factory.GetStandardCipher(_engine, BlockCipherModesOfOperation.Ecb); var X = NumeralString.ToNumeralString(param.Payload); var n = X.Numbers.Length; // 1. Let u = ⌈n / 2⌉; v = n – u. var u = n.CeilingDivide(2); var v = n - u; // 2. Let A = X[1..u]; B = X[u + 1..n]. var A = new NumeralString(X.Numbers.Take(u).ToArray()); var B = new NumeralString(X.Numbers.Skip(u).Take(v).ToArray()); // Let TL = T[0..31] and TR = T[32..63] var TL = param.Iv.Substring(32, 32); var TR = param.Iv.Substring(0, 32); // 4. For i from 0 to 7: for (var i = NumberOfRounds - 1; i >= 0; i--) { // i. If i is even, let m = u and W = TR, else let m = v and W = TL. // v. If i is even, let m = u; else, let m = v. var m = i % 2 == 0 ? u : v; var W = i % 2 == 0 ? TR : TL; // ii. Let P = W ⊕ [i] 4 || [NUMradix(REV(B))]12 . var numA = new BitString(_ffInternals.Num(param.Radix, _ffInternals.Rev(A))); if (numA.BitLength < 12 * BitsInByte) { var bitsToPrepend = new BitString(12 * BitsInByte - numA.BitLength); numA = bitsToPrepend.ConcatenateBits(numA); } var P = W.XOR(new BitString(new byte[3]).ConcatenateBits(((byte)i).ToBitString())) .ConcatenateBits(numA); // iii. Let S = REVB(CIPHREVB(K) REVB(P)). var S = _ffInternals.RevB(mode.ProcessPayload( new ModeBlockCipherParameters( BlockCipherDirections.Encrypt, _ffInternals.RevB(param.Key), _ffInternals.RevB(P))).Result); // iv. Let y = NUM(S). var y = _ffInternals.Num(S); // v. Let c = (NUMradix (REV(B)) - y) mod radix m . var c = (_ffInternals.Num(param.Radix, _ffInternals.Rev(B)) - y).PosMod(BigInteger.Pow(param.Radix, m)); // vi. Let C = REV(STRm radix(c)). var C = _ffInternals.Rev(_ffInternals.Str(param.Radix, m, c)); // vii. Let B = A. B = A; // viii. Let A = C. A = C; } // 5. Return A || B. return(NumeralString.ToBitString(A) .ConcatenateBits(NumeralString.ToBitString(B))); }
protected override BitString Encrypt(IFfxModeBlockCipherParameters param) { var mode = _factory.GetStandardCipher(_engine, BlockCipherModesOfOperation.Ecb); var X = NumeralString.ToNumeralString(param.Payload); var n = X.Numbers.Length; var t = param.Iv.BitLength / BitsInByte; // 1. Let u = Floor(n/2); v = n – u. var u = n / 2; var v = n - u; // 2. Let A = X[1..u]; B = X[u + 1..n]. var A = new NumeralString(X.Numbers.Take(u).ToArray()); var B = new NumeralString(X.Numbers.Skip(u).Take(v).ToArray()); // 3. Let b = Ceiling(Ceiling(v×LOG(radix))/8). var b = (int)System.Math.Ceiling(System.Math.Ceiling(v * System.Math.Log(param.Radix, 2)) / 8); // 4. Let d = 4*Ceiling(b/4) + 4. var d = 4 * b.CeilingDivide(4) + 4; // the number times to iterate through the concatenation of cipher iterator blocks var jCount = d.CeilingDivide(16); // 5. Let P = [1] 1 || [2] 1 || [1] 1 || [radix] 3 || [10] 1 || [u mod 256] 1 || [n] 4 || [t] 4. var pBytes = new byte[_engine.BlockSizeBytes]; pBytes[0] = 0x01; pBytes[1] = 0x02; pBytes[2] = 0x01; // 3 bytes for radix, but radix is capped at 16 bits (2^16), so add a 0 byte pBytes[3] = 0x00; Array.Copy(BitString.To32BitString(param.Radix).GetLeastSignificantBits(16).ToBytes(), 0, pBytes, 4, 2); pBytes[6] = 0x0a; pBytes[7] = (byte)(u % 256); Array.Copy(BitString.To32BitString(n).ToBytes(), 0, pBytes, 8, 4); Array.Copy(BitString.To32BitString(t).ToBytes(), 0, pBytes, 12, 4); var P = new BitString(pBytes); // 6. For i from 0 to 9: for (var i = 0; i < NumberOfRounds; i++) { // i. Let Q = T || [0] (−t−b−1) mod 16 || [i] 1 || [NUMradix(B)]b. var numB = new BitString(_ffInternals.Num(param.Radix, B)); if (numB.BitLength < b * BitsInByte) { var bitsToPrepend = new BitString(b * BitsInByte - numB.BitLength); numB = bitsToPrepend.ConcatenateBits(numB); } var Q = new BitString(0) .ConcatenateBits(param.Iv) .ConcatenateBits(new BitString((-t - b - 1).PosMod(16) * BitsInByte)) .ConcatenateBits(((byte)i).ToBitString()) .ConcatenateBits(numB.GetMostSignificantBits(b * BitsInByte)); // ii. Let R = PRF(P || Q). var R = _ffInternals.Prf(P.ConcatenateBits(Q), param.Key); // iii. Let S be the first d bytes of the following string of Ceiling(d/16) blocks: // R || CIPHK(R Å [1]16) || CIPHK (R Å [2]16) … CIPHK(R Å [éd/16ù–1]). var S = R.GetDeepCopy(); for (var j = 1; j < jCount; j++) { var pad = BitString.To32BitString(j).PadToModulusMsb(_engine.BlockSizeBits); S = S.ConcatenateBits( mode.ProcessPayload( new ModeBlockCipherParameters( BlockCipherDirections.Encrypt, param.Key, R.XOR(pad))).Result ); } S = S.GetMostSignificantBits(d * BitsInByte); // iv. Let y = NUM(S). var y = _ffInternals.Num(S); // v. If i is even, let m = u; else, let m = v. var m = i % 2 == 0 ? u : v; // vi. Let c = (NUMradix (A)+y) mod radix m . var c = (_ffInternals.Num(param.Radix, A) + y).PosMod(BigInteger.Pow(param.Radix, m)); // vii. Let C = STR m radix (c). var C = _ffInternals.Str(param.Radix, m, c); // viii. Let A = B. A = B; // ix. Let B = C. B = C; } // 7. Return A || B. return(NumeralString.ToBitString(A) .ConcatenateBits(NumeralString.ToBitString(B))); }