public override SymmetricCipherResult Decrypt(BitString key, BitString cipherText, bool wrappedWithInverseCipher) { // 0. Check for valid bitlength ciphertext if (cipherText.BitLength < 128 || cipherText.BitLength % 64 != 0) { return(new SymmetricCipherResult("Invalid length for ciphertext")); } // 1. Let n = number of semi-blocks in C (number of half-blocks, where a block is 128-bits) var n = cipherText.BitLength / 64; // 2. Let ICV2 = 0xA65959A6 // 3. Set S based on semi-blocks var S = new BitString(32); if (n == 2) { var aesResult = Cipher.ProcessPayload(new ModeBlockCipherParameters(BlockCipherDirections.Decrypt, key, cipherText, wrappedWithInverseCipher)); if (!aesResult.Success) { return(new SymmetricCipherResult(aesResult.ErrorMessage)); } S = aesResult.Result; } else if (n > 2) { S = WrapInverse(key, cipherText, wrappedWithInverseCipher); } // 4. Check MSB(S, 32) to be equal to ICV2 if (!S.MSBSubstring(0, 32).Equals(Icv2)) { return(new SymmetricCipherResult("ICV2 not found as most significant bits of S")); } // 5. pLen = int(LSB(MSB(S, 64), 32)) var pLen = (int)S.MSBSubstring(0, 64).Substring(0, 32).ToPositiveBigInteger(); // 6. padLen = 8 * (n - 1) - pLen var padLen = 8 * (n - 1) - pLen; // 7. Make sure 0 < padLen < 7 if (padLen < 0 || padLen > 7) { return(new SymmetricCipherResult("Invalid padLen")); } // 8. If the padding isn't 0s, then fail if (!S.Substring(0, 8 * padLen).Equals(BitString.Zeroes(8 * padLen))) { return(new SymmetricCipherResult("Padding is not all 0s")); } // 9. Return p = MSB(LSB(S, 64*(n-1)), 8*pLen) var p = S.Substring(0, 64 * (n - 1)).MSBSubstring(0, 8 * pLen); return(new SymmetricCipherResult(p)); }
public BitString MixKeys(BitString currentKey, BitString lastOutput, BitString secondToLastOutput) { switch (currentKey.BitLength) { case 128: return(currentKey.XOR(lastOutput.GetMostSignificantBits(128))); case 192: var mostSignificant16KeyBitStringXor = currentKey.GetMostSignificantBits(64).XOR( // XOR 64 most significant key bits w/ secondToLastOutput.Substring(0, 64) // the 64 least significant bits of the previous cipher text ); var leastSignificant128KeyBitStringXor = currentKey.GetLeastSignificantBits(128).XOR(lastOutput.GetMostSignificantBits(128)); return(mostSignificant16KeyBitStringXor.ConcatenateBits(leastSignificant128KeyBitStringXor)); case 256: var mostSignificantFirst16BitStringXor = currentKey.GetMostSignificantBits(128).XOR(secondToLastOutput.GetMostSignificantBits(128)); var leastSignificant16BitStringXor = currentKey.GetLeastSignificantBits(128).XOR(lastOutput.GetMostSignificantBits(128)); return(mostSignificantFirst16BitStringXor.ConcatenateBits(leastSignificant16BitStringXor)); default: throw new ArgumentException(nameof(currentKey)); } }
public virtual BitString GHash(BitString h, BitString x) { //ThisLogger.Debug("GHash"); if (h.BitLength != 128) { return(null); } if (x.BitLength % 128 != 0 || x.BitLength == 0) { ThisLogger.Debug(x.BitLength); return(null); } // Step 1: Let X1,...,Xm-1,Xm denote the unique sequence of blocks such that // X = X1 || X2 || ... || Xm-1 || Xm int m = x.BitLength / 128; // Step 2: Let Y0 be the "zero block" 0^128 var y = BitString.Zeroes(128); // Step 3: For i = 1,...,m let Yi = (Yi-1 xor Xi) dot H for (int i = 0; i < m; ++i) { BitString xi = x.Substring((m - i - 1) * 128, 128); BitString YxorXi = BitString.XOR(y, xi); y = BlockProduct(YxorXi, h); } return(y); }
public byte[] HandleFinalFullPayloadBlockDecryption(BitString payload, IBlockCipherEngine engine, int numberOfBlocks, int originalPayloadBitLength) { // Decrypt the last full payload block (when there is more than one block) if (numberOfBlocks > 1) { var originalPayloadPaddedToBlockSize = payload.PadToModulus(engine.BlockSizeBits).ToBytes(); // Decrypt the last full payload block (in this case the second to last block) var secondToLastBlock = new byte[engine.BlockSizeBytes]; var secondToLastBlockStartIndex = (numberOfBlocks - 2) * engine.BlockSizeBytes; Array.Copy(originalPayloadPaddedToBlockSize, secondToLastBlockStartIndex, secondToLastBlock, 0, engine.BlockSizeBytes); var decryptedSecondToLastBlockBuffer = new byte[engine.BlockSizeBytes]; engine.ProcessSingleBlock(secondToLastBlock, decryptedSecondToLastBlockBuffer, 0); var decryptedBlock = new BitString(decryptedSecondToLastBlockBuffer); // Pad the payload to the nearest multiple of the block size using the last B−M bits of block cipher decryption of the second-to-last ciphertext block. var amountToPad = (engine.BlockSizeBits - payload.BitLength % engine.BlockSizeBits); if (amountToPad > 0) { payload = payload.ConcatenateBits(BitString.Substring(decryptedBlock, 0, amountToPad)); } var payloadBytes = payload.ToBytes(); TransformText(payloadBytes, engine, numberOfBlocks, originalPayloadBitLength); payload = new BitString(payloadBytes); return(payload.ToBytes()); } return(payload.ToBytes()); }
private BitString BCC(BitString key, BitString data) { // 1. chaining_value = 0^outlen // Comment: set the first chaining value to outlen zeros BitString chainingValue = new BitString(CounterAttributes.OutputLength); // 2. n = len(data)/outlen int n = data.BitLength / CounterAttributes.OutputLength; // 3. Starting with the leftmost bits of data, split the data into n // blocks of outlen bits each forming block_1 to block_n // 4. For i = 1 to n do: int iStart = data.BitLength - CounterAttributes.OutputLength; for (int i = 0; i < n; ++i, iStart -= CounterAttributes.OutputLength) { // 4.1 input_block = chaining_value xor block(i) BitString inputBlock = chainingValue.XOR(data.Substring(iStart, CounterAttributes.OutputLength)); // 4.2 chaining_value = Block_Encrypt(Key, input_block) chainingValue = BlockEncrypt(key, inputBlock); } // 5. output_block = chaining_value; BitString outputBlock = chainingValue; // 6. Return output_block return(outputBlock); }
public void Substring_ShouldReturnExpectedSubstring_WithEnumeration() { var bitString = new BitString("11110101"); var other = bitString.Substring(3, 4); Assert.AreEqual(4, other.Length); Assert.AreEqual("1010", other.ToBinString()); }
public void Substring_ShouldReturnExpectedSubstring_WithCopy() { var bitString = new BitString("111101011001011011100010"); var other = bitString.Substring(8, 8); Assert.AreEqual(8, other.Length); Assert.AreEqual("10010110", other.ToBinString()); }
protected virtual void Absorb(byte[] bytes, int length) { State.Clear(); var message = new BitString(bytes, length); var rate = State.Rate; message.Append(Suffix()); message.Append(GetPadding(rate, message.Length)); var n = message.Length / rate; var zeroes = new BitString(Capacity); BitString chunk; for (var i = 0; i < n; i++) { chunk = message.Substring(rate * i, rate); chunk.Append(zeroes); State.BitString.Xor(chunk); Function(); } }
private BitString GetNextPayload(int j, BitString currentIv, List <BitString> previousOutputs) { switch (Shift) { case 1: if (j < 128) { // Note, Bits are stored in the opposite direction on the BitString in comparison to where the MCT pseudo code expects them return(currentIv .Substring(currentIv.BitLength - 1 - j, Shift).GetDeepCopy()); } else { return(previousOutputs[j - _blockSizeBits / Shift].GetDeepCopy()); } case 8: if (j < 16) { return(new BitString(new byte[] { currentIv[j] })); } else { return(previousOutputs[j - 16].GetDeepCopy()); } case 128: if (j == 0) { return(currentIv.GetDeepCopy()); } else { return(previousOutputs[previousOutputs.Count - 2].GetDeepCopy()); } default: throw new ArgumentException(nameof(Shift)); } }
// Use this method when you need a Little Endian substring that is not a multiple of 8 bits in length // For the last byte, we would need to pull bits from the other end of the byte, rather than like reading an array in order // This only occurs once under SHAKE with variable output sizes private static BitString LittleEndianSubstring(BitString message, int startIdx, int length) { var lastFullByte = (length / 8) * 8; // Integer division rounds down for us var firstBytes = BitString.MSBSubstring(message, startIdx, lastFullByte); if (length == lastFullByte) { return(firstBytes); } var nextByte = BitString.MSBSubstring(message, startIdx + lastFullByte, 8); var bitsNeeded = length % 8; var lastBits = new BitString(0); if (bitsNeeded != 0) { lastBits = BitString.Substring(nextByte, 0, bitsNeeded); } return(BitString.ConcatenateBits(firstBytes, lastBits)); }
public BitString MixKeys(TDESKeys keys, List <BitString> previousOutputs) { if (keys == null) { throw new ArgumentNullException(nameof(keys)); } if (previousOutputs == null || (previousOutputs.Count * previousOutputs[0].BitLength) < 192) { throw new ArgumentException("Need 192 bits of previous outputs", nameof(previousOutputs)); } var outputBitString = new BitString(192); previousOutputs.Reverse(); foreach (var previousOutput in previousOutputs) { outputBitString = outputBitString.ConcatenateBits(previousOutput); } var newKey1 = keys.KeysAsBitStrings[0].XOR(outputBitString.Substring(0, 64)); var newKey2 = keys.KeysAsBitStrings[1].XOR(outputBitString.Substring(0, 64)); var newKey3 = keys.KeysAsBitStrings[2].XOR(outputBitString.Substring(0, 64)); if (keys.KeyOption == KeyOptionValues.ThreeKey) { newKey2 = keys.KeysAsBitStrings[1].XOR(outputBitString.Substring(64, 64)); newKey3 = keys.KeysAsBitStrings[2].XOR(outputBitString.Substring(128, 64)); } if (keys.KeyOption == KeyOptionValues.TwoKey) { newKey2 = keys.KeysAsBitStrings[1].XOR(outputBitString.Substring(64, 64)); } byte[] outputArray = new byte[24]; Array.Copy(newKey1.ToBytes(), outputArray, 8); Array.Copy(newKey2.ToBytes(), 0, outputArray, 8, 8); Array.Copy(newKey3.ToBytes(), 0, outputArray, 16, 8); return(new BitString(outputArray)); }
/* * INPUT: The initial Single-Tuple of a random length between 0 and 65536 bits. * * MCT(Tuple, MaxOutLen, MinOutLen, OutLenIncrement) * { * Range = (MaxOutLen – MinOutLen + 1); * OutputLen = MaxOutLen; * Customization = ""; * * T[0][0] = Tuple; * * for (j = 0; j < 100; j++) * { * for (i = 1; i < 1001; i++) * { * workingBits = Left(T[i-1][0] || ZeroBits(288), 288); * tupleSize = Left(workingBits, 3) % 4 + 1; // never more than 4 tuples to a round * for (k = 0; k < tupleSize; k++) * { * T[i][k] = Substring of workingBits from (k * 288 / tupleSize) to ((k+1) * 288 / tupleSize - 1); * } * Output[i] = TupleHash(T[i], OutputLen, Customization); * Rightmost_Output_bits = Right(Output[i], 16); * OutputLen = MinOutLen + (floor((Rightmost_Output_bits % Range) / OutLenIncrement) * OutLenIncrement); * Customization = BitsToString(T[i][0] || Rightmost_Output_bits); * } * * OutputJ[j] = Output[1000]; * } * * return OutputJ; * } */ #endregion MonteCarloAlgorithm Pseudocode public MCTResultTuple <AlgoArrayResponse> MCTHash(HashFunction function, IEnumerable <BitString> tuple, MathDomain domain, bool hexCustomization, bool isSample) { _hexCustomization = hexCustomization; if (isSample) { NUM_OF_RESPONSES = 3; } var responses = new List <AlgoArrayResponse>(); var i = 0; var j = 0; var min = domain.GetDomainMinMax().Minimum; var max = domain.GetDomainMinMax().Maximum; var increment = domain.GetDomainMinMax().Increment; var minBytes = min / 8; var maxBytes = max / 8; var outputLen = max; var customization = ""; var range = (max - min) + 1; var innerTuple = GetDeepCopy(tuple); try { for (i = 0; i < NUM_OF_RESPONSES; i++) { var innerDigest = new BitString(0); var iterationResponse = new AlgoArrayResponse() { }; iterationResponse.Tuple = innerTuple; iterationResponse.Customization = customization; for (j = 0; j < 1000; j++) { // Might not have 144 bits to pull from so we pad with 0 var innerBitString = BitString.ConcatenateBits(innerTuple.ElementAt(0), BitString.Zeroes(288)) .GetMostSignificantBits(288); var innerTupleSize = innerBitString.GetMostSignificantBits(3).Bits.ToInt() % 4 + 1; innerTuple = new List <BitString>(); for (int k = 0; k < innerTupleSize; k++) { innerTuple.Add(BitString.MSBSubstring(innerBitString, k * 288 / innerTupleSize, 288 / innerTupleSize)); } function.DigestLength = outputLen; var innerResult = _iTupleHash.HashMessage(function, innerTuple, customization); innerDigest = innerResult.Digest.GetDeepCopy(); // Will always have 16 bits to pull from var rightmostBitString = BitString.Substring(innerDigest, 0, 16); var rightmostBits = rightmostBitString.Bits; outputLen = min + (int)System.Math.Floor((double)(rightmostBits.ToInt() % range) / increment) * increment; customization = GetStringFromBytes(BitString.ConcatenateBits(innerTuple.ElementAt(0), rightmostBitString).ToBytes()); innerTuple = new List <BitString>(); innerTuple.Add(innerDigest.GetDeepCopy()); } iterationResponse.Digest = innerDigest.GetDeepCopy(); responses.Add(iterationResponse); } } catch (Exception ex) { ThisLogger.Debug($"i count {i}, j count {j}"); ThisLogger.Error(ex); return(new MCTResultTuple <AlgoArrayResponse>($"{ex.Message}; {outputLen}")); } return(new MCTResultTuple <AlgoArrayResponse>(responses)); }
/* * INPUT: The initial Msg is the length of the digest size * * MCT(Msg, MaxOutLen, MinOutLen, OutLenIncrement) * { * Range = (MaxOutLen – MinOutLen + 1); * OutputLen = MaxOutLen; * FunctionName = ""; * Customization = ""; * * Output[0] = Msg; * for (j = 0; j < 100; j++) * { * for (i = 1; i < 1001; i++) * { * InnerMsg = Left(Output[i-1] || ZeroBits(128), 128); * Output[i] = CSHAKE(InnerMsg, OutputLen, FunctionName, Customization); * Rightmost_Output_bits = Right(Output[i], 16); * OutputLen = MinOutLen + (floor((Rightmost_Output_bits % Range) / OutLenIncrement) * OutLenIncrement); * Customization = BitsToString(InnerMsg || Rightmost_Output_bits); * } * * OutputJ[j] = Output[1000]; * } * * return OutputJ; * } */ #endregion MonteCarloAlgorithm Pseudocode public MctResult <AlgoArrayResponseWithCustomization> MCTHash(HashFunction function, BitString message, MathDomain domain, bool customizationHex, bool isSample) { _customizationHex = customizationHex; if (isSample) { NUM_OF_RESPONSES = 3; } var responses = new List <AlgoArrayResponseWithCustomization>(); var i = 0; var j = 0; var min = domain.GetDomainMinMax().Minimum; var max = domain.GetDomainMinMax().Maximum; var increment = domain.GetDomainMinMax().Increment; //var outputLen = (int)System.Math.Floor((double)max / 8) * 8; var outputLen = max; var customization = ""; var functionName = ""; var range = (max - min) + 1; var innerMessage = message.GetDeepCopy(); try { for (i = 0; i < NUM_OF_RESPONSES; i++) { var innerDigest = new BitString(0); var iterationResponse = new AlgoArrayResponseWithCustomization() { }; iterationResponse.Message = innerMessage; iterationResponse.Customization = customization; for (j = 0; j < 1000; j++) { // Might not have 128 bits to pull from so we pad with 0 innerMessage = BitString.ConcatenateBits(innerMessage, BitString.Zeroes(128)); innerMessage = BitString.MSBSubstring(innerMessage, 0, 128); function.DigestLength = outputLen; var innerResult = _iCSHAKE.HashMessage(function, innerMessage, customization, functionName); innerDigest = innerResult.Digest.GetDeepCopy(); // Will always have 16 bits to pull from var rightmostBitString = BitString.Substring(innerDigest, 0, 16); var rightmostBits = rightmostBitString.Bits; //outputLen = min + (8 * rightmostBits.ToInt()) % range; outputLen = min + (int)System.Math.Floor((double)(rightmostBits.ToInt() % range) / increment) * increment; customization = GetStringFromBytes(BitString.ConcatenateBits(innerMessage, rightmostBitString).ToBytes()); innerMessage = innerDigest.GetDeepCopy(); } iterationResponse.Digest = innerDigest.GetDeepCopy(); responses.Add(iterationResponse); } } catch (Exception ex) { ThisLogger.Debug($"i count {i}, j count {j}"); ThisLogger.Error(ex); return(new MctResult <AlgoArrayResponseWithCustomization>($"{ex.Message}; {outputLen}")); } return(new MctResult <AlgoArrayResponseWithCustomization>(responses)); }
public virtual BitString GCTR(BitString icb, BitString x, BitString key) { // ICB must be 128 bits long // ThisLogger.Debug("GCTR"); if (icb.BitLength != 128) { ThisLogger.Warn($"icbLen:{icb.BitLength}"); return(null); } // Step 1: If X is the empty string, then return the empty string as Y if (x.BitLength == 0) { return(new BitString(0)); } var ecb = _modeFactory.GetStandardCipher( _engineFactory.GetSymmetricCipherPrimitive(BlockCipherEngines.Aes), BlockCipherModesOfOperation.Ecb ); // Step 2: Let n = ceil[ len(X)/128 ] int n = x.BitLength.CeilingDivide(128); // Step 3: Let X1,X2,...,Xn-1,Xn denote the unique sequence of bit // strings such that X = X1 || X2 || ... || Xn-1 || Xn* // X1, X2,...,Xn-1 are complete blocks // Xn* is either a complete block or a partial block // Step 4: Let CB1 = ICB // Step 5: For i = 2 to n, let CBi = inc32(CBi-1) // Step 6: For i = 1 to n-1, let Yi = Xi xor CIPH_K(CBi) BitString cbi = icb; BitString Y = new BitString(0); int sx = x.BitLength - 128; for (int i = 1; i <= (n - 1); ++i, sx -= 128) { if (i > 1) { cbi = inc_s(32, cbi); } BitString xi = x.Substring(sx, 128); var cbiParam = new ModeBlockCipherParameters( BlockCipherDirections.Encrypt, key, cbi ); var h = ecb.ProcessPayload(cbiParam); BitString yi = BitString.XOR(xi, h.Result); Y = Y.ConcatenateBits(yi); // This is part of Step 8 } // Step 7: Let Yn* = Xn* xor MSB_len(Xn*) (CIPH_K(CBn)) // i == n case: if (n > 1) { cbi = inc_s(32, cbi); } var xn = x.Substring(0, 128 + sx); var cbiParam1 = new ModeBlockCipherParameters( BlockCipherDirections.Encrypt, key, cbi ); var h1 = ecb.ProcessPayload(cbiParam1); var yn = xn.XOR(h1.Result.GetMostSignificantBits(xn.BitLength)); Y = Y.ConcatenateBits(yn); // This is part of Step 8 // Step 8: Let Y = Y1 || ... || Yn* // Step 9: Return Y return(Y); }
// Public for BlockCipherConditioningComponent public DrbgResult BlockCipherDf(BitString seedMaterial, int numberOfBitsToReturn) { int maxNumberOfBits = 512; // Check that input string is a multiple of 8 bits if (seedMaterial.BitLength % 8 != 0) { ThisLogger.Debug($"{nameof(seedMaterial)} not mod 8"); return(new DrbgResult(DrbgStatus.Error)); } // 1. If (no_of_bits_to_return > max_number_of_bits) then return // and ERROR_FLAG if (numberOfBitsToReturn > maxNumberOfBits) { ThisLogger.Debug($"{nameof(seedMaterial)} gt {nameof(maxNumberOfBits)}"); return(new DrbgResult(DrbgStatus.Error)); } // 2. L = len(input_string)/8 // Comment: L is the bitstring representation of the integer resulting // from len(input_string)/8. L shall be represented as a 32-bit integer. //BitString l = new BitString(new BigInteger(seedMaterial.BitLength / 8)).GetLeastSignificantBits(4 * 8); BitString l = new BitString(BitConverter.GetBytes(seedMaterial.BitLength / 8).Reverse().ToArray()); // 3. N = no_of_bits_to_return/8 // Comment: N is the bitstring representation of the integer resulting // from number_of_bits_to_return/8. N shall be represented as a 32-bit // integer //BitString n = new BitString(new BigInteger(numberOfBitsToReturn / 8)).GetLeastSignificantBits(4 * 8); BitString n = new BitString(BitConverter.GetBytes(numberOfBitsToReturn / 8).Reverse().ToArray()); // 3. S = L || N || input_string || 0x80 // Comment: Prepend the string length and the requested length of the // output to the input_string // NOTE: SP800-90 has step 3 twice BitString s = l .ConcatenateBits(n) .ConcatenateBits(seedMaterial) .ConcatenateBits(new BitString("80")); // 4. While (len(S) mod outlen) != 0, S = S || 0x00 // Comment: Pad S with zeros if necessary while ((s.BitLength % CounterAttributes.OutputLength) != 0) { s = s .ConcatenateBits(BitString.Zero()); } // 5. temp = the Null string // Comment: compute the starting value BitString temp = new BitString(0); // 6. i = 0 // Comment: i shall be represented as a 32-bit integer, i.e., len(i) = 32 int i = 0; byte[] bt = new byte[32]; for (int iterator = 0; iterator < 32; iterator++) { bt[iterator] = (byte)iterator; } // 7. Key = leftmost keylen bits of 0x000102030405 BitString k = new BitString(bt).GetMostSignificantBits(CounterAttributes.KeyLength); // 8. While len(temp)< keylen + outlen, do: while (temp.BitLength < (CounterAttributes.KeyLength + CounterAttributes.OutputLength)) { // 8.1 IV = i || 0^(outlen - len(i)) BitString iv = new BitString(BitConverter.GetBytes(i).Reverse().ToArray()) .ConcatenateBits(new BitString(CounterAttributes.OutputLength - 32)); // 8.2 temp = temp || BCC(Key, (IV || S)) temp = temp .ConcatenateBits(BCC(k, iv.ConcatenateBits(s))); i++; } // 9. Key = Leftmost keylen bits of temp k = temp.GetMostSignificantBits(CounterAttributes.KeyLength); // 10. X = Next outlen bits of temp int istart = temp.BitLength - CounterAttributes.KeyLength - CounterAttributes.OutputLength; BitString x = temp.Substring(istart, CounterAttributes.OutputLength); // 11. temp = the Null string temp = new BitString(0); // 12. While len(temp) < number_of_bits_to_return, do: while (temp.BitLength < numberOfBitsToReturn) { // 12.1 X = Block_Encrypt(Key, X) x = BlockEncrypt(k, x); // 12.2 temp = temp || X temp = temp.ConcatenateBits(x); } // 13. requested_bits = Leftmost no_of_bits_to_return of temp return(new DrbgResult(temp.GetMostSignificantBits(numberOfBitsToReturn))); }
/* * INPUT: The initial Msg of 128 bits long * * Initial Outputlen = (floor(maxoutlen/8) )*8 * //makes maxoutlen a multiple of 8 and remains within the range specified. * * { * Output0 = Msg; * for (j=0; j<100; j++) { * for (i=1; i<1001; i++) { * M[i] = 128 leftmost bits of Output[i-1]; * Output[i] = SHAKE(M[i],Outputlen); * If (i == 1000){ * Outputlen[j] = Outputlen; * } * Rightmost_Output_bits = rightmost 16 bits of Output[i]; * Range = (maxoutbytes – minoutbytes + 1); * Outputlen = minoutbytes + (Rightmost_Output_bits mod Range); * } * Output[j] = Output[1000]; * OUTPUT: Outputlen[j], Output[j] * } * } */ #endregion MonteCarloAlgorithm Pseudocode public MctResult <AlgoArrayResponse> MctHash(BitString message, MathDomain domain, bool isSample = false) { if (isSample) { NUM_OF_RESPONSES = 3; } var responses = new List <AlgoArrayResponse>(); var i = 0; var j = 0; var min = domain.GetDomainMinMax().Minimum; var max = domain.GetDomainMinMax().Maximum; var minBytes = min / 8; var maxBytes = max / 8; var outputLen = (int)System.Math.Floor((double)max / 8) * 8; var range = (max - min) + 8; //var range = (max - min) + min; var innerMessage = message.GetDeepCopy(); // Might not have 128 bits to pull from so we pad with 0 innerMessage = BitString.ConcatenateBits(innerMessage, BitString.Zeroes(128)); innerMessage = BitString.MSBSubstring(innerMessage, 0, 128); try { for (i = 0; i < NUM_OF_RESPONSES; i++) { var innerDigest = new BitString(0); var iterationResponse = new AlgoArrayResponse() { }; iterationResponse.Message = innerMessage; for (j = 0; j < 1000; j++) { var innerResult = _sha.HashMessage(innerMessage, outputLen); innerDigest = innerResult.Digest.GetDeepCopy(); // Will always have 16 bits to pull from var rightmostBits = BitString.Substring(innerDigest, 0, 16).Bits; outputLen = min + (8 * GetIntFromBits(rightmostBits)) % range; innerMessage = innerDigest.GetDeepCopy(); // Might not have 128 bits to pull from so we pad with 0 innerMessage = BitString.ConcatenateBits(innerMessage, BitString.Zeroes(128)); innerMessage = BitString.MSBSubstring(innerMessage, 0, 128); } iterationResponse.Digest = innerDigest.GetDeepCopy(); responses.Add(iterationResponse); } } catch (Exception ex) { ThisLogger.Debug($"i count {i}, j count {j}"); ThisLogger.Error(ex); return(new MctResult <AlgoArrayResponse>($"{ex.Message}; {outputLen}")); } return(new MctResult <AlgoArrayResponse>(responses)); }
private VerifyResult EmsaPssVerify(BitString M, BitString EM, int emBits) { var mHash = Sha.HashMessage(M).Digest; if (EM.BitLength < mHash.BitLength / 8 + SaltLength + 2) { return(new VerifyResult("RSA PSS Verify: inconsistent result")); } if (!EM.Substring(0, 8).Equals(Bc)) { return(new VerifyResult("RSA PSS Verify: 'BC' hex not found")); } // Bit values var maskedDB = EM.MSBSubstring(0, EM.BitLength - mHash.BitLength - 8); var H = EM.MSBSubstring(maskedDB.BitLength, mHash.BitLength); if (!maskedDB.MSBSubstring(0, EM.BitLength - emBits).Equals(BitString.Zeroes(EM.BitLength - emBits))) { return(new VerifyResult("RSA PSS Verify: Leading 0s not found in maskedDB")); } var dbMask = Mask.Mask(H, EM.BitLength - mHash.BitLength - 8); var DB = BitString.XOR(maskedDB, dbMask); for (var i = 0; i < EM.BitLength - emBits; i++) { DB.Set(DB.BitLength - i - 1, false); } var leftmostOctets = EM.BitLength - mHash.BitLength - SaltLength * 8 - 16; if (leftmostOctets != 0) { if (!DB.MSBSubstring(0, leftmostOctets).Equals(BitString.Zeroes(leftmostOctets))) { return(new VerifyResult("RSA PSS Verify: DB incorrect, improper number of leading 0s")); } } if (!DB.MSBSubstring(leftmostOctets, 8).Equals(ZeroOne)) { return(new VerifyResult("RSA PSS Verify: DB incorrect, '01' byte not found")); } var salt = DB.Substring(0, SaltLength * 8); var MPrime = BitString.Zeroes(64); MPrime = BitString.ConcatenateBits(MPrime, mHash); MPrime = BitString.ConcatenateBits(MPrime, salt); var HPrime = Sha.HashMessage(MPrime).Digest; if (HPrime.Equals(H)) { return(new VerifyResult()); } else { return(new VerifyResult("RSA PSS Verify: Hashes do not match")); } }